368 Commits

Author SHA1 Message Date
E. Westbrook
3a66baed15 test/find-connect-limit: add missing "socket =" 2020-03-28 15:28:26 -06:00
E. Westbrook
790a58112f test/udp-zero-length-send-recv: add missing "socket ="; use shebang "#!/usr/bin/env lua" 2020-03-28 15:23:51 -06:00
E. Westbrook
d341493bbf test/udp-zero-length-send: add missing "socket ="; use shebang "#!/usr/bin/env lua" 2020-03-28 15:20:24 -06:00
E. Westbrook
0901c486ff test/getoptions: guard calls with pcall(); check result of getoption"linger" 2020-03-28 15:14:18 -06:00
E. Westbrook
68aeb39dc2 test/tcp-getoptions: bugfix: missing "socket =" in require"socket" 2020-03-27 16:55:04 -06:00
Diego Nehab
733af884f1 Merge pull request #280 from ewestbrook/rockspec-scm
SCM rockspec housekeeping
2019-04-22 00:27:05 -03:00
E. Westbrook
ab3b0ef5c9 rockspec/luasocket-scm-2.rockspec 2019-04-21 09:41:17 -06:00
E. Westbrook
9acb6dc81a move SCM rockspec to rockspec folder; rename consistent with luarocks repository 2019-04-21 09:31:08 -06:00
Diego Nehab
c89a931cc3 Merge pull request #271 from ewestbrook/pragmavisibility
Use visibility pragma around declarations instead of attributes on definitions
2019-03-11 00:08:41 -03:00
E. Westbrook
21514304be wrap visibility pragmas in #ifndef _WIN32 2019-03-10 00:04:20 -07:00
E. Westbrook
3a37ab8890 rockspecs: unix += compat 2019-03-10 00:04:20 -07:00
E. Westbrook
33883e78c8 rockspecs: serial += compat 2019-03-10 00:04:20 -07:00
E. Westbrook
c8d0fdda54 src/makefile: serial += compat 2019-03-10 00:04:20 -07:00
E. Westbrook
8b2dcdcf7d usocket: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
4e363330a3 unixstream: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
d27b1a7945 unixdgram: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
5d07d9b227 unix: include reorg 2019-03-10 00:04:20 -07:00
E. Westbrook
d71e6bc459 udp: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
42a1a732b7 timeout: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
86e1b3f45f tcp: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
1fa10673f7 socket.h: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
c8b9b40eda serial.c: pragma visibiliity 2019-03-10 00:04:20 -07:00
E. Westbrook
c2245f35c5 select: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
ce6a08d57d options: pragma visibility 2019-03-10 00:04:20 -07:00
E. Westbrook
83648f8df2 mime: include reorg 2019-03-10 00:04:20 -07:00
E. Westbrook
2015290cb4 luasocket: include centralization 2019-03-10 00:03:04 -07:00
E. Westbrook
ee30e4643d io: pragma visibility 2019-03-10 00:03:04 -07:00
E. Westbrook
611cdd19cc inet: pragma visibility 2019-03-10 00:03:04 -07:00
E. Westbrook
4bf3eb6db2 except: pragma visibility 2019-03-10 00:03:04 -07:00
E. Westbrook
133774cd3d compat: pragma visibility 2019-03-10 00:03:04 -07:00
E. Westbrook
e3ac49efbd buffer: pragma visibility 2019-03-10 00:03:04 -07:00
E. Westbrook
98800e9129 auxiliar: pragma visibility 2019-03-10 00:03:04 -07:00
Diego Nehab
2af4872a40 Fix formatting. 2019-03-10 00:47:17 -03:00
Diego Nehab
03b72d8f7e Use static initialization
This helps with multi-threaded apps.
2019-03-09 23:23:48 -03:00
Diego Nehab
c7215bef07 Remove .filters and hardcoded platform. 2019-03-02 17:47:18 -03:00
Diego Nehab
1e4255e2a9 Update Windows projects vor Visual Studio 2017 2019-03-01 20:46:37 -03:00
Diego Nehab
5cc91ab600 Merge pull request #272 from ewestbrook/pr268bugfix
bugfix: http.lua confict resolution omission
2019-03-01 00:38:44 -03:00
E. Westbrook
297f9d0277 bugfix: http.lua multischeme change that got dropped during PR conflict resolution 2019-02-28 18:40:30 -07:00
Diego Nehab
34d525984c Merge pull request #243 from mojca/eai-undefined
EAI_OVERFLOW, AI_NUMERICSERV: put behind #ifdef so this works on Mac OS X 10.4 and 10.5.
2019-02-26 14:09:00 -03:00
Mojca Miklavec
d9afe3fd9c Only use EAI_OVERFLOW, AI_NUMERICSERV if defined
Some systems like Mac OS X 10.5 (and lower) do not have EAI_OVERFLOW and
AI_NUMERICSERV defined.

These variables are used to avoid a potentially slow name resolution
for the hostname (which will always be an ip address)
and for service name (which will always be an actual port number).

The code might be slower, but it should still work.

Closes: #242
2019-02-26 09:30:15 +01:00
Diego Nehab
c0fba03e4f Merge pull request #270 from ewestbrook/functionvisibility
Tag functions explicitly for shared library visibility
2019-02-26 00:06:02 -03:00
E. Westbrook
e2e43d62fa rockspecs: remove visibility and dllexport defines in favor of in-source labeling 2019-02-25 16:07:36 -07:00
E. Westbrook
2d8f0d9901 src/makefile: remove visibility and dllexport defines in favor of in-source labeling 2019-02-25 16:04:49 -07:00
E. Westbrook
f8183bab87 usocket.c: use LUASOCKET_PRIVATE 2019-02-25 16:04:29 -07:00
E. Westbrook
d7ffc2f4e6 usocket.c use LUASOCKET_PRIVATE 2019-02-25 16:04:16 -07:00
E. Westbrook
fe437ee844 unixstream.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:44 -07:00
E. Westbrook
678d558c5f unixdgram.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:33 -07:00
E. Westbrook
30a0a6003b udp.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:21 -07:00
E. Westbrook
87c2dee13e timeout.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:04 -07:00
E. Westbrook
525d703e16 tcp.c: use LUASOCKET_PRIVATE 2019-02-25 16:00:51 -07:00
E. Westbrook
898f2df025 serial.c: include luasocket.h 2019-02-25 16:00:38 -07:00
E. Westbrook
fae993c118 select.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:29 -07:00
E. Westbrook
ef2a3fcedb options.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:19 -07:00
E. Westbrook
3f19a052e8 io.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:09 -07:00
E. Westbrook
731b23bc89 inet.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:54 -07:00
E. Westbrook
395729d431 except.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:45 -07:00
E. Westbrook
2bf6730fd5 pragma.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:30 -07:00
E. Westbrook
b95527e140 buffer.c: use LUASOCKET_PRIVATE 2019-02-25 15:57:25 -07:00
E. Westbrook
c0374dd46f auxiliar.c: use LUASOCKET_PRIVATE 2019-02-25 15:57:01 -07:00
E. Westbrook
16b0026e27 unix.c: use LUASOCKET_API 2019-02-25 15:56:28 -07:00
E. Westbrook
1f6035070f mime.c: use LUASOCKET_API 2019-02-25 15:56:17 -07:00
E. Westbrook
c23bf865ce unix.h: use LUASOCKET_API 2019-02-25 15:55:36 -07:00
E. Westbrook
efc4bb3e2d mime.h: use LUASOCKET_API 2019-02-25 15:55:04 -07:00
E. Westbrook
f06b17c4c9 luasocket.h: define LUASOCKET_API and LUASOCKET_PRIVATE for export visibility 2019-02-25 15:54:09 -07:00
Diego Nehab
9b3f7a4304 Merge pull request #268 from ewestbrook/prc-multischeme
Scheme-independent connection and redirection
2019-02-24 21:29:19 -03:00
E. Westbrook
2a467001f6 http.lua: Error informatively if insufficient LuaSec support 2019-02-24 16:24:42 -07:00
E. Westbrook
e587800164 socket.http.request(): simultaneous support for http and https URL schemes, with caller-adjustable scheme-to-transport mappings (default "socket.http" and "ssl.https") 2019-02-24 15:23:16 -07:00
Diego Nehab
38865fad3a Merge pull request #224 from pdgendt/patch-2
mime.lua: Obsolete require("io")
2019-02-24 18:06:00 -03:00
Diego Nehab
fa807f3ffd Merge pull request #246 from xyida/yoda
Fixed an issue that was mistaken for HTTP 0.9 when timeout
2019-02-24 18:01:33 -03:00
Diego Nehab
a9c75cb099 Merge pull request #244 from leyyer/options
add options:
2019-02-24 17:57:23 -03:00
Diego Nehab
699c36c019 Merge pull request #116 from linuxmaniac/master
Add "tcp-keepidle", "tcp-keepcnt" and "tcp-keepintvl" options
2019-02-24 17:55:27 -03:00
Diego Nehab
f6ba23d463 Merge pull request #259 from davidgumberg/patch-1
Make macosx.cmd generic
2019-02-24 17:54:11 -03:00
Diego Nehab
b8f088e868 Merge pull request #258 from ewestbrook/luasec117
http.lua: if default for scheme, omit port number in "Host:" header
2019-02-24 17:48:00 -03:00
Diego Nehab
c5cef32897 Merge pull request #262 from fregie/master
compile unixdgram.c, unixstream.c into unix.so
2019-02-24 17:45:58 -03:00
Diego Nehab
4b0f1d753d Merge pull request #265 from ewestbrook/dualincpaths
src/makefile: support both lua/$(LUAV) and lua$(LUAV) include paths
2019-02-24 17:44:54 -03:00
Diego Nehab
40f79c1961 Merge pull request #266 from siffiejoe/luajit-static-linking
Fix static linking problem with LuaJIT
2019-02-24 17:42:27 -03:00
Diego Nehab
e136dd3df3 Merge pull request #267 from ewestbrook/prc-maxredirects
Allow overriding of hard-coded redirect limit
2019-02-24 17:41:10 -03:00
E. Westbrook
09ff9b650c http.lua: allow override of hard-coded 5 max redirects 2019-02-23 12:23:17 -07:00
Philipp Janda
59c8aaac34 Fix static linking problem with LuaJIT
LuaJIT and LuaSocket both define new Lua APIs from Lua 5.2 (in
particular `luaL_setfuncs` and `luaL_testudata`). When linking both
statically, the one definition rule strikes and linking fails. This
commit fixes the issue by renaming the LuaSocket versions of those
functions behind the scenes using the C preprocessor.

Closes #214
2019-02-23 10:37:16 +01:00
E. Westbrook
5858c8e776 src/makefile: support both lua/$(LUAV) and lua$(LUAV) include paths 2019-02-22 16:16:03 -07:00
E. Westbrook
686f2ce822 http.lua: if default for scheme, omit port number in "Host:" header 2019-02-20 02:42:40 -07:00
Diego Nehab
144fa01c2f Merge pull request #264 from ewestbrook/freebsd-unix-bind-connect
src/unixdgram.c: fix connect() and bind() on FreeBSD
2019-02-19 16:08:47 -03:00
E. Westbrook
024646de54 Use SUN_LEN macro 2019-02-19 10:05:10 -07:00
Diego Nehab
57e04f55dc Merge pull request #263 from ewestbrook/freebsd-has-sun-len
src/makefile: enable UNIX_HAS_SUN_LEN for FreeBSD builds
2019-02-19 13:26:18 -03:00
E. Westbrook
531012df1a src/unixdgram.c: allow connect() and bind() on freebsd without dummy char, and simplify calculations 2019-02-19 04:51:23 -07:00
E. Westbrook
d1e35c9573 src/makefile: define UNIX_HAS_SUN_LEN for FreeBSD builds 2019-02-19 04:02:37 -07:00
fregie
4950294c26 compile unixdgram.c, unixstream.c into unix.so 2019-01-11 16:04:34 +08:00
David Gumberg
e2bb1d3b42 Make macosx.cmd generic 2018-09-29 16:29:58 -07:00
Diego Nehab
288219fd6b Update to Visual Studio 2017. 2018-08-22 17:37:32 -03:00
Diego Nehab
648d81281f Merge pull request #256 from ewestbrook/luasocket254
url.lua:absolute_path(): fix issue #254
2018-08-22 14:18:43 -03:00
E. Westbrook
043e997713 url.lua:remove_dot_components(): avoid ambiguous numeric representation as empty-path-segment marker 2018-08-21 12:43:30 -06:00
E. Westbrook
ca5398be09 url.lua:remove_dot_components(): use temporary NUL marker to reduce empty-segment special-case code 2018-08-21 12:17:12 -06:00
E. Westbrook
38d936ec0e url.lua:remove_dot_components(): empty path component double-dot corner case 2018-08-21 11:27:42 -06:00
E. Westbrook
5b862e6a3c url.lua:absolute_path(): ensure a separator between base_path and relative_path 2018-08-21 10:43:04 -06:00
E. Westbrook
7ccea58776 url.lua:remove_dot_components(): avoid overconsuming dot segments 2018-08-21 09:59:45 -06:00
E. Westbrook
c570a32c21 url.lua:remove_dot_components(): limit beginning-of-string double-dot corner case to prevent triple-dot activation and authority collision 2018-08-21 09:07:42 -06:00
E. Westbrook
c905b5d44f url.lua: separate remove_dot_components() from absolute_path(); also use in _M.absolute() even when not merging 2018-08-21 08:03:51 -06:00
E. Westbrook
17a95c126a url.lua:absolute_path(): fix issue #254, simplify, add more test cases 2018-08-19 11:32:42 -06:00
Diego Nehab
5813cd0505 Merge pull request #253 from flyingdutchman23/master
Fix gcc-8.1.0 warning.
2018-08-06 13:15:58 -03:00
Joris Clement
9b82c7871d Fix gcc-8.1.0 warning. 2018-08-06 15:30:13 +02:00
Diego Nehab
4df569e9f8 Merge pull request #250 from ewestbrook/testudata-compat
Update auxiliar.c to use luaL_testudata (#249), now with Lua 5.1 compatibility
2018-06-05 10:54:55 -03:00
Diego Nehab
cc42bcbf80 Merge pull request #251 from ewestbrook/ltn12tblsrc
Add ltn12.source.table()
2018-06-05 09:56:59 -03:00
E. Westbrook
8fee636309 Add ltn12.source.table() 2018-06-05 00:00:39 -06:00
E. Westbrook
5848de4851 src/compat.c: provide luaL_testudata() for use by auxiliar.c under Lua 5.1 2018-06-04 20:14:13 -06:00
George Zhao
e1e41be948 Update auxiliar.c 2018-06-03 20:08:02 +08:00
xyida
4a3504612c Fixed an issue that was mistaken for HTTP 0.9 when timeout 2018-04-26 16:39:33 +08:00
surenyi
97bfe1e043 add options:
get/set : recv-buffer-size
get/set : send-buffer-size

Signed-off-by: surenyi <surenyi82@163.com>
2018-03-25 14:58:10 +08:00
Diego Nehab
6529598909 Merge pull request #239 from ewestbrook/namebuf57
Fix buffer size error in src/options.c detected by GCC 7
2017-12-23 01:24:33 -02:00
E. Westbrook
72fb9dcb49 src/options.c: increase buffer from 45 to 57, to accommodate string sizes specified (detected by gcc7's -Wstringpop-overflow) 2017-12-22 16:57:20 -07:00
Diego Nehab
88b13a825b Merge pull request #238 from hleuwer/master
Fix URL parsing of userinfo containing # character.
2017-11-23 13:28:25 -02:00
Herbert Leuwer
2d6a0f7bda fixed url parsing; postpone fragment parsing after authority parsing; added test cases to test/urltest.lua
fixed reference patterns in check_protect() to upper case hex letters
2017-11-22 09:30:12 +01:00
Herbert Leuwer
3ee89515a0 fixed URL parsing in url.lua: parse fragment after parsing username and password. 2017-11-19 19:48:37 +01:00
Pieter De Gendt
053c032a70 mime.lua: Obsolete require("io")
The `io` package is included but never used.
2017-09-04 10:26:11 +02:00
Diego Nehab
5a17f79b03 Merge pull request #213 from elliptica/master
Fix typo
2017-05-15 15:29:49 -03:00
Elliptica
aef7bcf288 Fix typo 2017-04-17 18:47:48 +03:00
Diego Nehab
ff1a447b4d Merge pull request #210 from Lord-Helmchen/patch-1
make protect_segment in url.lua rfc compliant
2017-03-20 17:01:30 -03:00
Diego Nehab
47e644031f Preserve path when parsing urls. 2017-03-20 16:56:15 -03:00
Diego Nehab
1b4debffee Fix issue #196 2017-03-20 15:50:47 -03:00
Diego Nehab
865356f6eb Merge pull request #211 from fperrad/patch-1
fix for Lua 5.3 built without number / string conversion
2017-03-20 13:58:33 -03:00
LordHelmchen
44fb9e9112 correct typo 2017-03-16 17:53:02 +01:00
François Perrad
16bb548746 fix for Lua 5.3 built without number / string conversion
This kind of Lua could be built with this command:
```
    hererocks --lua 5.3 --cflags="-DLUA_NOCVTN2S -DLUA_NOCVTS2N"
```
2017-03-16 16:57:17 +01:00
LordHelmchen
860da0f4b4 make protect_segment in url.lua rfc compliant
percent-encode uppercase
see https://tools.ietf.org/html/rfc3986#section-6.2.2
2017-03-16 16:33:28 +01:00
Diego Nehab
29e5ad610a Merge pull request #207 from cbane/unix-sockets
Add backwards compatibility wrappers for socket.unix
2017-01-25 23:25:55 -02:00
Courtney Bane
ea0064625b Add backwards compatibility wrappers for socket.unix
Add backwards compatibility aliases "tcp" and "udp" for the recently renamed
"stream" and "dgram" functions, as well as a wrapper function and metatable
setup so that socket.unix() calls socket.unix.stream().
2017-01-25 18:04:35 -06:00
Diego Nehab
843fe9b65f Merge pull request #206 from ncopa/create-socket-on-first-sendto
Create socket on first sendto if family agnostic udp() was used
2017-01-25 13:15:51 -02:00
Natanael Copa
3041a808c3 Create socket on first sendto if family agnostic udp() was used
Create socket and set family on first sendto() if udp() was created
without address family.

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
2017-01-25 12:52:56 +01:00
Diego Nehab
a0baab5f3c Merge pull request #199 from enginix/master
Rename unix.tcp to unix.stream, unix.udp to unix.dgram
2017-01-04 18:41:31 -02:00
enginix
3a33c37b9c rename unix.tcp to unix.stream, unix.udp to unix.dgram 2016-12-25 23:33:10 +08:00
Diego Nehab
ac3201d620 Merge pull request #192 from mmaxs/master
Allow DESTDIR to be set from the environment
2016-11-11 02:28:07 -05:00
Mike Usenko
cd1e52eb7a allow DESTDIR to be set from the environment 2016-11-08 22:07:20 +03:00
Diego Nehab
316a9455b9 Merge pull request #181 from enginix/master
Add support for datagram unix domain sockets
2016-07-22 14:06:30 -03:00
enginix
2205c2053c add getsockname api for unix {udp,tcp} socket 2016-07-22 22:52:13 +08:00
enginix
c87f953d81 fix unixudp object checking issue 2016-07-04 16:38:37 +08:00
enginix
9f77f8b24f unix socket: compat lua 5.1 2016-06-30 15:40:51 +08:00
enginix
aa1b8cc9bc support datagram unix domain sockets 2016-06-24 21:33:19 +08:00
Diego Nehab
30a64c585a Merge pull request #178 from pdxmeshnet/master
Add rockspec to current development version.
2016-06-17 11:17:26 -03:00
Alex R
3abd1f2dd0 Added future release rockspec file 2016-06-15 15:27:07 -07:00
Diego Nehab
6aa4f2bc33 Merge pull request #167 from xspager/add_haiku_plat
Add the lib network to the linked libs if the platform is Haiku
2016-04-12 09:29:46 -03:00
Diego Nehab
e2acf378ea Merge pull request #171 from JonasKunze/feature/overwriteFlags
Enabled overwriting of MYCF/MYLDFlAGS
2016-04-12 09:29:14 -03:00
Diego Nehab
6a0506ca44 Merge pull request #170 from bytefire/master
URL-decode user password before adding to authorization header.
2016-04-12 09:28:27 -03:00
Jonas Kunze
624924a77b Enabled overwriting of MYCF/MYLDFlAGS 2016-04-12 13:06:47 +02:00
Okash Khawaja
b9f6fd215a URL-decode user password before adding to authorization header. 2016-04-12 00:04:21 +01:00
Okash Khawaja
9984741d94 Update comments for url.unescape() function. 2016-04-12 00:01:51 +01:00
Daniel Lemos
6fa6462636 Given LuaRocks support Haiku as a valid platform, link the network library 2016-03-11 16:05:21 -03:00
Diego Nehab
23ce5aeaa2 Hide ftp.PORT "constant" as a local 2016-03-07 01:33:08 -03:00
Diego Nehab
916b548240 Family agostic FTP and expose HTTP/FTP url parsing 2016-03-07 01:30:30 -03:00
Diego Nehab
5b4b915879 Remove global PORT. Fix https redirect. 2016-03-04 16:16:41 -03:00
Diego Nehab
944305dc21 Added gettimeout for completeness.
Also documented.
Rordered manuals so order is alphabetical.
2016-03-04 15:36:32 -03:00
Diego Nehab
cdce73b226 Added support for FTP command lists 2016-03-04 14:38:56 -03:00
Diego Nehab
fe7b37aced Merge pull request #166 from siffiejoe/exception-tweaks
Exception tweaks
2016-02-24 13:23:20 -03:00
Philipp Janda
0341516a29 Clarify documentation for try/protect. 2016-02-24 06:59:37 +01:00
Philipp Janda
4392bdcdd4 Always put metatable in first upvalue. 2016-02-24 00:57:42 +01:00
Philipp Janda
9fe38c654f Don't swallow errors in finalizers. 2016-02-24 00:48:43 +01:00
Diego Nehab
9ffd96724d Merge pull request #162 from siffiejoe/exception-meta
Support table errors in LuaSockets LTN13 C implementation.
2016-02-23 14:30:35 -03:00
Philipp Janda
7cab8a5006 Update comment in except.h 2016-02-21 12:28:13 +01:00
mpeterv
7c1df8a7cd Update HTML docs for try/protect 2016-02-21 12:10:25 +01:00
mpeterv
fb713cdedb Add more tests for socket.try/protect 2016-02-21 12:09:58 +01:00
Philipp Janda
d075e7322f Support table errors.
LuaSocket wraps error messages raised by newtry() in a table and unpacks
them later so that (string) errors raised by 3rd-party code can be
passed through as-is. This obviously didn't work when the 3rd-party code
raised a table as an error message. This change sets a private metatable
on all wrapped LuaSocket exceptions to distinguish them from 3rd-party
table errors.
2016-02-21 11:59:44 +01:00
Diego Nehab
bf13ec7fd4 Merge pull request #155 from JonasKunze/feature/solaris
Added Solaris platform
2016-02-11 11:02:58 -02:00
Diego Nehab
280e1d68a6 Merge pull request #157 from mpeterv/ltn12-lua53
Fix error in ltn12 under Lua 5.3
2016-02-11 11:01:57 -02:00
mpeterv
9192881346 Don't break global mbox table in mbox.split_mbox 2016-02-11 15:57:56 +03:00
mpeterv
52bb99af35 Fix sink method in tp module 2016-02-11 15:56:57 +03:00
mpeterv
700ece0721 Fix base_parsed global in url module 2016-02-11 15:54:59 +03:00
mpeterv
3c3a5d0011 Use base.select instead of just select 2016-02-11 15:53:53 +03:00
mpeterv
a7f21e8ec4 Fix error in ltn12 under Lua 5.3 2016-02-11 15:51:54 +03:00
Jonas Kunze
5d52ffedf4 Added solaris platform
To compile on solaris some libs had to be linked. So far I was only able
to test it on OmniOS r151006
2016-01-15 18:48:57 +01:00
Diego Nehab
83880dbed7 When zero-timeout, only try first address in connect. 2015-12-03 12:56:18 -02:00
Diego Nehab
be67f63f4e Changed buffer-per-socket to buffer-per-operation.
This is a difficult tradeoff to measure. I think large
datagrams won't be used very frequently. So it is better to
not lock a large buffer to each socket object and instead
allocate and deallocate for each operation receiving a
datagram larger than UDP_DATAGRAMSIZE.
2015-10-06 11:33:50 +08:00
Diego Nehab
fd729b32a8 Added support for arbitrary datagram sizes.
The maximum size is still constant per UDP object, but the
size can be speficied at creation time.
2015-10-05 11:47:51 +08:00
Diego Nehab
d1ec29be7f Merge branch 'KateAdams-tcp_reuseport' 2015-10-05 10:28:54 +08:00
Diego Nehab
f4b4720073 Merge branch 'tcp_reuseport' of https://github.com/KateAdams/luasocket into KateAdams-tcp_reuseport 2015-10-05 10:28:29 +08:00
Diego Nehab
4110e4125d Merge branch 'agnostic'
Seems safe to move to master.
2015-08-25 15:43:48 -03:00
Diego Nehab
77bba625d7 Fixes suggested by @Florob in #147. 2015-08-25 15:41:40 -03:00
Diego Nehab
46d7e75f3e Merge pull request #96 from chastabor/master
Generate headers before proxy changes host and port
2015-08-24 16:41:24 -03:00
Diego Nehab
b6a10ccb68 Merge pull request #84 from PixelToast/patch-2
the universe has only existed for 43.8 years
2015-08-24 16:31:42 -03:00
Diego Nehab
96965b179c New agnostic IPv4 IPv6 functions.
Also dealing with EPROTOTYPE Yosemite seems to be throwing
at us for no reason.
2015-08-22 19:52:01 -03:00
Diego Nehab
b211838648 Fix rockspec and serial.c module. 2015-08-21 22:31:29 -03:00
Diego Nehab
9322eacefd Merge pull request #141 from cjtallman/master
Added missing options for UDP getoption.
2015-08-21 15:51:52 -03:00
Diego Nehab
e75444ccd1 New compat.h module implements luaL_setfuncs.
Makes initialization code simpler everywhere.
2015-08-21 15:39:34 -03:00
cjtallman
67abaf89eb Added missing options for UDP getoption.
Documentation says "dontroute", "broadcast", "reuseaddr", and
"reuseport" are supported as arguments to getoption, however their
implementations were missing.
2015-06-11 09:02:20 -07:00
Diego Nehab
321c0c9b1f Merge branch 'Tieske-errormsg' 2015-03-03 19:20:44 -03:00
Diego Nehab
863a54cbaf Fix cut-paste typo on PIE_HOST_NOT_FOUND. 2015-03-03 19:20:13 -03:00
Diego Nehab
892ea1791a Merge branch 'errormsg' of https://github.com/Tieske/luasocket into Tieske-errormsg 2015-03-03 19:17:53 -03:00
Diego Nehab
8066a90e87 Merge pull request #115 from tst2005/patch-1
white background
2015-03-03 19:11:15 -03:00
Diego Nehab
bbcbbf845e Merge pull request #119 from gatzka/master
Make casts const correct.
2015-03-03 19:01:00 -03:00
Thijs Schreijer
d3ed08616b updated error messages, less error prone, platform independent 2015-03-03 21:17:06 +01:00
Diego Nehab
8396a0291b Better solution to luaL_checkint... 2015-03-01 22:49:04 -03:00
Diego Nehab
9d49cdcf05 Merge pull request #128 from Tieske/accidental_global
fixed accidental global in `ftp.lua`
2015-03-01 22:01:15 -03:00
Thijs Schreijer
59869b8bf6 fixed accidental global in ftp.lua 2015-03-01 20:34:53 +01:00
Diego Nehab
76ed24fe8a Fix inet_global_getaddrinfo leak of getnameinfo
Issue #127 closed.
2015-02-18 20:54:27 -02:00
Diego Nehab
ddf4292824 Out of the box support for Lua 5.3. 2015-02-18 20:51:37 -02:00
Stephan Gatzka
d8f77cca64 Remove unused function luaL_typerror(). 2014-12-21 07:45:36 +01:00
Stephan Gatzka
9178451ef9 Add missing prototype for opt_get_reuseport(). 2014-12-21 07:45:17 +01:00
Stephan Gatzka
c6f136c7f5 Make local function udp_strerror() static. 2014-12-21 07:44:11 +01:00
Stephan Gatzka
41692dfb4b Make casts const correct. 2014-12-21 06:57:10 +01:00
Victor Seva
2906d6a522 Add "tcp-keepidle", "tcp-keepcnt" and "tcp-keepintvl" options 2014-12-05 13:17:50 +01:00
TsT
8a24ddaf49 white background
white background (successfully tested on https://tst2005.github.io/luasocket/ in https://tst2005.github.io/luasocket/reference.css )
2014-11-28 12:09:44 +01:00
Diego Nehab
5edf093643 Merge pull request #114 from siffiejoe/yieldable_protect52
make socket.protect yieldable on Lua 5.2/5.3
2014-11-10 15:56:25 -02:00
Philipp Janda
0b03eec16b make socket.protect yieldable on Lua 5.2/5.3 2014-11-10 18:49:40 +01:00
Diego Nehab
583257c28c Merge pull request #113 from siffiejoe/yieldable_protect51
fixed yieldable socket.protect in etc/dispatch.lua
2014-11-10 15:39:34 -02:00
Philipp Janda
7006ae120d fixed yieldable socket.protect in etc/dispatch.lua 2014-11-10 18:17:10 +01:00
Diego Nehab
6dcecd8f45 Merge pull request #108 from daurnimator/master
src/usocket: Do not setblocking on destroy, shutdown, and listen.
2014-10-27 16:30:48 -02:00
daurnimator
4f122e60b1 src/usocket: Don't unset/set O_NONBLOCK around listen() or shutdown() calls.
It doesn't effect them.
Not true on windows
2014-10-27 14:07:38 -04:00
daurnimator
e602c2b271 src/usocket: Do not setblocking on destroy;
This results in unexpected behaviour if the socket has been `dup()`d, as O_NONBLOCK is shared.
Close is always 'blocking' anyway

See https://github.com/wahern/cqueues/issues/13 for an example use case
2014-10-27 13:35:36 -04:00
Diego Nehab
d80bb0d82b Fix Host: header according to RFC7230 2014-07-15 14:49:20 -03:00
Charles Tabor
2314235b3a Add proxy authentication headers if present. 2014-03-27 14:40:04 -05:00
Charles Tabor
36aa87e031 Generate headers before proxy changes host and port 2014-03-21 14:25:44 -05:00
PixelToast
534dfed859 the universe has only existed for 43.8 years 2013-11-07 19:13:36 -05:00
kobra
833333e131 Added ability to set the option reuseport of a tcp socket. 2013-09-12 00:46:32 +01:00
Diego Nehab
6d5e40c324 Add MYCFLAGS and MYLDFLAGS go allow for customization 2013-09-09 14:55:20 -03:00
Diego Nehab
d0b1f5b4c1 Add support for FreeBSD in makefile
Thanks to Leryan. See issue #78.
2013-09-09 14:29:14 -03:00
Diego Nehab
396e9e5ee6 Fixed timeout bug introduced by commit e81a6ff 2013-09-09 14:23:00 -03:00
Diego Nehab
244e5d34a0 Merge pull request #74 from catwell/pull-hostport
Include port in default Host header
2013-09-09 09:54:08 -07:00
Diego Nehab
c715993fb8 Merge pull request #65 from fab13n/480a818bf0ef6de32527ba14fc2bb27e754d0612
Support for several filters in ltn12.{sink,source}.chain
2013-09-09 09:48:46 -07:00
Pierre Chapuis
87d72dce4e include port in default Host header
See RFC 2616 section 14.23.
2013-08-14 14:41:57 +02:00
Diego Nehab
6bdb00e24c Merge pull request #69 from catwell/pull-globals
fixes related to constants in the HTTP module
2013-07-05 12:40:49 -07:00
Pierre Chapuis
1f9ccb2b58 http: look for PROXY in _M, not as a global 2013-07-05 18:00:29 +02:00
Pierre Chapuis
ddf88aca09 http: do not set global TIMEOUT 2013-07-05 17:59:52 +02:00
Fabien Fleutot
480a818bf0 support multiple filters in ltn12.{sink,source}.chain() 2013-06-18 11:01:46 +02:00
Diego Nehab
22cd5833fc Change link to github page. 2013-06-14 19:27:32 +08:00
Diego Nehab
19bd8baf9b Add files to distribution. 2013-06-14 19:21:27 +08:00
Diego Nehab
de58cb417a Change 2.1 to 3.0 2013-06-14 19:16:16 +08:00
Diego Nehab
bf7bc59a4d Change 2.1 to 3.0-rc1 2013-06-14 19:15:37 +08:00
Diego Nehab
ea812a755e Update NEW file and section 2013-06-14 19:12:44 +08:00
Diego Nehab
2cc51443c2 Download archive with https rather than git scheme 2013-06-13 17:35:52 +08:00
Diego Nehab
85aa5e3d9c Fix version in rockspec. 2013-06-13 17:13:14 +08:00
Diego Nehab
9ddfe92820 Fix path for rockspec in travis file. 2013-06-13 16:40:14 +08:00
Diego Nehab
c07ad19ca1 Merging moteus suggestions for rockspec and travis 2013-06-13 16:19:03 +08:00
Diego Nehab
7cad902bb7 Fix makefile and test_socket_error.lua 2013-06-12 21:45:15 +08:00
Diego Nehab
b34386ca5c Merge pull request #58 from mascarenhas/master
New rockspec that uses LuaRocks to build instead of the makefile
2013-06-12 06:38:37 -07:00
Fabio Mascarenhas
cce138c8e5 new rockspec using builtin build type 2013-06-11 17:23:50 -03:00
Diego Nehab
6e00ffd62f Changing from 2.1-rc1 to 3.0-rc1. 2013-06-11 19:10:03 +08:00
Diego Nehab
906abf29d1 Fix unix export marker. 2013-06-11 17:20:27 +08:00
Diego Nehab
bc709ac7b7 Export global table only if "module()" is defined. 2013-06-05 18:36:51 +08:00
Diego Nehab
b1d1e721d1 No need for inet_pton. 2013-06-04 16:26:49 +08:00
Diego Nehab
802567b7de Merge pull request #49 from moteus/moteus-ftp-get-2xx
Fix. recive 2xx while ftp.get cause timeout error
2013-05-30 03:02:33 -07:00
Diego Nehab
ebde49944b Unix domain tests still broken. 2013-05-30 17:59:28 +08:00
unknown
5eefc73b57 Remove warnings. Move windows specific code. 2013-05-30 16:50:28 +08:00
Diego Nehab
a233e27865 Leaving if in src/ but out of build for now. 2013-05-30 16:20:34 +08:00
moteus
00a06857c9 Fix. recive 2xx while ftp.get cause timeout error
In this example:
>Client send: MDTM test.txt
>Server response: 213 20120824120909
Because FTP server do not open new channel (2XX response)
and LuaSocket try open new channel we get timeout.

```lua
local ftp   = require "socket.ftp"
local ltn12 = require "ltn12"
local url   = require("socket.url")

local URL = "ftp://USER:TEST@127.0.0.1";
local CMD = 'MDTM test.txt';

-- get timeout
ftp.get{
  url = URL;
  command = CMD;
  sink = ltn12.sink.table{};
}

-- or we can use ftp.command
ftp.command{
  url = URL;
  command = URL,
  check = function(...)
    local status, data = ...
    return true
  end;
}
```
2013-05-30 11:01:07 +04:00
Diego Nehab
5341131cd0 Merge pull request #43 from moteus/moteus-getopt-error
Add. Allow get `error` option to socket.
2013-05-29 04:20:33 -07:00
moteus
1de617e355 Add. Allow get error option to socket. 2013-05-29 14:33:27 +04:00
unknown
b84a5f3d08 Change VC12 project to no LUA_COMPAT_MODUULE 2013-05-29 17:19:24 +08:00
Diego Nehab
79e6c4915d Export global only if LUA_COMPAT_MODULE defined. 2013-05-29 16:56:56 +08:00
moteus
5167ddaf49 Merge branch 'unstable' of git://github.com/diegonehab/luasocket into moteus-lua52 2013-05-28 14:06:18 +04:00
unknown
2d51d61688 Fix "final" bug in pton and TCP connreset handling 2013-05-28 17:27:06 +08:00
Diego Nehab
27fd725c6d Typo fixed. 2013-05-28 01:54:49 +08:00
unknown
734cc23e1f Fixed inet_pton and a new Winsock UDP bug.
inet_pton was copying the entire sockaddr_in struct,
rather than just the sin_addr field...

I am a bit unsure about the UDP fix, because it may affect
TCP as well. On UDP sockets, when a sendto fails, the next
receive/receivefrom fails with CONNRESET. I changed
sock_recv/sock_recvfrom in wsocket.c to skip the CONNRESET
from the recv/recvfrom, hoping that if the socket is TCP,
sock_waitfd will get the CONNRESET again. The tests pass,
but this should be tested more thoroughly.
2013-05-28 00:09:30 +08:00
unknown
66cd8cfcee Fix wrong usage of inet_pton. 2013-05-27 22:17:51 +08:00
unknown
056d7653f3 Link only against ws2_32.lib. 2013-05-27 21:58:41 +08:00
Diego Nehab
3d61b0fe36 Merge branch 'pkulchenko' into unstable 2013-05-27 21:17:00 +08:00
Diego Nehab
834a3cf520 Simplifying getaddrinfo treatment. 2013-05-27 21:05:48 +08:00
unknown
5e0b56b8d3 Merge branch 'moteus' of https://github.com/moteus/luasocket into moteus 2013-05-27 20:32:54 +08:00
unknown
26704061a4 Fix Visual Studio 2012 projects 2013-05-27 20:30:06 +08:00
moteus
45ff0e1775 Fix. use table.unpack in mimetest on Lua 5.2. 2013-05-27 13:11:07 +04:00
moteus
920bc97629 Build with Lua 5.2 without LUA_COMPAT_MODULE flag.
LUASOCKET_USE_GLOBAL flag enable create global variables when load socket/mime modules.
2013-05-27 12:45:09 +04:00
moteus
bd51d8c1a5 Fix. Optional IPv6 test 2013-05-27 11:26:35 +04:00
moteus
e54f78c61c Fix. setsockname fails with "*" as host.
Add. test_bind.lua
2013-05-27 11:25:31 +04:00
moteus
56dbda39ed Fix. getaddrinfo returns garbage as address on Windows.
Add. test_getaddrinfo.lua
2013-05-27 11:20:52 +04:00
Diego Nehab
fbe184f28a No need for build script: makefile target instead. 2013-05-26 21:27:18 +08:00
Diego Nehab
427220c7b1 Merge tryconnect6 into inet_tryconnect. 2013-05-26 21:26:26 +08:00
Diego Nehab
6d93fd7c8f Fix socket.connect
Previous implementation was not making sure the socket
had the same family as the addr returned by getaddrinfo.
So instead of "connection refused", we could get "invalid
argument", which was our fault.
2013-05-26 15:18:13 +08:00
Diego Nehab
22107bb9fc Check linux build. 2013-05-25 07:25:02 -03:00
Diego Nehab
5d3a78b4a6 Added my test command lines. 2013-05-25 18:10:46 +08:00
unknown
bb0b31301a Add MingW support. 2013-05-25 18:07:38 +08:00
Diego Nehab
afe0494318 Change Mac OS Lua directory 2013-05-25 15:26:12 +08:00
unknown
cbc77440c8 Merge branch 'lua52-mingw' of https://github.com/pkulchenko/luasocket into pkulchenko 2013-05-24 18:33:43 +08:00
Diego Nehab
ca48baf495 Merge pull request #37 from davidm/unstable
lpr.lua: fix invalid string escape sequence \?
2013-04-17 20:55:19 -07:00
David Manura
817d47df42 lpr.lua: fix invalid string escape sequence \?
Not valid in 5.2 and luajit.
2013-04-17 23:35:56 -04:00
Diego Nehab
238b217c4f Merge pull request #29 from keplerproject/94c958871919726f2954b3d3fa9a9f8ae21124e9
Rockspec for building and installing LuaSocket 2.1 with LuaRocks
2013-04-17 19:40:14 -07:00
Diego Nehab
c28fa1d309 Merge pull request #27 from catwell/pull-noarg
fix more uses of arg
2013-04-17 19:38:21 -07:00
Diego Nehab
00435529bb Merge pull request #32 from ideka/unstable
Use the length operator (#) instead of table.getn.
2013-04-17 19:13:28 -07:00
Paul Kulchenko
571308a94e Updated IPV6_V6ONLY to match header files on Windows. 2013-04-09 09:25:40 -07:00
Paul Kulchenko
5a58786a39 Added inet_pton/inet_ntop for MinGW on Windows; compiles with Lua52. 2013-04-07 12:39:56 -07:00
Gerardo Marset
56893e9dcd Use the length operator (#) instead of table.getn.
table.getn was deprecated in Lua 5.1 in favor of #, the length operator.
See: http://www.lua.org/manual/5.1/manual.html#7.2
2013-02-25 20:28:28 -02:00
Fabio Mascarenhas
94c9588719 rockspec for luasocket 2.1 unstable 2013-01-24 15:28:17 -02:00
Pierre Chapuis
33b4f0cfc7 remove uses of arg in the codebase 2013-01-23 19:13:32 +01:00
Pierre Chapuis
eea1bc04d7 fix use of arg in ltn documentation 2013-01-23 19:03:46 +01:00
Diego Nehab
d548a78e55 Cookie modifications. 2013-01-10 01:10:34 -02:00
Diego Nehab
72a5347f97 Remove warnings and fix makefile for Win32. 2012-12-11 17:43:49 -02:00
Diego Nehab
618ce43ee3 Fix socket_accept usage to depend on family. 2012-12-11 16:35:27 -02:00
Diego Nehab
66670c3541 Move Visual Studio projects to 2012. 2012-12-10 18:45:05 -02:00
Diego Nehab
9d97d39575 Fix ltn12 version. 2012-12-10 15:50:44 -02:00
Diego Nehab
a4b45edef2 Merge pull request #25 from ewmailing/unstable
Copied socket_gaistrerror implementation from usocket to wsocket to allo...
2012-12-10 09:31:13 -08:00
Diego Nehab
114080d835 Merge pull request #24 from catwell/tracking-diego
fix use of arg in ltn12
2012-12-10 09:25:21 -08:00
Eric Wing
5c467b3954 Copied socket_gaistrerror implementation from usocket to wsocket to allow Windows version to compile because it is missing the function. EAI_OVERFLOW and EAI_SYSTEM are commented out because they don't exist on Windows. 2012-11-20 12:58:52 -08:00
Pierre Chapuis
ffddaf4a2e fix use of arg in ltn12 2012-09-17 23:44:04 +02:00
Diego Nehab
a402222464 Merge pull request #22 from Florob/smtp
Send SMTP AUTH LOGIN response using tp:send(). Fixes #18
2012-08-23 15:34:43 -07:00
Diego Nehab
6368caeb5a Fix udp:setpeername("*")
There seems to be a curious difference between MacOS and
Linux and I am not sure if this is documented. When you
break a "connection" on Mac OS, you only eliminate the peer
association, but the local address remains bound. On Linux,
breaking a "connection" eliminates the binding to the local
address. Have you guys ever come accross this?

Another irritating difference is that connect() returns the
error EAFNOSUPPORT on Mac OS. I am going to ignore all
errors when the reason for calling connect() is simply to
break the "connection".
2012-08-23 19:31:15 -03:00
Florian Zeitz
32e7a107e2 Send SMTP AUTH LOGIN response using tp:send(). Fixes #18
tp:command() uppercases the command.
Without a command we would end up with a space in
front of the data. Therefore use send() directly here.
2012-08-07 00:01:48 +02:00
Diego Nehab
03ba06f70c Add new bug fix comment. 2012-08-01 03:34:06 -03:00
Diego Nehab
f329aae724 Fix HORRIBLE but in b64/qp code.
Bug was caught by user moteus.
Code was checking if arguments was nil after using
luaL_Buffer code, which messes with the stack.
Simple to fix, though.
2012-08-01 03:06:09 -03:00
Diego Nehab
54ffcd483f Fixed default Linux path to work with Ubuntu
Also fixed clean target to remove serial objects
2012-08-01 02:13:27 -03:00
Diego Nehab
6370b61414 Merge pull request #20 from Florob/sendto
IPv6 support for udp:sendto() and udp:receivefrom()
2012-07-31 22:04:06 -07:00
Diego Nehab
5616f3a0ae Merge pull request #15 from darkrain42/unstable
tcp: Initialize clnt->family in :accept()
2012-07-31 22:02:10 -07:00
Diego Nehab
c1bb432eff Merge pull request #14 from Zash/zash-improves-makefile
Use the install util instead of cp and mkdir
2012-07-31 22:00:03 -07:00
Florian Zeitz
7503bb0ca3 Add IPv6 support to udp:receivefrom() 2012-07-18 21:05:30 +02:00
Florian Zeitz
a6cf48596d Add IPv6 support to udp:sendto() 2012-07-17 19:02:20 +02:00
Paul Aurich
d777341eaf tcp: Initialize clnt->family in :accept()
Also unconditionally zero out the structs when allocated, for
good measure.
2012-05-21 19:44:08 -07:00
Kim Alvefur
36461db5bb src/makefile: Use install instead of cp and mkdir. 2012-05-15 18:44:38 +02:00
Kim Alvefur
c624761d32 src/makefile: Move mkdir to a variable 2012-05-15 18:27:46 +02:00
Diego Nehab
05535a19f8 Improve makefile to allow overriden variables
Before this change, it was difficult to set default
directories for different platforms that would still
work with different Lua versions.
2012-05-11 15:33:47 +08:00
Diego Nehab
399bdb7f41 Merge pull request #12 from sam-github/fix-connect6-and-do-connect-in-c
socket.connect now implemented in the C core
2012-05-10 23:16:38 -07:00
Sam Roberts
156669c28b socket.connect now implemented in the C core
This avoid socket.lua duplicating the iteration over the results
of getaddrinfo(). Some problems with the C implementation not
initializing sockets or the luasocket family have also been fixed,
and error reporting made more robust.
2012-05-10 14:14:22 -07:00
Diego Nehab
3d3e69c6e4 Merge pull request #8 from sam-github/fix-confusing-servname-reference
Reword error msg to distinguish between service and server
2012-05-08 11:52:23 -07:00
Diego Nehab
1bb586d655 Merge pull request #7 from sam-github/fix-makefiles
Rework makefiles to simplify setting and choosing build options.
2012-05-08 11:51:25 -07:00
Diego Nehab
ee7c53c3e5 Merge pull request #6 from Florob/getnameinfo
Add a getnameinfo() wrapper
2012-05-08 11:48:54 -07:00
Sam Roberts
ac59bcbeac Reword error msg to distinguish between service and server
servname is easily confused with "server name", making it seem
as if the server name couldn't be resolved.
2012-05-08 10:55:33 -07:00
Sam Roberts
c291383ce2 Rework makefiles to simplify setting and choosing build options.
Includes documentation for common build settings, reasonable
defaults, and ability to set common build options in the
environment.
2012-05-08 10:51:56 -07:00
Florian Zeitz
0c3e067af1 Add a getnameinfo() wrapper
This wrapper takes a domain name or an IP as first argument
and a service name or port as second argument.
Either argument may be nil.

It returns a list of names (always only one in the IP case) and a
service name.
2012-05-05 02:13:56 +02:00
Diego Nehab
04be61f88d Test server exits gracefully at command of test client 2012-05-01 16:21:06 +08:00
Diego Nehab
af55d25675 Merge branch 'tests52' of https://github.com/Florob/luasocket into Florob-tests52 2012-05-01 16:12:16 +08:00
Florian Zeitz
6de0aa54fd Update method list in tests 2012-04-29 21:03:28 +02:00
Florian Zeitz
cf4d29f86d Select loadstring or load for Lua 5.1/5.2 respectively 2012-04-29 20:46:35 +02:00
Florian Zeitz
46736a3355 Test method registration for IPv6 sockets 2012-04-29 20:44:15 +02:00
Sam Roberts
e86eac96fa :shutdown() errors on all invalid argument strings
It used to error only on invalid argument strings that started with 's',
'r', or 'b'.
2012-04-26 16:50:27 -07:00
Diego Nehab
30d1aae140 Added Sam's suggestion to TODO 2012-04-27 02:03:09 +08:00
Diego Nehab
c2e29537f5 Fixed getpeername/getsockname situation
- Added IPv6 support to getsockname
- Simplified getpeername implementation
- Added family to return of getsockname and getpeername
and added modification to the manual to describe
2012-04-24 00:47:30 +08:00
Diego Nehab
1acf8188cd socket.bind also tries all addresses returned by getaddrinfo. 2012-04-23 01:40:31 +08:00
Diego Nehab
966642f76a socket.connect() loops over addresses returned by getaddrinfo 2012-04-23 01:29:41 +08:00
Diego Nehab
f960b3872a Making progress toward a release
Documented headers.lua
Update copyright date everywhere
Remove RCSID from files
Move version back to 2.1 rather than 2.1.1
Fixed url package to support ipv6 hosts
Changed "domain" to "family" in tcp and udp structures
Implemented getfamily methods
2012-04-23 00:18:45 +08:00
Diego Nehab
f37e026026 First stab at documenation
Update Lua and Luasocket version in samples and in documentation
Documented ipv5_v6only default option being set
Documented tcp6 and udp6
Documented dns.getaddrinfo
Documented zero-sized datagram change?
Documented getoption
2012-04-17 01:15:26 +08:00
Diego Nehab
b3c4f46179 merged lua_typerrror.{c,h} into auxiliar.{c,h} 2012-04-16 20:41:48 +08:00
Sam Roberts
4b671f4551 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
2012-04-11 14:18:20 -07:00
Sam Roberts
195b2a74bb On failure, exit with a message instead of blocking indefinitely. 2012-04-11 13:54:01 -07:00
Sam Roberts
38b99b80a2 Add Wurldtech note to README. 2012-04-11 13:54:01 -07:00
Sam Roberts
d1a50282a7 Correct luasocket version in v2.0.2 readme.
v2.0.2 was released with a README saying it was v2.0.1.
2012-04-11 13:54:01 -07:00
Sam Roberts
8bb542baaf Support getoption method for tcp objects. 2012-04-11 13:54:01 -07:00
Sam Roberts
0716cb868e Bounds check the argument to FD_SET
Failing to check the FD_SET argument against FD_SETSIZE causes
undefined behaviour (segfaults, for example).
2012-04-11 13:54:01 -07:00
Sam Roberts
27a3964ff7 socket_strerror() sometimes maps errno, instead of its argument
Looks like a historical bug. Its err argument is an error number, but
if it isn't using a custom error message for it, it just calls
strerror() with the errno global, effectively ignoring its argument
and returning a semi-random string.
2012-04-11 13:54:01 -07:00
Sam Roberts
db47a91d40 Fix links to home.html, they should be to index.html.
home.html doesn't exist, index.html does.
2012-04-11 13:45:59 -07:00
root
e716e7347b mime: Remove io dependency
This dependency was spuriously added, maybe for debug reasons,
as confirmed to me by Diego Nehab by mail.
Some systems based in Lua (e.g. Ginga) prohibit the use of
io module for security reasons, so this dependency makes
mime unusable; even worse this makes other modules, based
on mime, unusable too (e.g. html).
2012-04-11 13:45:59 -07:00
Sam Roberts
12bde801f6 Document dirty, getfd, and setfd for select and tcp. 2012-04-11 13:45:59 -07:00
Sam Roberts
3a0fd4744d Reference index was missing documented APIs, and only partially alphabetized. 2012-04-11 13:45:59 -07:00
Sam Roberts
b1f7c349b5 Add support for serial devices as socket streams on unix. 2012-04-11 13:45:59 -07:00
Sam Roberts
3b19f2a7ed testsrvr asserts when test finishes successfully.
When the test client finishes, the test server asserts with a "closed" message.
After looking carefully at this, I think the tests are running
successfully and passing. Since it appears to be a test failure, I
modified the server to allow the client to close the control connection.
2012-04-11 13:45:59 -07:00
Sam Roberts
dace50628c Utility to find how many TCP connections can be made. 2012-04-11 13:45:59 -07:00
Sam Roberts
f63d616bc0 Use poll by default for socket.connect(), instead of select().
Connect timeouts are implemented by waiting on the new socket
descriptor. When select() is used for this, it imposes an arbitrary
limit on the number of connections that can be made, usually 1024-3.
Using poll() removes this limit on the number of simultaneous TCP
connections can be made using luasocket. The previous default
implementation using select() is available by defining SOCKET_SELECT.
Note that using socket.select() always uses select(), so it isn't
possible to wait on an arbitrary number of connections at once.
2012-04-11 13:45:59 -07:00
Sam Roberts
21698c7665 Receive of zero for UDP is now possible.
Previously, receive of zero was considered to be "closed", but that
is only true for stream-based protocols, like TCP.
2012-04-11 13:45:59 -07:00
Sam Roberts
c37f71d062 Test showing failure to receive a zero-length packet. 2012-04-11 13:45:59 -07:00
Sam Roberts
51acb54760 Stop returning an error after successful send of zero length UDP packets
A zero-length send is invalid with TCP, but well defined with UDP.
udp:send"" was returning (nil,"refused"), indicating that it failed when
the packet was actually sent. The test script reproduces the bug, and
includes a tcpdump of the zero length packet being sent.
2012-04-11 13:45:59 -07:00
Sam Roberts
a8b19e5367 OS X CFLAGS definition caused silent failure to build debug version of luasocket.
The luasocket tests require LUASOCKET_DEBUG to be defined at build time,
but for OS X if COMPAT was undefined, the command line looked like
  ... -I -DLUASOCKET_DEBUG ...
so that the the macro definition was silently being treated as the
argument to -I. Result is the macro was never set, and tests would
never run. Fixed by moving -I to the (optional) definition of the
location of compat headers.
2012-04-11 13:45:59 -07:00
Sam Roberts
1f704cfb89 Add all-unix and install-unix targets which include all modules supported on unix.
Besides standard socket and mime modules, this includes unix domain
socket support.
2012-04-11 13:45:59 -07:00
Sam Roberts
826589afcd Add location of Ubuntu's lua5.1 headers to config. 2012-04-11 13:45:59 -07:00
Sam Roberts
dcb92d6268 Support the conventional DESTDIR and prefix variables
Many packaging systems rely on them, they are described here:
- http://www.gnu.org/prep/standards/standards.html#index-prefix
- http://www.gnu.org/prep/standards/standards.html#DESTDIR
2012-04-11 13:45:58 -07:00
Sam Roberts
e3e0dee639 ignore build output 2012-04-11 13:45:58 -07:00
Florian Zeitz
f399ab25fc inet: Honor the strict aliasing rule 2012-04-11 13:33:35 -07:00
Liam Devine
e81a6ff623 Conditional creation of p_timeout instance 'tm' 2012-04-11 13:33:34 -07:00
Liam Devine
9a58252528 change localhost to loopback ip to prevent error on my mac box???? 2012-04-11 13:33:34 -07:00
Liam Devine
51187ecc90 Updated readme version and os tested 2012-04-11 13:33:34 -07:00
Liam Devine
c8eed36788 This is a replacement for luaL_typerror , removed from Lua 5.2, which corrects the spelling.
NOTE:
There is one failing test in.the /test/testsrvr.lua and /test/testclnt.lua combination which was present in the repo I cloned from.
2012-04-11 13:33:34 -07:00
Liam Devine
e15ed19db6 Compiles with Lua 5.1.4 and Lua 5.2.0-beta, although the makefile needs sorting out to take maybe a version number and also the local paths need removing. 2012-04-11 13:33:34 -07:00
Paul Aurich
a984607f28 inet: return more useful errors 2012-04-11 13:33:34 -07:00
Paul Aurich
7893d9ece2 inet: refactor getpeername to allocate the struct on the stack 2012-04-11 13:33:34 -07:00
Florian Zeitz
8393c76180 Fix getpeername to work with IPv6 addresses 2012-04-11 13:33:34 -07:00
Florian Zeitz
594f826aa1 Add support for connecting to IPv6 hosts 2012-04-11 13:33:34 -07:00
Florian Zeitz
5874d47f55 dns.getaddrinfo: Return proper error messages 2012-04-11 13:33:34 -07:00
Florian Zeitz
f871a29f27 Add support for the IPV6_V6ONLY socket option defaulting to on. 2012-04-11 13:33:34 -07:00
Florian Zeitz
4df1618aab Adapt socket.bind() to create a IPv4 or IPv6 depending on the address given 2012-04-11 13:33:34 -07:00
Florian Zeitz
5065a2585c dns: Rename toip6() to getaddrinfo() since the old name is misleading 2012-04-11 13:33:34 -07:00
Florian Zeitz
923eef1929 Rework binding IPv6 sockets by harmonizing it with the IPv4 variant 2012-04-11 13:33:34 -07:00
Matthew Wild
5c33ef9997 url.escape/url.unescape: Fix to return *only* the encoded/decoded string (thanks moodydeath) 2012-04-11 13:33:34 -07:00
Paul Aurich
908ee2cce1 Fix two crashes and add -Wshadow so that this can't happen again.
The two crashes are the s/const char *// changes in tcp.c.  The rest
is cleanup so it will build.
2012-04-11 13:33:34 -07:00
Matthew Wild
dd83e0a849 #ifdef EAI_BADHINTS and EAI_PROTOCOL which don't seem available on my system (Linux/glibc 2.11) 2012-04-11 13:33:34 -07:00
Diego Nehab
2778766d67 Preliminary IPv6 support for v2.1 2012-04-11 13:25:11 -07:00
Diego Nehab
3a8ba90dfb Saving before big changes to support IPv6. 2011-05-25 20:57:22 +00:00
Diego Nehab
bce60be30f Decent makefiles! 2009-05-27 09:31:38 +00:00
Diego Nehab
d1a72435d5 New release. 2007-10-13 23:55:20 +00:00
145 changed files with 8325 additions and 3658 deletions

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
*.o
*.so
*.so.*
*.obj
*.lib
*.dll*
*.user
*.sdf
Debug
Release
*.manifest
*.swp
*.suo
x64

54
.travis.yml Normal file
View File

@@ -0,0 +1,54 @@
language: erlang
env:
global:
- LUAROCKS_BASE=luarocks-2.0.13
matrix:
- LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
- LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
- LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
branches:
only:
- master
before_install:
- if [ $LUA = "luajit" ]; then
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
fi
- sudo apt-get install $LUA
- sudo apt-get install $LUA_DEV
- lua$LUA_SFX -v
# Install a recent luarocks release
- wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
- tar zxvpf $LUAROCKS_BASE.tar.gz
- cd $LUAROCKS_BASE
- ./configure
--lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
- sudo make
- sudo make install
- cd $TRAVIS_BUILD_DIR
install:
- export DEBUG=DEBUG
- sudo -E luarocks make luasocket-scm-0.rockspec
script:
- cd test
- lua$LUA_SFX hello.lua
- lua$LUA_SFX testsrvr.lua > /dev/null &
- lua$LUA_SFX testclnt.lua
- lua$LUA_SFX stufftest.lua
- lua$LUA_SFX excepttest.lua
- lua$LUA_SFX test_bind.lua
- lua$LUA_SFX test_getaddrinfo.lua
- lua$LUA_SFX ltn12test.lua
- lua$LUA_SFX mimetest.lua
- lua$LUA_SFX urltest.lua
- lua$LUA_SFX test_socket_error.lua
notifications:
email:
on_success: change
on_failure: always

13
FIX
View File

@@ -1,15 +1,14 @@
http was preserving old host header during redirects http was preserving old host header during redirects
fix smtp.send hang on source error fix smtp.send hang on source error
add create field to FTP and SMTP and fix HTTP ugliness add create field to FTP and SMTP and fix HTTP ugliness
clean timeout argument to open functions in SMTP, HTTP and FTP clean timeout argument to open functions in SMTP, HTTP and FTP
eliminate globals from namespaces created by module(). eliminate globals from namespaces created by module().
url.absolute was not working when base_url was already parsed url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class. tcp{client}:shutdown() was checking for group instead of class.

View File

@@ -1,5 +1,5 @@
LuaSocket 2.0.2 license LuaSocket 3.0 license
Copyright © 2004-2007 Diego Nehab Copyright © 2004-2013 Diego Nehab
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

49
Lua.props Executable file
View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Condition="'$(Platform)'=='x64'" Label="LuaPlat">
<LUAPLAT>$(Platform)/$(Configuration)</LUAPLAT>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'" Label="LuaPlat">
<LUAPLAT>$(Configuration)</LUAPLAT>
</PropertyGroup>
<PropertyGroup Label="UserMacros">
<LUAV>5.3</LUAV>
<LUAPREFIX>z:\data\build\vc14\</LUAPREFIX>
<LUALIB>$(LUAPREFIX)\lib\lua\$(LUAV)\$(LUAPLAT)</LUALIB>
<LUACDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)</LUACDIR>
<LUALDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)\lua</LUALDIR>
<LUAINC>$(LUAPREFIX)\include\lua\$(LUAV);$(LUAPREFIX)\include\lua$(LUAV)</LUAINC>
<LUALIBNAME>lua$(LUAV.Replace('.', '')).lib</LUALIBNAME>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUAPLAT">
<Value>$(LUAPLAT)</Value>
</BuildMacro>
<BuildMacro Include="LUAPREFIX">
<Value>$(LUAPREFIX)</Value>
</BuildMacro>
<BuildMacro Include="LUAV">
<Value>$(LUAV)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC">
<Value>$(LUAINC)</Value>
</BuildMacro>
<BuildMacro Include="LUACDIR">
<Value>$(LUACDIR)</Value>
</BuildMacro>
<BuildMacro Include="LUALDIR">
<Value>$(LUALDIR)</Value>
</BuildMacro>
<BuildMacro Include="LUALIBNAME">
<Value>$(LUALIBNAME)</Value>
</BuildMacro>
</ItemGroup>
</Project>

49
NEW
View File

@@ -1,11 +1,44 @@
What's New What's New
This is just a bug-fix/update release. Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
* Fixed: crash when reading '*a' on closed socket (Paul Ducklin); * Added: Compatible with Lua 5.2
* Fixed: return values are consistent when reading from closed sockets; - Note that unless you define LUA_COMPAT_MODULE, package
* Fixed: case sensitivity in headers of multipart messages in tables will not be exported as globals!
smtp.message() (Graham Henstridge); * Added: IPv6 support;
* Fixed a couple instances of error() being called instead of base.error(). These would cause an error when an error was reported. :) (Ketmar Dark); - Socket.connect and socket.bind support IPv6 addresses;
* Fixed: test script now uses pairs() iterator instead of the old - Getpeername and getsockname support IPv6 addresses, and
Lua syntax (Robert Dodier). return the socket family as a third value;
- URL module updated to support IPv6 host names;
- New socket.tcp6 and socket.udp6 functions;
- New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
* Added: getoption method;
* Fixed: url.unescape was returning additional values;
* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could
mistaking their own stack slots for functions arguments;
* Fixed: Receiving zero-length datagram is now possible;
* Improved: Hidden all internal library symbols;
* Improved: Better error messages;
* Improved: Better documentation of socket options.
* Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
* Fixed: failure on bind() was destroying the socket (Sam Roberts);
* Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
* Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
* Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
* Fixed: manual links to home.html changed to index.html (Robert Hahn);
* Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
* Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
* Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
* Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
* Improved: Clarified tcp:receive() in the manual (MPB);
* Improved: Decent makefiles (LHF).
* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).

11
README
View File

@@ -1,6 +1,11 @@
This is the LuaSocket 2.0.1. It has been tested on WinXP, Mac OS X, This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
and Linux. Please use the Lua mailing list to report any bugs and Linux.
(or "features") you encounter.
Please use the project page at GitHub
https://github.com/diegonehab/luasocket
to file bug reports or propose changes.
Have fun, Have fun,
Diego Nehab. Diego Nehab.

64
TODO
View File

@@ -1,7 +1,67 @@
- bizarre default values for getnameinfo should throw error instead!
> It's just too bad it can't talk to gmail -
> reason 1: they absolutely want TLS
> reason 2: unlike all the other SMTP implementations, they
> don't
> tolerate missing < > around adresses
- document the new bind and connect behavior.
- shouldn't we instead make the code compatible to Lua 5.2
without any compat stuff, and use a compatibility layer to
make it work on 5.1?
- add what's new to manual
- should there be an equivalent to tohostname for IPv6?
- should we add service name resolution as well to getaddrinfo?
- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
- add http POST sample to manual
people keep asking stupid questions
- documentation of dirty/getfd/setfd is problematic because of portability
same for unix and serial.
what to do about this? add a stronger disclaimer?
- fix makefile with decent defaults?
Done:
- added IPv6 support to getsockname
- simplified getpeername implementation
- added family to return of getsockname and getpeername
and added modification to the manual to describe
- connect and bind try all adresses returned by getaddrinfo
- document headers.lua?
- update copyright date everywhere?
- remove RCSID from files?
- move version to 2.1 rather than 2.1.1?
- fixed url package to support ipv6 hosts
- changed domain to family
- implement getfamily methods.
- remove references to Lua 5.0 from documentation, add 5.2?
- update lua and luasocket version in samples in documentation
- document ipv5_v6only default option being set?
- document tcp6 and udp6
- document dns.getaddrinfo
- documented zero-sized datagram change?
no.
- document unix socket and serial socket? add raw support?
no.
- document getoption
- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
replace \r\n with \0xD\0xA in everything
New mime support New mime support
ftp send should return server replies? ftp send should return server replies?
make sure there are no object files in the distribution tarball make sure there are no object files in the distribution tarball
http handling of 100-continue, see DB patch http handling of 100-continue, see DB patch

60
config
View File

@@ -1,60 +0,0 @@
#------
# LuaSocket makefile configuration
#
#------
# Output file names
#
EXT=so
SOCKET_V=2.0.2
MIME_V=1.0.2
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
MIME_SO=mime.$(EXT).$(MIME_V)
UNIX_SO=unix.$(EXT)
#------
# Lua includes and libraries
#
#LUAINC=-I/usr/local/include/lua50
#LUAINC=-I/usr/local/include/lua5.1
#LUAINC=-Ilua-5.1.1/src
#------
# Compat-5.1 directory
#
#COMPAT=compat-5.1r5
#------
# Top of your Lua installation
# Relative paths will be inside the src tree
#
#INSTALL_TOP_SHARE=/usr/local/share/lua/5.0
#INSTALL_TOP_LIB=/usr/local/lib/lua/5.0
INSTALL_TOP_SHARE=/usr/local/share/lua/5.1
INSTALL_TOP_LIB=/usr/local/lib/lua/5.1
INSTALL_DATA=cp
INSTALL_EXEC=cp
#------
# Compiler and linker settings
# for Mac OS X
#
#CC=gcc
#DEF= -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN
#CFLAGS= $(LUAINC) -I$(COMPAT) $(DEF) -pedantic -Wall -O2 -fno-common
#LDFLAGS=-bundle -undefined dynamic_lookup
#LD=export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
#------
# Compiler and linker settings
# for Linux
CC=gcc
DEF=-DLUASOCKET_DEBUG
CFLAGS= $(LUAINC) $(DEF) -pedantic -Wall -O2 -fpic
LDFLAGS=-O -shared -fpic
LD=gcc
#------
# End of makefile configuration
#

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -39,12 +39,16 @@
<h2 id=dns>DNS</h2> <h2 id=dns>DNS</h2>
<p> <p>
Name resolution functions return <em>all</em> information obtained from the IPv4 name resolution functions
resolver in a table of the form: <a href=#toip><tt>dns.toip</tt></a>
and
<a href=#tohostname><tt>dns.tohostname</tt></a>
return <em>all</em> information obtained from
the resolver in a table of the form:
</p> </p>
<blockquote><tt> <blockquote><tt>
resolved = {<br> resolved4 = {<br>
&nbsp;&nbsp;name = <i>canonic-name</i>,<br> &nbsp;&nbsp;name = <i>canonic-name</i>,<br>
&nbsp;&nbsp;alias = <i>alias-list</i>,<br> &nbsp;&nbsp;alias = <i>alias-list</i>,<br>
&nbsp;&nbsp;ip = <i>ip-address-list</i><br> &nbsp;&nbsp;ip = <i>ip-address-list</i><br>
@@ -55,6 +59,53 @@ resolved = {<br>
Note that the <tt>alias</tt> list can be empty. Note that the <tt>alias</tt> list can be empty.
</p> </p>
<p>
The more general name resolution function
<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which
supports both IPv6 and IPv4,
returns <em>all</em> information obtained from
the resolver in a table of the form:
</p>
<blockquote><tt>
resolved6 = {<br>
&nbsp;&nbsp;[1] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-1</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-1</i><br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;[n] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-n</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-n</i><br>
&nbsp;&nbsp;}<br>
}
</tt> </blockquote>
<p>
Here, <tt>family</tt> contains the string <tt>"inet"</tt> for IPv4
addresses, and <tt>"inet6"</tt> for IPv6 addresses.
</p>
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getaddrinfo>
socket.dns.<b>getaddrinfo(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to address.
</p>
<p class=parameters>
<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
</p>
<p class=return>
The function returns a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b>
followed by an error message.
</p>
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gethostname> <p class=name id=gethostname>
@@ -72,7 +123,7 @@ socket.dns.<b>tohostname(</b>address<b>)</b>
</p> </p>
<p class=description> <p class=description>
Converts from IP address to host name. Converts from IPv4 address to host name.
</p> </p>
<p class=parameters> <p class=parameters>
@@ -93,7 +144,7 @@ socket.dns.<b>toip(</b>address<b>)</b>
</p> </p>
<p class=description> <p class=description>
Converts from host name to IP address. Converts from host name to IPv4 address.
</p> </p>
<p class=parameters> <p class=parameters>
@@ -113,8 +164,8 @@ message.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -42,7 +42,7 @@
FTP (File Transfer Protocol) is a protocol used to transfer files FTP (File Transfer Protocol) is a protocol used to transfer files
between hosts. The <tt>ftp</tt> namespace offers thorough support between hosts. The <tt>ftp</tt> namespace offers thorough support
to FTP, under a simple interface. The implementation conforms to to FTP, under a simple interface. The implementation conforms to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc0959.txt">RFC 959</a>. <a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a>.
</p> </p>
<p> <p>
@@ -70,8 +70,8 @@ local ftp = require("socket.ftp")
<p> <p>
URLs MUST conform to URLs MUST conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC <a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
1738</a>, that is, an URL is a string in the form: that is, an URL is a string in the form:
</p> </p>
<blockquote> <blockquote>
@@ -86,7 +86,6 @@ the FTP module:
<ul> <ul>
<li> <tt>PASSWORD</tt>: default anonymous password. <li> <tt>PASSWORD</tt>: default anonymous password.
<li> <tt>PORT</tt>: default port used for the control connection;
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; <li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
<li> <tt>USER</tt>: default anonymous user; <li> <tt>USER</tt>: default anonymous user;
</ul> </ul>
@@ -270,8 +269,8 @@ f, e = ftp.put{
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -36,7 +36,7 @@
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=http>HTTP</h2> <h2 id="http">HTTP</h2>
<p> <p>
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
@@ -45,8 +45,7 @@ namespace offers full support for the client side of the HTTP
protocol (i.e., protocol (i.e.,
the facilities that would be used by a web-browser implementation). The the facilities that would be used by a web-browser implementation). The
implementation conforms to the HTTP/1.1 standard, implementation conforms to the HTTP/1.1 standard,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
2616</a>.
</p> </p>
<p> <p>
@@ -67,8 +66,7 @@ local http = require("socket.http")
<p> <p>
URLs must conform to URLs must conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC <a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
1738</a>,
that is, an URL is a string in the form: that is, an URL is a string in the form:
</p> </p>
@@ -97,8 +95,9 @@ headers = {<br>
</blockquote> </blockquote>
<p> <p>
Field names are case insensitive (as specified by the standard) and all Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names. functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified. Field values are left unmodified.
</p> </p>
@@ -113,15 +112,19 @@ the HTTP module:
</p> </p>
<ul> <ul>
<li> <tt>PORT</tt>: default port used for connections; <li> <tt>PROXY</tt>: default proxy used for connections;
<li> <tt>PROXY</tt>: default proxy used for connections;
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; <li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
<li> <tt>USERAGENT</tt>: default user agent reported to server. <li> <tt>USERAGENT</tt>: default user agent reported to server.
</ul> </ul>
<p class=note id="post">
Note: These constants are global. Changing them will also
change the behavior other code that might be using LuaSocket.
</p>
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=request> <p class=name id="request">
http.<b>request(</b>url [, body]<b>)</b><br> http.<b>request(</b>url [, body]<b>)</b><br>
http.<b>request{</b><br> http.<b>request{</b><br>
&nbsp;&nbsp;url = <i>string</i>,<br> &nbsp;&nbsp;url = <i>string</i>,<br>
@@ -132,7 +135,8 @@ http.<b>request{</b><br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> &nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[proxy = <i>string</i>,]<br> &nbsp;&nbsp;[proxy = <i>string</i>,]<br>
&nbsp;&nbsp;[redirect = <i>boolean</i>,]<br> &nbsp;&nbsp;[redirect = <i>boolean</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br> &nbsp;&nbsp;[create = <i>function</i>,]<br>
&nbsp;&nbsp;[maxredirects = <i>number</i>]<br>
<b>}</b> <b>}</b>
</p> </p>
@@ -182,6 +186,7 @@ Defaults to the LTN12 <tt>pump.step</tt> function.
function from automatically following 301 or 302 server redirect messages; function from automatically following 301 or 302 server redirect messages;
<li><tt>create</tt>: An optional function to be used instead of <li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. <a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
<li><tt>maxredirects</tt>: An optional number specifying the maximum number of redirects to follow. Defaults to <tt>5</tt> if not specified. A boolean <tt>false</tt> value means no maximum (unlimited).
</ul> </ul>
<p class=return> <p class=return>
@@ -199,8 +204,7 @@ it usually returns a message body (a web page informing the
URL was not found or some other useless page). To make sure the URL was not found or some other useless page). To make sure the
operation was successful, check the returned status <tt>code</tt>. For operation was successful, check the returned status <tt>code</tt>. For
a list of the possible values and their meanings, refer to <a a list of the possible values and their meanings, refer to <a
href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
2616</a>.
</p> </p>
<p class=description> <p class=description>
@@ -259,7 +263,7 @@ r, c, h = http.request {
-- } -- }
</pre> </pre>
<p class=note id=post> <p class=note id="post">
Note: When sending a POST request, simple interface adds a Note: When sending a POST request, simple interface adds a
"<tt>Content-type: application/x-www-form-urlencoded</tt>" "<tt>Content-type: application/x-www-form-urlencoded</tt>"
header to the request. This is the type used by header to the request. This is the type used by
@@ -267,7 +271,7 @@ HTML forms. If you need another type, use the generic
interface. interface.
</p> </p>
<p class=note id=authentication> <p class=note id="authentication">
Note: Some URLs are protected by their Note: Some URLs are protected by their
servers from anonymous download. For those URLs, the server must receive servers from anonymous download. For those URLs, the server must receive
some sort of authentication along with the request or it will deny some sort of authentication along with the request or it will deny
@@ -278,7 +282,7 @@ download and return status "401&nbsp;Authentication Required".
The HTTP/1.1 standard defines two authentication methods: the Basic The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both Authentication Scheme and the Digest Authentication Scheme, both
explained in detail in explained in detail in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2068.txt">RFC 2068</a>. <a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
</p> </p>
<p class=note>The Basic Authentication Scheme sends <p class=note>The Basic Authentication Scheme sends
@@ -304,7 +308,7 @@ b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
-- the request directly. -- the request directly.
r, c = http.request { r, c = http.request {
url = "http://www.example.com/private/index.html", url = "http://www.example.com/private/index.html",
headers = { authentication = "Basic " .. (mime.b64("fulano:silva")) } headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
} }
</pre> </pre>
@@ -314,16 +318,16 @@ r, c = http.request {
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
</p> </p>
<p> <p>
<small> <small>
Last modified by Diego Nehab on <br> Last modified by Eric Westbrook on <br>
Thu Apr 20 00:25:26 EDT 2006 Sat Feb 23 19:09:42 UTC 2019
</small> </small>
</p> </p>
</center> </center>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -49,7 +49,7 @@ functionality commonly needed by applications that deal with the Internet.
The core support has been implemented so that it is both efficient and The core support has been implemented so that it is both efficient and
simple to use. It is available to any Lua application once it has been simple to use. It is available to any Lua application once it has been
properly initialized by the interpreter in use. The code has been tested properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and Unix platforms. </p> and runs well on several Windows and UNIX platforms. </p>
<p> <p>
Among the support modules, the most commonly used implement the Among the support modules, the most commonly used implement the
@@ -78,8 +78,8 @@ LuaSocket.
</p> </p>
<p> <p>
Copyright &copy; 2004-2007 Diego Nehab. All rights reserved. <br> Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a> Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
</p> </p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -87,25 +87,18 @@ Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
<h2 id=download>Download</h2> <h2 id=download>Download</h2>
<p> <p>
LuaSocket version 2.0.2 is now available for download! It is LuaSocket version 3.0-rc1 is now available for download!
compatible with Lua&nbsp;5.1, and has It is compatible with Lua&nbsp;5.1 and 5.2, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
are it works well on most UNIX distributions and Windows flavors. are it works well on most UNIX distributions and Windows flavors.
</p> </p>
<p> <p>
The library can be downloaded in source code from the The current version of the library can be found at
<a href=http://luaforge.net/projects/luasocket/>LuaSocket the <a href="https://github.com/diegonehab/luasocket">LuaSocket
project page</a> at LuaForge. project page</a> on GitHub. Besides the full C and Lua source code
Besides the full C and Lua source code for the library, the distribution for the library, the distribution contains several examples,
contains several examples, this user's manual and basic test procedures. this user's manual and basic test procedures.
</p>
<p>
Danilo Tuler is maintaining Win32 binaries for LuaSocket, which are also
available from LuaForge. These are compatible with the
<a href=http://luaforge.net/projects/luabinaries>LuaBinaries</a>,
also available from LuaForge.
</p> </p>
<p> Take a look at the <a <p> Take a look at the <a
@@ -118,14 +111,14 @@ manual to find out how to properly install the library.
<h2 id=thanks>Special thanks</h2> <h2 id=thanks>Special thanks</h2>
<p> <p>
Throughout LuaSocket's history, many people gave suggestions that helped This marks the first release of LuaSocket that
improve it. For that, I thank the Lua community. wholeheartedly embraces the open-source development
Special thanks go to philosophy. After a long hiatus, Matthew Wild finally
David Burgess, who has helped push the library to a new level of quality and convinced me it was time for a release including IPv6 and
from whom I have learned a lot of stuff that doesn't show up in RFCs. Lua 5.2 support. It was more work than we anticipated.
Special thanks also to Carlos Cassino, who played a big part in the Special thanks to Sam Roberts, Florian Zeitz, and Paul
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall Aurich, Liam Devine, Alexey Melnichuk, and everybody else
has been helping a lot too! Thanks to you all! that has helped bring this library back to life.
</p> </p>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -133,41 +126,58 @@ has been helping a lot too! Thanks to you all!
<h2 id=new>What's New</h2> <h2 id=new>What's New</h2>
<p> <p>
2.0.2 is just a bug-fix/update release. Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
and Lua&nbsp;5.2 compatibility.
</p> </p>
<ul> <ul>
<li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin); <li> Added: Compatible with Lua&nbsp;5.2
<li> Fixed: return values are consistent when reading from closed sockets; <ul>
<li> Fixed: case sensitivity in headers of multipart <li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
messages in smtp.message() (Graham Henstridge); package tables will <em>not</em> be exported as globals!
<li> Fixed a couple instances of error() being called instead of
base.error(). These would cause an error when an error was
reported :) (Ketmar Dark);
<li> Fixed: test script now uses pairs() iterator instead
of the old Lua syntax (Robert Dodier).
</ul> </ul>
<li> Added: IPv6 support;
<p>
2.0.1 is just a bug-fix/update release.
</p>
<ul> <ul>
<li> Updated: now using <tt>compat-5.1r5</tt>; <li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
<li> Improved: <tt>http.request</tt> is more robust to <li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
malformed URLs (Adrian Sietsma); IPv6 addresses, and return the socket family as a third value;
<li> Improved: the simple <tt>http.request</tt> interface sends a <li> URL module updated to support IPv6 host names;
"<tt>Content-type: application/x-www-form-urlencoded</tt>" <li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
header (William Trenker); <li> New <tt>socket.dns.getaddrinfo</tt> and
<li> Improved: <tt>http.request</tt> is robust to evil <tt>socket.dns.getnameinfo</tt> functions;
servers that send inappropriate 100-continue messages </ul>
(David Burgess); <li> Added: <tt>getoption</tt> method;
<li> Fixed: <tt>http.request</tt> was using the old host header during <li> Fixed: <tt>url.unescape</tt> was returning additional values;
redirects (Florian Berger); <li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
<li> Fixed: sample <tt>unix.c</tt> had fallen through the <tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
cracks during development (Matthew Percival); mistaking their own stack slots for functions arguments;
<li> Fixed: error code was not being propagated correctly in <li> Fixed: Receiving zero-length datagram is now possible;
ftp.lua (David Burgess). <li> Improved: Hidden all internal library symbols;
<li> Improved: Better error messages;
<li> Improved: Better documentation of socket options.
<li> Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
<li> Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
<li> Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
<li> Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
<li> Fixed: manual links to home.html changed to index.html
(Robert Hahn);
<li> Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
<li> Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
<li> Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
<li> Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
<li> Improved: Clarified tcp:receive() in the manual (MPB);
<li> Improved: Decent makefiles (LHF).
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
</ul> </ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -176,7 +186,7 @@ ftp.lua (David Burgess).
<p> <p>
All previous versions of the LuaSocket library can be downloaded <a All previous versions of the LuaSocket library can be downloaded <a
href="http://www.cs.princeton.edu/~diego/professional/luasocket/old"> href="http://www.impa.br/~diego/software/luasocket/old">
here</a>. Although these versions are no longer supported, they are here</a>. Although these versions are no longer supported, they are
still available for those that have compatibility issues. still available for those that have compatibility issues.
</p> </p>
@@ -187,7 +197,7 @@ still available for those that have compatibility issues.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -195,7 +205,7 @@ still available for those that have compatibility issues.
<p> <p>
<small> <small>
Last modified by Diego Nehab on <br> Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:23 EDT 2006 Tue Jun 11 18:50:23 HKT 2013
</small> </small>
</p> </p>
</center> </center>

View File

@@ -25,8 +25,8 @@ Installation">
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -39,24 +39,10 @@ Installation">
<h2>Installation</h2> <h2>Installation</h2>
<p> LuaSocket 2.0.2 uses the new package system for Lua 5.1. <p> Here we describe the standard distribution. If the
All Lua library developers are encouraged to update their libraries so that standard doesn't meet your needs, we refer you to the Lua
all libraries can coexist peacefully and users can benefit from the discussion list, where any question about the package scheme
standardization and flexibility of the standard. will likely already have been answered. </p>
</p>
<p>
Those stuck with Lua 5.0 will need the
<a href=http://www.keplerproject.org/compat/>compat-5.1</a>
module. It is maintained by
<a href=http://www.keplerproject.org/>The Kepler
Project</a>'s team, and implements the Lua 5.1 package proposal
on top of Lua 5.0. </p>
<p> Here we will only describe the standard distribution.
If the standard doesn't meet your needs, we refer you to the
Lua discussion list, where any question about the package
scheme will likely already have been answered. </p>
<h3>Directory structure</h3> <h3>Directory structure</h3>
@@ -64,14 +50,19 @@ scheme will likely already have been answered. </p>
directories, one for system dependent files, and another for system directories, one for system dependent files, and another for system
independent files. Let's call these directories <tt>&lt;CDIR&gt;</tt> independent files. Let's call these directories <tt>&lt;CDIR&gt;</tt>
and <tt>&lt;LDIR&gt;</tt>, respectively. and <tt>&lt;LDIR&gt;</tt>, respectively.
For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for For example, in my laptp, Lua&nbsp;5.1 is configured to
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.0</tt>' for use '<tt>/usr/local/lib/lua/5.1</tt>' for
<tt>&lt;LDIR&gt;</tt>. On Windows, sometimes only one directory is used, say <tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.1</tt>' for
'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket <tt>&lt;LDIR&gt;</tt>. On Windows, <tt>&lt;CDIR&gt;</tt>
usually points to the directory where the Lua executable is
found, and <tt>&lt;LDIR&gt;</tt> points to a
<tt>lua/</tt> directory inside <tt>&lt;CDIR&gt;</tt>. (These
settings can be overridden by environment variables
<tt>LUA_PATH</tt> and <tt>LUA_CPATH</tt>. See the Lua
documentation for details.) Here is the standard LuaSocket
distribution directory structure:</p> distribution directory structure:</p>
<pre class=example> <pre class=example>
&lt;LDIR&gt;/compat-5.1.lua
&lt;LDIR&gt;/ltn12.lua &lt;LDIR&gt;/ltn12.lua
&lt;LDIR&gt;/socket.lua &lt;LDIR&gt;/socket.lua
&lt;CDIR&gt;/socket/core.dll &lt;CDIR&gt;/socket/core.dll
@@ -88,33 +79,6 @@ distribution directory structure:</p>
would be replaced by <tt>core.so</tt>. would be replaced by <tt>core.so</tt>.
</p> </p>
<p> In order for the interpreter to find all LuaSocket components, three
environment variables need to be set. The first environment variable tells
the interpreter to load the <tt>compat-5.1.lua</tt> module at startup: </p>
<pre class=example>
LUA_INIT=@&lt;LDIR&gt;/compat-5.1.lua
</pre>
<p>
This is only need for Lua&nbsp;5.0! Lua&nbsp;5.1 comes with
the package system built in, of course.
</p>
<p>
The other two environment variables instruct the compatibility module to
look for dynamic libraries and extension modules in the appropriate
directories and with the appropriate filename extensions.
</p>
<pre class=example>
LUA_PATH=&lt;LDIR&gt;/?.lua;?.lua
LUA_CPATH=&lt;CDIR&gt;/?.dll;?.dll
</pre>
<p> Again, naturally, on Unix systems the shared library extension would be
<tt>.so</tt> instead of <tt>.dll</tt>.</p>
<h3>Using LuaSocket</h3> <h3>Using LuaSocket</h3>
<p> With the above setup, and an interpreter with shared library support, <p> With the above setup, and an interpreter with shared library support,
@@ -122,19 +86,19 @@ it should be easy to use LuaSocket. Just fire the interpreter and use the
<tt>require</tt> function to gain access to whatever module you need:</p> <tt>require</tt> function to gain access to whatever module you need:</p>
<pre class=example> <pre class=example>
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; socket = require("socket") &gt; socket = require("socket")
&gt; print(socket._VERSION) &gt; print(socket._VERSION)
--&gt; LuaSocket 2.0.2 --&gt; LuaSocket 3.0-rc1
</pre> </pre>
<p> Each module loads their dependencies automatically, so you only need to <p> Each module loads their dependencies automatically, so you only need to
load the modules you directly depend upon: </p> load the modules you directly depend upon: </p>
<pre class=example> <pre class=example>
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; http = require("socket.http") &gt; http = require("socket.http")
&gt; print(http.request("http://www.cs.princeton.edu/~diego/professional/luasocket")) &gt; print(http.request("http://www.impa.br/~diego/software/luasocket"))
--&gt; homepage gets dumped to terminal --&gt; homepage gets dumped to terminal
</pre> </pre>
@@ -144,8 +108,8 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -153,7 +117,7 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<p> <p>
<small> <small>
Last modified by Diego Nehab on <br> Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:30 EDT 2006 Tue Jun 11 19:06:14 HKT 2013
</small> </small>
</p> </p>
</center> </center>

View File

@@ -25,8 +25,8 @@ Library, Support">
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -314,8 +314,8 @@ and many others are covered by the <a href=reference.html>reference manual</a>.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -25,8 +25,8 @@ Pump, Support, Library">
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -224,8 +224,8 @@ local ltn12 = require("ltn12")
-- copy a file -- copy a file
ltn12.pump.all( ltn12.pump.all(
ltn12.source.file(io.open("original.png")), ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png")) ltn12.sink.file(io.open("copy.png", "wb"))
) )
</pre> </pre>
@@ -379,8 +379,8 @@ local ltn12 = require("ltn12")
-- copy a file -- copy a file
ltn12.pump.all( ltn12.pump.all(
ltn12.source.file(io.open("original.png")), ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png")) ltn12.sink.file(io.open("copy.png", "wb"))
) )
</pre> </pre>
@@ -405,14 +405,24 @@ Creates and returns a source that produces the contents of a
<tt>string</tt>, chunk by chunk. <tt>string</tt>, chunk by chunk.
</p> </p>
<!-- table +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.table">
ltn12.source.<b>table(</b>table<b>)</b>
</p>
<p class=description>
Creates and returns a source that produces the numerically-indexed values of a <tt>table</tt> successively beginning at 1. The source returns nil (end-of-stream) whenever a nil value is produced by the current index, which proceeds forward regardless.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class=footer>
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -44,11 +44,11 @@ content transfer encodings, such as Base64 and Quoted-Printable.
It also provides functions to break text into lines and change It also provides functions to break text into lines and change
the end-of-line convention. the end-of-line convention.
MIME is described mainly in MIME is described mainly in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>, <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>, <a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>, <a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and <a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2048.txt">2049</a>. <a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
</p> </p>
<p> <p>
@@ -72,34 +72,6 @@ local mime = require("mime")
<h3 id=high>High-level filters</h3> <h3 id=high>High-level filters</h3>
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="normalize">
mime.<b>normalize(</b>[marker]<b>)</b>
</p>
<p class=description>
Converts most common end-of-line markers to a specific given marker.
</p>
<p class=parameters>
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
end-of-line marker defined by the MIME standard.
</p>
<p class=return>
The function returns a filter that performs the conversion.
</p>
<p class=note>
Note: There is no perfect solution to this problem. Different end-of-line
markers are an evil that will probably plague developers forever.
This function, however, will work perfectly for text created with any of
the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
markers, the function will still work well, although it doesn't
guarantee that the number of empty lines will be correct.
</p>
<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -159,6 +131,35 @@ base64 = ltn12.filter.chain(
) )
</pre> </pre>
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="normalize">
mime.<b>normalize(</b>[marker]<b>)</b>
</p>
<p class=description>
Converts most common end-of-line markers to a specific given marker.
</p>
<p class=parameters>
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
end-of-line marker defined by the MIME standard.
</p>
<p class=return>
The function returns a filter that performs the conversion.
</p>
<p class=note>
Note: There is no perfect solution to this problem. Different end-of-line
markers are an evil that will probably plague developers forever.
This function, however, will work perfectly for text created with any of
the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
markers, the function will still work well, although it doesn't
guarantee that the number of empty lines will be correct.
</p>
<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="stuff"> <p class=name id="stuff">
@@ -457,8 +458,8 @@ marker.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -466,7 +467,7 @@ marker.
<p> <p>
<small> <small>
Last modified by Diego Nehab on <br> Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:44 EDT 2006 Fri Mar 4 15:19:17 BRT 2016
</small> </small>
</p> </p>
</center> </center>

View File

@@ -2,6 +2,7 @@ body {
margin-left: 1em; margin-left: 1em;
margin-right: 1em; margin-right: 1em;
font-family: "Verdana", sans-serif; font-family: "Verdana", sans-serif;
background: #ffffff;
} }
tt { tt {

View File

@@ -25,8 +25,8 @@ Support, Manual">
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -42,9 +42,10 @@ Support, Manual">
<blockquote> <blockquote>
<a href="dns.html">DNS (in socket)</a> <a href="dns.html">DNS (in socket)</a>
<blockquote> <blockquote>
<a href="dns.html#toip">toip</a>, <a href="dns.html#getaddrinfo">getaddrinfo</a>,
<a href="dns.html#gethostname">gethostname</a>,
<a href="dns.html#tohostname">tohostname</a>, <a href="dns.html#tohostname">tohostname</a>,
<a href="dns.html#gethostname">gethostname</a>. <a href="dns.html#toip">toip</a>.
</blockquote> </blockquote>
</blockquote> </blockquote>
@@ -98,7 +99,8 @@ Support, Manual">
<a href="ltn12.html#source.error">error</a>, <a href="ltn12.html#source.error">error</a>,
<a href="ltn12.html#source.file">file</a>, <a href="ltn12.html#source.file">file</a>,
<a href="ltn12.html#source.simplify">simplify</a>, <a href="ltn12.html#source.simplify">simplify</a>,
<a href="ltn12.html#source.string">string</a>. <a href="ltn12.html#source.string">string</a>,
<a href="ltn12.html#source.table">table</a>.
</blockquote> </blockquote>
</blockquote> </blockquote>
@@ -108,9 +110,9 @@ Support, Manual">
<a href="mime.html">MIME</a> <a href="mime.html">MIME</a>
<blockquote> <blockquote>
<a href="mime.html#high">high-level</a>: <a href="mime.html#high">high-level</a>:
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#decode">decode</a>, <a href="mime.html#decode">decode</a>,
<a href="mime.html#encode">encode</a>, <a href="mime.html#encode">encode</a>,
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#stuff">stuff</a>, <a href="mime.html#stuff">stuff</a>,
<a href="mime.html#wrap">wrap</a>. <a href="mime.html#wrap">wrap</a>.
</blockquote> </blockquote>
@@ -120,10 +122,10 @@ Support, Manual">
<a href="mime.html#dot">dot</a>, <a href="mime.html#dot">dot</a>,
<a href="mime.html#eol">eol</a>, <a href="mime.html#eol">eol</a>,
<a href="mime.html#qp">qp</a>, <a href="mime.html#qp">qp</a>,
<a href="mime.html#wrp">wrp</a>, <a href="mime.html#qpwrp">qpwrp</a>,
<a href="mime.html#qpwrp">qpwrp</a>.
<a href="mime.html#unb64">unb64</a>, <a href="mime.html#unb64">unb64</a>,
<a href="mime.html#unqp">unqp</a>, <a href="mime.html#unqp">unqp</a>,
<a href="mime.html#wrp">wrp</a>.
</blockquote> </blockquote>
</blockquote> </blockquote>
@@ -142,19 +144,31 @@ Support, Manual">
<blockquote> <blockquote>
<a href="socket.html">Socket</a> <a href="socket.html">Socket</a>
<blockquote> <blockquote>
<a href="socket.html#bind">bind</a>,
<a href="socket.html#connect">connect</a>,
<a href="socket.html#connect">connect4</a>,
<a href="socket.html#connect">connect6</a>,
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
<a href="socket.html#debug">_DEBUG</a>, <a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>, <a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>, <a href="socket.html#gettime">gettime</a>,
<a href="socket.html#headers.canonic">headers.canonic</a>,
<a href="socket.html#newtry">newtry</a>, <a href="socket.html#newtry">newtry</a>,
<a href="socket.html#protect">protect</a>, <a href="socket.html#protect">protect</a>,
<a href="socket.html#select">select</a>, <a href="socket.html#select">select</a>,
<a href="socket.html#sink">sink</a>, <a href="socket.html#sink">sink</a>,
<a href="socket.html#skip">skip</a>, <a href="socket.html#skip">skip</a>,
<a href="socket.html#sleep">sleep</a>, <a href="socket.html#sleep">sleep</a>,
<a href="socket.html#setsize">_SETSIZE</a>,
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
<a href="socket.html#source">source</a>, <a href="socket.html#source">source</a>,
<a href="tcp.html#tcp">tcp</a>, <a href="tcp.html#socket.tcp">tcp</a>,
<a href="tcp.html#socket.tcp4">tcp4</a>,
<a href="tcp.html#socket.tcp6">tcp6</a>,
<a href="socket.html#try">try</a>, <a href="socket.html#try">try</a>,
<a href="udp.html#udp">udp</a>, <a href="udp.html#socket.udp">udp</a>,
<a href="udp.html#socket.udp4">udp4</a>,
<a href="udp.html#socket.udp6">udp6</a>,
<a href="socket.html#version">_VERSION</a>. <a href="socket.html#version">_VERSION</a>.
</blockquote> </blockquote>
</blockquote> </blockquote>
@@ -168,11 +182,17 @@ Support, Manual">
<a href="tcp.html#bind">bind</a>, <a href="tcp.html#bind">bind</a>,
<a href="tcp.html#close">close</a>, <a href="tcp.html#close">close</a>,
<a href="tcp.html#connect">connect</a>, <a href="tcp.html#connect">connect</a>,
<a href="tcp.html#dirty">dirty</a>,
<a href="tcp.html#getfd">getfd</a>,
<a href="tcp.html#getoption">getoption</a>,
<a href="tcp.html#getpeername">getpeername</a>, <a href="tcp.html#getpeername">getpeername</a>,
<a href="tcp.html#getsockname">getsockname</a>, <a href="tcp.html#getsockname">getsockname</a>,
<a href="tcp.html#getstats">getstats</a>, <a href="tcp.html#getstats">getstats</a>,
<a href="tcp.html#gettimeout">gettimeout</a>,
<a href="tcp.html#listen">listen</a>,
<a href="tcp.html#receive">receive</a>, <a href="tcp.html#receive">receive</a>,
<a href="tcp.html#send">send</a>, <a href="tcp.html#send">send</a>,
<a href="tcp.html#setfd">setfd</a>,
<a href="tcp.html#setoption">setoption</a>, <a href="tcp.html#setoption">setoption</a>,
<a href="tcp.html#setstats">setstats</a>, <a href="tcp.html#setstats">setstats</a>,
<a href="tcp.html#settimeout">settimeout</a>, <a href="tcp.html#settimeout">settimeout</a>,
@@ -186,8 +206,10 @@ Support, Manual">
<a href="udp.html">UDP (in socket)</a> <a href="udp.html">UDP (in socket)</a>
<blockquote> <blockquote>
<a href="udp.html#close">close</a>, <a href="udp.html#close">close</a>,
<a href="udp.html#getoption">getoption</a>,
<a href="udp.html#getpeername">getpeername</a>, <a href="udp.html#getpeername">getpeername</a>,
<a href="udp.html#getsockname">getsockname</a>, <a href="udp.html#getsockname">getsockname</a>,
<a href="udp.html#gettimeout">gettimeout</a>,
<a href="udp.html#receive">receive</a>, <a href="udp.html#receive">receive</a>,
<a href="udp.html#receivefrom">receivefrom</a>, <a href="udp.html#receivefrom">receivefrom</a>,
<a href="udp.html#send">send</a>, <a href="udp.html#send">send</a>,
@@ -220,8 +242,8 @@ Support, Manual">
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -25,8 +25,8 @@ Library, Support">
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -48,14 +48,13 @@ control (if you bother to read the code).
</p> </p>
<p>The implementation conforms to the Simple Mail Transfer Protocol, <p>The implementation conforms to the Simple Mail Transfer Protocol,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>. <a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>.
Another RFC of interest is <a Another RFC of interest is <a
href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>, href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
which governs the Internet Message Format. which governs the Internet Message Format.
Multipart messages (those that contain attachments) are part Multipart messages (those that contain attachments) are part
of the MIME standard, but described mainly of the MIME standard, but described mainly
in <a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">RFC in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
2046</a>
<p> In the description below, good understanding of <a <p> In the description below, good understanding of <a
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
@@ -91,8 +90,9 @@ headers = {<br>
</blockquote> </blockquote>
<p> <p>
Field names are case insensitive (as specified by the standard) and all Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names. functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified. Field values are left unmodified.
</p> </p>
@@ -114,167 +114,6 @@ the SMTP module:
<li> <tt>ZONE</tt>: default time zone. <li> <tt>ZONE</tt>: default time zone.
</ul> </ul>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send>
smtp.<b>send{</b><br>
&nbsp;&nbsp;from = <i>string</i>,<br>
&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br>
&nbsp;&nbsp;source = <i>LTN12 source</i>,<br>
&nbsp;&nbsp;[user = <i>string</i>,]<br>
&nbsp;&nbsp;[password = <i>string</i>,]<br>
&nbsp;&nbsp;[server = <i>string</i>,]<br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[domain = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
Sends a message to a recipient list. Since sending messages is not as
simple as downloading an URL from a FTP or HTTP server, this function
doesn't have a simple interface. However, see the
<a href=#message><tt>message</tt></a> source factory for
a very powerful way to define the message contents.
</p>
<p class=parameters>
The sender is given by the e-mail address in the <tt>from</tt> field.
<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
address, or a string
in case there is just one recipient.
The contents of the message are given by a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt>. Several arguments are optional:
</p>
<ul>
<li> <tt>user</tt>, <tt>password</tt>: User and password for
authentication. The function will attempt LOGIN and PLAIN authentication
methods if supported by the server (both are unsafe);
<li> <tt>server</tt>: Server to connect to. Defaults to "localhost";
<li> <tt>port</tt>: Port to connect to. Defaults to 25;
<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
local machine host name;
<li> <tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
If successful, the function returns 1. Otherwise, the function returns
<b><tt>nil</tt></b> followed by an error message.
</p>
<p class=note>
Note: SMTP servers can be very picky with the format of e-mail
addresses. To be safe, use only addresses of the form
"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and
<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
addresses can take whatever form you like. </p>
<p class=note>
Big note: There is a good deal of misconception with the use of the
destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
'<tt>Bcc</tt>' header to your messages because it will probably do the
exact opposite of what you expect.
</p>
<p class=note>
Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
message. Each recipient of an SMTP mail message receives a copy of the
message body along with the headers, and nothing more. The headers
<em>are</em> part of the message and should be produced by the
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em>
part of the message and will not be sent to anyone.
</p>
<p class=note>
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper
use of these headers. Here is a summary of what it says:
</p>
<ul>
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
of the message;
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
making a copy on a typewriter using carbon paper) contains the
addresses of others who are to receive the message, though the
content of the message may not be directed at them;
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.
</ul>
<p class=note>
The LuaSocket <tt>send</tt> function does not care or interpret the
headers you send, but it gives you full control over what is sent and
to whom it is sent:
</p>
<ul>
<li> If someone is to receive the message, the e-mail address <em>has</em>
to be in the recipient list. This is the only parameter that controls who
gets a copy of the message;
<li> If there are multiple recipients, none of them will automatically
know that someone else got that message. That is, the default behavior is
similar to the <tt>Bcc</tt> field of popular e-mail clients;
<li> It is up to you to add the <tt>To</tt> header with the list of primary
recipients so that other recipients can see it;
<li> It is also up to you to add the <tt>Cc</tt> header with the
list of additional recipients so that everyone else sees it;
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
empty. Otherwise, everyone receiving the message will see it and that is
exactly what you <em>don't</em> want to happen!
</ul>
<p class=note>
I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>
and
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>.
</p>
<pre class=example>
-- load the smtp support
local smtp = require("socket.smtp")
-- Connects to server "localhost" and sends a message to users
-- "fulano@example.com", "beltrano@example.com",
-- and "sicrano@example.com".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
from = "&lt;luasocket@example.com&gt;"
rcpt = {
"&lt;fulano@example.com&gt;",
"&lt;beltrano@example.com&gt;",
"&lt;sicrano@example.com&gt;"
}
mesgt = {
headers = {
to = "Fulano da Silva &lt;fulano@example.com&gt;",
cc = '"Beltrano F. Nunes" &lt;beltrano@example.com&gt;',
subject = "My first message"
},
body = "I hope this works. If it does, I can send you another 1000 copies."
}
r, e = smtp.send{
from = from,
rcpt = rcpt,
source = smtp.message(mesgt)
}
</pre>
<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=message> <p class=name id=message>
@@ -392,14 +231,176 @@ r, e = smtp.send{
} }
</pre> </pre>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send>
smtp.<b>send{</b><br>
&nbsp;&nbsp;from = <i>string</i>,<br>
&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br>
&nbsp;&nbsp;source = <i>LTN12 source</i>,<br>
&nbsp;&nbsp;[user = <i>string</i>,]<br>
&nbsp;&nbsp;[password = <i>string</i>,]<br>
&nbsp;&nbsp;[server = <i>string</i>,]<br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[domain = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
Sends a message to a recipient list. Since sending messages is not as
simple as downloading an URL from a FTP or HTTP server, this function
doesn't have a simple interface. However, see the
<a href=#message><tt>message</tt></a> source factory for
a very powerful way to define the message contents.
</p>
<p class=parameters>
The sender is given by the e-mail address in the <tt>from</tt> field.
<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
address, or a string
in case there is just one recipient.
The contents of the message are given by a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt>. Several arguments are optional:
</p>
<ul>
<li> <tt>user</tt>, <tt>password</tt>: User and password for
authentication. The function will attempt LOGIN and PLAIN authentication
methods if supported by the server (both are unsafe);
<li> <tt>server</tt>: Server to connect to. Defaults to "localhost";
<li> <tt>port</tt>: Port to connect to. Defaults to 25;
<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
local machine host name;
<li> <tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
If successful, the function returns 1. Otherwise, the function returns
<b><tt>nil</tt></b> followed by an error message.
</p>
<p class=note>
Note: SMTP servers can be very picky with the format of e-mail
addresses. To be safe, use only addresses of the form
"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and
<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
addresses can take whatever form you like. </p>
<p class=note>
Big note: There is a good deal of misconception with the use of the
destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
'<tt>Bcc</tt>' header to your messages because it will probably do the
exact opposite of what you expect.
</p>
<p class=note>
Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
message. Each recipient of an SMTP mail message receives a copy of the
message body along with the headers, and nothing more. The headers
<em>are</em> part of the message and should be produced by the
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em>
part of the message and will not be sent to anyone.
</p>
<p class=note>
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper
use of these headers. Here is a summary of what it says:
</p>
<ul>
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
of the message;
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
making a copy on a typewriter using carbon paper) contains the
addresses of others who are to receive the message, though the
content of the message may not be directed at them;
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.
</ul>
<p class=note>
The LuaSocket <tt>send</tt> function does not care or interpret the
headers you send, but it gives you full control over what is sent and
to whom it is sent:
</p>
<ul>
<li> If someone is to receive the message, the e-mail address <em>has</em>
to be in the recipient list. This is the only parameter that controls who
gets a copy of the message;
<li> If there are multiple recipients, none of them will automatically
know that someone else got that message. That is, the default behavior is
similar to the <tt>Bcc</tt> field of popular e-mail clients;
<li> It is up to you to add the <tt>To</tt> header with the list of primary
recipients so that other recipients can see it;
<li> It is also up to you to add the <tt>Cc</tt> header with the
list of additional recipients so that everyone else sees it;
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
empty. Otherwise, everyone receiving the message will see it and that is
exactly what you <em>don't</em> want to happen!
</ul>
<p class=note>
I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
and
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
</p>
<pre class=example>
-- load the smtp support
local smtp = require("socket.smtp")
-- Connects to server "localhost" and sends a message to users
-- "fulano@example.com", "beltrano@example.com",
-- and "sicrano@example.com".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
from = "&lt;luasocket@example.com&gt;"
rcpt = {
"&lt;fulano@example.com&gt;",
"&lt;beltrano@example.com&gt;",
"&lt;sicrano@example.com&gt;"
}
mesgt = {
headers = {
to = "Fulano da Silva &lt;fulano@example.com&gt;",
cc = '"Beltrano F. Nunes" &lt;beltrano@example.com&gt;',
subject = "My first message"
},
body = "I hope this works. If it does, I can send you another 1000 copies."
}
r, e = smtp.send{
from = from,
rcpt = rcpt,
source = smtp.message(mesgt)
}
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class=footer>
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -51,6 +51,30 @@ To obtain the <tt>socket</tt> namespace, run:
local socket = require("socket") local socket = require("socket")
</pre> </pre>
<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="headers.canonic">
socket.headers.<b>canonic</b></p>
<p> The <tt>socket.headers.canonic</tt> table
is used by the HTTP and SMTP modules to translate from
lowercase field names back into their canonic
capitalization. When a lowercase field name exists as a key
in this table, the associated value is substituted in
whenever the field name is sent out.
</p>
<p>
You can obtain the <tt>headers</tt> namespace if case run-time
modifications are required by running:
</p>
<pre class=example>
-- loads the headers module
local headers = require("headers")
</pre>
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind> <p class=name id=bind>
@@ -73,19 +97,24 @@ set to <tt><b>true</b></tt>.
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect> <p class=name id=connect>
socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b> socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p> </p>
<p class=description> <p class=description>
This function is a shortcut that creates and returns a TCP client object This function is a shortcut that creates and returns a TCP client object
connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally, connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
the user can also specify the local address and port to bind the user can also specify the local address and port to bind
(<tt>locaddr</tt> and <tt>locport</tt>). (<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
to "<tt>inet</tt>" or "<tt>inet6</tt>".
Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
connection is created depends on your system configuration. Two variations
of connect are defined as simple helper functions that restrict the
<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
</p> </p>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug> <p class=name id=debug>
socket.<b>_DEBUG</b> socket.<b>_DEBUG</b>
</p> </p>
@@ -94,6 +123,36 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support. with debug support.
</p> </p>
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
socket.<b>_DATAGRAMSIZE</b>
</p>
<p class=description>
Default datagram size used by calls to
<a href="udp.html#receive"<tt>receive</tt></a> and
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
(Unless changed in compile time, the value is 8192.)
</p>
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
socket.<b>gettime()</b>
</p>
<p class=description>
Returns the UNIX time in seconds. You should subtract the values returned by this function
to get meaningful values.
</p>
<pre class=example>
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry> <p class=name id=newtry>
@@ -109,8 +168,7 @@ is raised.
<p class=parameters> <p class=parameters>
<tt>Finalizer</tt> is a function that will be called before <tt>Finalizer</tt> is a function that will be called before
<tt>try</tt> throws the exception. It will be called <tt>try</tt> throws the exception.
in <em>protected</em> mode.
</p> </p>
<p class=return> <p class=return>
@@ -158,15 +216,9 @@ to throw exceptions.
</p> </p>
<p class=return> <p class=return>
Returns an equivalent function that instead of throwing exceptions, Returns an equivalent function that instead of throwing exceptions in case of
returns <tt><b>nil</b></tt> followed by an error message. a failed <a href=#try><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
</p> followed by an error message.
<p class=note>
Note: Beware that if your function performs some illegal operation that
raises an error, the protected function will catch the error and return it
as a string. This is because the <a href=#try><tt>try</tt></a> function
uses errors as the mechanism to throw exceptions.
</p> </p>
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -192,13 +244,24 @@ non-numeric indices) in the arrays will be silently ignored.
<p class=return> The function returns a list with the sockets ready for <p class=return> The function returns a list with the sockets ready for
reading, a list with the sockets ready for writing and an error message. reading, a list with the sockets ready for writing and an error message.
The error message is "<tt>timeout</tt>" if a timeout condition was met and The error message is "<tt>timeout</tt>" if a timeout
condition was met, "<tt>select failed</tt>" if the call
to <tt>select</tt> failed, and
<tt><b>nil</b></tt> otherwise. The returned tables are <tt><b>nil</b></tt> otherwise. The returned tables are
doubly keyed both by integers and also by the sockets doubly keyed both by integers and also by the sockets
themselves, to simplify the test if a specific socket has themselves, to simplify the test if a specific socket has
changed status. changed status.
</p> </p>
<p class=note>
<b>Note:</b> <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
number may be as high as 1024 or as low as 64 by default,
depending on the system. It is usually possible to change this
at compile time. Invoking <tt>select</tt> with a larger
number of sockets will raise an error.
</p>
<p class=note> <p class=note>
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail <b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
on non-blocking TCP sockets. The function may return a socket as on non-blocking TCP sockets. The function may return a socket as
@@ -217,6 +280,22 @@ method or <tt>accept</tt> might block forever.
it to <tt>select</tt>, it will be ignored. it to <tt>select</tt>, it will be ignored.
</p> </p>
<p class=note>
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
</p>
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setsize>
socket.<b>_SETSIZE</b>
</p>
<p class=description>
The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle.
</p>
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink> <p class=name id=sink>
@@ -288,8 +367,8 @@ Freezes the program execution during a given amount of time.
</p> </p>
<p class=parameters> <p class=parameters>
<tt>Time</tt> is the number of seconds to sleep for. <tt>Time</tt> is the number of seconds to sleep for. If
The function truncates <tt>time</tt> down to the nearest integer. <tt>time</tt> is negative, the function returns immediately.
</p> </p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -324,24 +403,16 @@ side closes the connection.
The function returns a source with the appropriate behavior. The function returns a source with the appropriate behavior.
</p> </p>
<!-- time ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime> <p class=name id=socketinvalid>
socket.<b>gettime()</b> socket.<b>_SOCKETINVALID</b>
</p> </p>
<p class=description> <p class=description>
Returns the time in seconds, relative to the origin of the The OS value for an invalid socket.
universe. You should subtract the values returned by this function
to get meaningful values.
</p> </p>
<pre class=example>
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try> <p class=name id=try>
@@ -349,9 +420,9 @@ socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b
</p> </p>
<p class=description> <p class=description>
Throws an exception in case of error. The exception can only be caught Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
by the <a href=#protect><tt>protect</tt></a> function. It does not explode <tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
into an error message. by a <a href=#protect><tt>protect</tt></a>ed function only.
</p> </p>
<p class=parameters> <p class=parameters>
@@ -362,7 +433,10 @@ nested with <tt>try</tt>.
<p class=return> <p class=return>
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt>. Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub>. <tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
in a table with metatable used by <a href=#protect><tt>protect</tt></a> to
distinguish exceptions from runtime errors.
</p> </p>
<pre class=example> <pre class=example>
@@ -386,8 +460,8 @@ This constant has a string describing the current LuaSocket version.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -1,10 +1,10 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"> "http://www.w3.org/TR/html4/strict.dtd">
<html> <html>
<head> <head>
<meta name="description" content="LuaSocket: The TCP/IP support"> <meta name="description" content="LuaSocket: The TCP/IP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support"> <meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<title>LuaSocket: TCP/IP support</title> <title>LuaSocket: TCP/IP support</title>
<link rel="stylesheet" href="reference.css" type="text/css"> <link rel="stylesheet" href="reference.css" type="text/css">
</head> </head>
@@ -24,11 +24,11 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
</p> </p>
</center> </center>
<hr> <hr>
@@ -36,31 +36,11 @@
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=tcp>TCP</h2> <h2 id="tcp">TCP</h2>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socket.tcp>
socket.<b>tcp()</b>
</p>
<p class=description>
Creates and returns a TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=accept> <p class=name id="accept">
server:<b>accept()</b> server:<b>accept()</b>
</p> </p>
@@ -70,9 +50,9 @@ object and returns a client object representing that connection.
</p> </p>
<p class=return> <p class=return>
If a connection is successfully initiated, a client object is returned. If a connection is successfully initiated, a client object is returned.
If a timeout condition is met, the method returns <b><tt>nil</tt></b> If a timeout condition is met, the method returns <b><tt>nil</tt></b>
followed by the error string '<tt>timeout</tt>'. Other errors are followed by the error string '<tt>timeout</tt>'. Other errors are
reported by <b><tt>nil</tt></b> followed by a message describing the error. reported by <b><tt>nil</tt></b> followed by a message describing the error.
</p> </p>
@@ -82,26 +62,28 @@ with a server object in
the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a <em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt> href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up. might block until <em>another</em> client shows up.
</p> </p>
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind> <p class=name id="bind">
master:<b>bind(</b>address, port<b>)</b> master:<b>bind(</b>address, port<b>)</b>
</p> </p>
<p class=description> <p class=description>
Binds a master object to <tt>address</tt> and <tt>port</tt> on the Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host. local host.
<p class=parameters> <p class=parameters>
<tt>Address</tt> can be an IP address or a host name. <tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [0..64K). <tt>Port</tt> must be an integer number in the range [0..64K).
If <tt>address</tt> If <tt>address</tt>
is '<tt>*</tt>', the system binds to all local interfaces is '<tt>*</tt>', the system binds to all local interfaces
using the <tt>INADDR_ANY</tt> constant. If <tt>port</tt> is 0, the system automatically using the <tt>INADDR_ANY</tt> constant or
chooses an ephemeral port. <tt>IN6ADDR_ANY_INIT</tt>, according to the family.
If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port.
</p> </p>
<p class=return> <p class=return>
@@ -110,13 +92,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
</p> </p>
<p class=note> <p class=note>
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
is available and is a shortcut for the creation of server sockets. is available and is a shortcut for the creation of server sockets.
</p> </p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=close> <p class=name id="close">
master:<b>close()</b><br> master:<b>close()</b><br>
client:<b>close()</b><br> client:<b>close()</b><br>
server:<b>close()</b> server:<b>close()</b>
@@ -127,37 +109,37 @@ Closes a TCP object. The internal socket used by the object is closed
and the local address to which the object was and the local address to which the object was
bound is made available to other applications. No further operations bound is made available to other applications. No further operations
(except for further calls to the <tt>close</tt> method) are allowed on (except for further calls to the <tt>close</tt> method) are allowed on
a closed socket. a closed socket.
</p> </p>
<p class=note> <p class=note>
Note: It is important to close all used sockets once they are not Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor, needed, since, in many systems, each socket uses a file descriptor,
which are limited system resources. Garbage-collected objects are which are limited system resources. Garbage-collected objects are
automatically closed before destruction, though. automatically closed before destruction, though.
</p> </p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect> <p class=name id="connect">
master:<b>connect(</b>address, port<b>)</b> master:<b>connect(</b>address, port<b>)</b>
</p> </p>
<p class=description> <p class=description>
Attempts to connect a master object to a remote host, transforming it into a Attempts to connect a master object to a remote host, transforming it into a
client object. client object.
Client objects support methods Client objects support methods
<a href=#send><tt>send</tt></a>, <a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, <a href=#receive><tt>receive</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>, <a href=#getsockname><tt>getsockname</tt></a>,
<a href=#getpeername><tt>getpeername</tt></a>, <a href=#getpeername><tt>getpeername</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>, <a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a>. and <a href=#close><tt>close</tt></a>.
</p> </p>
<p class=parameters> <p class=parameters>
<tt>Address</tt> can be an IP address or a host name. <tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [1..64K). <tt>Port</tt> must be an integer number in the range [1..64K).
</p> </p>
<p class=return> <p class=return>
@@ -166,23 +148,107 @@ describing the error. In case of success, the method returns 1.
</p> </p>
<p class=note> <p class=note>
Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
is available and is a shortcut for the creation of client sockets. is available and is a shortcut for the creation of client sockets.
</p> </p>
<p class=note> <p class=note>
Note: Starting with LuaSocket 2.0, Note: Starting with LuaSocket 2.0,
the <a href=#settimeout><tt>settimeout</tt></a> the <a href=#settimeout><tt>settimeout</tt></a>
method affects the behavior of <tt>connect</tt>, causing it to return method affects the behavior of <tt>connect</tt>, causing it to return
with an error in case of a timeout. If that happens, you can still call <a with an error in case of a timeout. If that happens, you can still call <a
href=socket.html#select><tt>socket.select</tt></a> with the socket in the href=socket.html#select><tt>socket.select</tt></a> with the socket in the
<tt>sendt</tt> table. The socket will be writable when the connection is <tt>sendt</tt> table. The socket will be writable when the connection is
established. established.
</p> </p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by
<a href=#socket.tcp><tt>socket.tcp</tt></a>,
<a href=#socket.tcp4><tt>socket.tcp4</tt></a> or
<a href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
the appropriate family (or both) are tried in the order
returned by the resolver until the
first success or until the last failure. If the timeout was
set to zero, only the first address is tried.
</p>
<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dirty">
master:<b>dirty()</b><br>
client:<b>dirty()</b><br>
server:<b>dirty()</b>
</p>
<p class=description>
Check the read buffer status.
</p>
<p class=return>
Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
</p>
<p class=note>
Note: <b>This is an internal method, use at your own risk.</b>
</p>
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getfd">
master:<b>getfd()</b><br>
client:<b>getfd()</b><br>
server:<b>getfd()</b>
</p>
<p class=description>
Returns the underling socket descriptor or handle associated to the object.
</p>
<p class=return>
The descriptor or handle. In case the object has been closed, the return will be -1.
</p>
<p class=note>
Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b>
</p>
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getoption">
client:<b>getoption(</b>option)</b><br>
server:<b>getoption(</b>option)</b>
</p>
<p class=description>
Gets options for the TCP object.
See <a href=#setoption><tt>setoption</tt></a> for description of the
option names and values.
</p>
<p class=parameters>
<tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>keepalive</tt>'
<li> '<tt>linger</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>tcp-nodelay</tt>'
</ul>
<p class=return>
The method returns the option <tt>value</tt> in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getpeername> <p class=name id="getpeername">
client:<b>getpeername()</b> client:<b>getpeername()</b>
</p> </p>
@@ -191,9 +257,10 @@ Returns information about the remote side of a connected client object.
</p> </p>
<p class=return> <p class=return>
Returns a string with the IP address of the peer, followed by the Returns a string with the IP address of the peer, the
port number that peer is using for the connection. port number that peer is using for the connection,
In case of error, the method returns <b><tt>nil</tt></b>. and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p> </p>
<p class=note> <p class=note>
@@ -202,24 +269,26 @@ Note: It makes no sense to call this method on server objects.
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getsockname> <p class=name id="getsockname">
master:<b>getsockname()</b><br> master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br> client:<b>getsockname()</b><br>
server:<b>getsockname()</b> server:<b>getsockname()</b>
</p> </p>
<p class=description> <p class=description>
Returns the local address information associated to the object. Returns the local address information associated to the object.
</p> </p>
<p class=return> <p class=return>
The method returns a string with local IP address and a number with The method returns a string with local IP address, a number with
the port. In case of error, the method returns <b><tt>nil</tt></b>. the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p> </p>
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getstats> <p class=name id="getstats">
master:<b>getstats()</b><br> master:<b>getstats()</b><br>
client:<b>getstats()</b><br> client:<b>getstats()</b><br>
server:<b>getstats()</b><br> server:<b>getstats()</b><br>
@@ -227,32 +296,46 @@ server:<b>getstats()</b><br>
<p class=description> <p class=description>
Returns accounting information on the socket, useful for throttling Returns accounting information on the socket, useful for throttling
of bandwidth. of bandwidth.
</p> </p>
<p class=return> <p class=return>
The method returns the number of bytes received, the number of bytes sent, The method returns the number of bytes received, the number of bytes sent,
and the age of the socket object in seconds. and the age of the socket object in seconds.
</p> </p>
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout">
master:<b>gettimeout()</b><br>
client:<b>gettimeout()</b><br>
server:<b>gettimeout()</b>
</p>
<p class=description>
Returns the current block timeout followed by the curent
total timeout.
</p>
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=listen> <p class=name id="listen">
master:<b>listen(</b>backlog<b>)</b> master:<b>listen(</b>backlog<b>)</b>
</p> </p>
<p class=description> <p class=description>
Specifies the socket is willing to receive connections, transforming the Specifies the socket is willing to receive connections, transforming the
object into a server object. Server objects support the object into a server object. Server objects support the
<a href=#accept><tt>accept</tt></a>, <a href=#accept><tt>accept</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>, <a href=#getsockname><tt>getsockname</tt></a>,
<a href=#setoption><tt>setoption</tt></a>, <a href=#setoption><tt>setoption</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>, <a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a> methods. and <a href=#close><tt>close</tt></a> methods.
</p> </p>
<p class=parameters> <p class=parameters>
The parameter <tt>backlog</tt> specifies the number of client The parameter <tt>backlog</tt> specifies the number of client
connections that can connections that can
be queued waiting for service. If the queue is full and another client be queued waiting for service. If the queue is full and another client
attempts connection, the connection is refused. attempts connection, the connection is refused.
@@ -265,17 +348,17 @@ method returns <b><tt>nil</tt></b> followed by an error message.
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=receive> <p class=name id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b> client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p> </p>
<p class=description> <p class=description>
Reads data from a client object, according to the specified <em>read Reads data from a client object, according to the specified <em>read
pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
</p> </p>
<p class=parameters> <p class=parameters>
<tt>Pattern</tt> can be any of the following: <tt>Pattern</tt> can be any of the following:
</p> </p>
<ul> <ul>
@@ -284,8 +367,9 @@ closed. No end-of-line translation is performed;
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is <li> '<tt>*l</tt>': reads a line of text from the socket. The line is
terminated by a LF character (ASCII&nbsp;10), optionally preceded by a terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
CR character (ASCII&nbsp;13). The CR and LF characters are not included in CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. This is the default pattern; the returned line. In fact, <em>all</em> CR characters are
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> ignored by the pattern. This is the default pattern;
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket. of bytes from the socket.
</ul> </ul>
@@ -296,26 +380,26 @@ of any received data before return.
<p class=return> <p class=return>
If successful, the method returns the received pattern. In case of error, If successful, the method returns the received pattern. In case of error,
the method returns <tt><b>nil</b></tt> followed by an error message which the method returns <tt><b>nil</b></tt> followed by an error
can be the string '<tt>closed</tt>' in case the connection was message, followed by a (possibly empty) string containing
the partial that was received. The error message can be
the string '<tt>closed</tt>' in case the connection was
closed before the transmission was completed or the string closed before the transmission was completed or the string
'<tt>timeout</tt>' in case there was a timeout during the operation. '<tt>timeout</tt>' in case there was a timeout during the operation.
Also, after the error message, the function returns the partial result of
the transmission.
</p> </p>
<p class=note> <p class=note>
<b>Important note</b>: This function was changed <em>severely</em>. It used <b>Important note</b>: This function was changed <em>severely</em>. It used
to support multiple patterns (but I have never seen this feature used) and to support multiple patterns (but I have never seen this feature used) and
now it doesn't anymore. Partial results used to be returned in the same now it doesn't anymore. Partial results used to be returned in the same
way as successful results. This last feature violated the idea that all way as successful results. This last feature violated the idea that all
functions should return <tt><b>nil</b></tt> on error. Thus it was changed functions should return <tt><b>nil</b></tt> on error. Thus it was changed
too. too.
</p> </p>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send> <p class=name id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b> client:<b>send(</b>data [, i [, j]]<b>)</b>
</p> </p>
@@ -326,7 +410,7 @@ Sends <tt>data</tt> through client object.
<p class=parameters> <p class=parameters>
<tt>Data</tt> is the string to be sent. The optional arguments <tt>Data</tt> is the string to be sent. The optional arguments
<tt>i</tt> and <tt>j</tt> work exactly like the standard <tt>i</tt> and <tt>j</tt> work exactly like the standard
<tt>string.sub</tt> Lua function to allow the selection of a <tt>string.sub</tt> Lua function to allow the selection of a
substring to be sent. substring to be sent.
</p> </p>
@@ -345,27 +429,27 @@ there was a timeout during the operation.
</p> </p>
<p class=note> <p class=note>
Note: Output is <em>not</em> buffered. For small strings, Note: Output is <em>not</em> buffered. For small strings,
it is always better to concatenate them in Lua it is always better to concatenate them in Lua
(with the '<tt>..</tt>' operator) and send the result in one call (with the '<tt>..</tt>' operator) and send the result in one call
instead of calling the method several times. instead of calling the method several times.
</p> </p>
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setoption> <p class=name id="setoption">
client:<b>setoption(</b>option [, value]<b>)</b><br> client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b> server:<b>setoption(</b>option [, value]<b>)</b>
</p> </p>
<p class=description> <p class=description>
Sets options for the TCP object. Options are only needed by low-level or Sets options for the TCP object. Options are only needed by low-level or
time-critical applications. You should only modify an option if you time-critical applications. You should only modify an option if you
are sure you need it. are sure you need it.
</p> </p>
<p class=parameters> <p class=parameters>
<tt>Option</tt> is a string with the option name, and <tt>value</tt> <tt>Option</tt> is a string with the option name, and <tt>value</tt>
depends on the option being set: depends on the option being set:
<ul> <ul>
@@ -373,7 +457,7 @@ depends on the option being set:
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables <li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
the periodic transmission of messages on a connected socket. Should the the periodic transmission of messages on a connected socket. Should the
connected party fail to respond to these messages, the connection is connected party fail to respond to these messages, the connection is
considered broken and processes using the socket are notified; considered broken and processes using the socket are notified;
<li> '<tt>linger</tt>': Controls the action taken when unsent data are <li> '<tt>linger</tt>': Controls the action taken when unsent data are
queued on a socket and a close is performed. The value is a table with a queued on a socket and a close is performed. The value is a table with a
@@ -384,19 +468,29 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will '<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
process the close in a manner that allows the process to continue as process the close in a manner that allows the process to continue as
quickly as possible. I do not advise you to set this to anything other than quickly as possible. I do not advise you to set this to anything other than
zero; zero;
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules <li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
used in validating addresses supplied in a call to used in validating addresses supplied in a call to
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses; <a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> <li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
disables the Nagle's algorithm for the connection. disables the Nagle's algorithm for the connection;
<li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!!
<li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!!
<li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!!
<li> '<tt>ipv6-v6only</tt>':
Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
sending and receiving only IPv6 packets.
</ul> </ul>
<p class=return> <p class=return>
The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise. The method returns 1 in case of success, or <b><tt>nil</tt></b>
followed by an error message otherwise.
</p> </p>
<p class=note> <p class=note>
@@ -405,7 +499,7 @@ Note: The descriptions above come from the man pages.
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setstats> <p class=name id="setstats">
master:<b>setstats(</b>received, sent, age<b>)</b><br> master:<b>setstats(</b>received, sent, age<b>)</b><br>
client:<b>setstats(</b>received, sent, age<b>)</b><br> client:<b>setstats(</b>received, sent, age<b>)</b><br>
server:<b>setstats(</b>received, sent, age<b>)</b><br> server:<b>setstats(</b>received, sent, age<b>)</b><br>
@@ -413,7 +507,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
<p class=description> <p class=description>
Resets accounting information on the socket, useful for throttling Resets accounting information on the socket, useful for throttling
of bandwidth. of bandwidth.
</p> </p>
<p class=parameters> <p class=parameters>
@@ -423,12 +517,12 @@ of bandwidth.
</p> </p>
<p class=return> <p class=return>
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p> </p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=settimeout> <p class=name id="settimeout">
master:<b>settimeout(</b>value [, mode]<b>)</b><br> master:<b>settimeout(</b>value [, mode]<b>)</b><br>
client:<b>settimeout(</b>value [, mode]<b>)</b><br> client:<b>settimeout(</b>value [, mode]<b>)</b><br>
server:<b>settimeout(</b>value [, mode]<b>)</b> server:<b>settimeout(</b>value [, mode]<b>)</b>
@@ -437,8 +531,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
<p class=description> <p class=description>
Changes the timeout values for the object. By default, Changes the timeout values for the object. By default,
all I/O operations are blocking. That is, any call to the methods all I/O operations are blocking. That is, any call to the methods
<a href=#send><tt>send</tt></a>, <a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, and <a href=#receive><tt>receive</tt></a>, and
<a href=#accept><tt>accept</tt></a> <a href=#accept><tt>accept</tt></a>
will block indefinitely, until the operation completes. The will block indefinitely, until the operation completes. The
<tt>settimeout</tt> method defines a limit on the amount of time the <tt>settimeout</tt> method defines a limit on the amount of time the
@@ -449,7 +543,7 @@ time has elapsed, the affected methods give up and fail with an error code.
<p class=parameters> <p class=parameters>
The amount of time to wait is specified as the The amount of time to wait is specified as the
<tt>value</tt> parameter, in seconds. There are two timeout modes and <tt>value</tt> parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning: both can be used together for fine tuning:
</p> </p>
<ul> <ul>
@@ -460,7 +554,7 @@ default mode;</li>
<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on <li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on
the amount of time LuaSocket can block a Lua script before returning from the amount of time LuaSocket can block a Lua script before returning from
a call.</li> a call.</li>
</ul> </ul>
<p class=parameters> <p class=parameters>
@@ -485,12 +579,12 @@ contained verbs making their imperative nature obvious.
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=shutdown> <p class=name id="shutdown">
client:<b>shutdown(</b>mode<b>)</b><br> client:<b>shutdown(</b>mode<b>)</b><br>
</p> </p>
<p class=description> <p class=description>
Shuts down part of a full-duplex connection. Shuts down part of a full-duplex connection.
</p> </p>
<p class=parameters> <p class=parameters>
@@ -507,14 +601,115 @@ This is the default mode;
This function returns 1. This function returns 1.
</p> </p>
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setfd">
master:<b>setfd(</b>fd<b>)</b><br>
client:<b>setfd(</b>fd<b>)</b><br>
server:<b>setfd(</b>fd<b>)</b>
</p>
<p class=description>
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
</p>
<p class=return>
No return value.
</p>
<p class=note>
Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b>
</p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp">
socket.<b>tcp()</b>
</p>
<p class=description>
Creates and returns an TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<p class=note>
Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#bind><tt>bind</tt></a> or <a
href=#bind><tt>connect</tt></a>, depending on the address
family obtained from the resolver.
</p>
<p class=note>
Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail.
</p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp4">
socket.<b>tcp4()</b>
</p>
<p class=description>
Creates and returns an IPv4 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp6">
socket.<b>tcp6()</b>
</p>
<p class=description>
Creates and returns an IPv6 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class=footer>
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta name="description" content="LuaSocket: The UDP support"> <meta name="description" content="LuaSocket: The UDP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support"> <meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
<title>LuaSocket: UDP support</title> <title>LuaSocket: UDP support</title>
<link rel="stylesheet" href="reference.css" type="text/css"> <link rel="stylesheet" href="reference.css" type="text/css">
</head> </head>
@@ -24,11 +24,11 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
</p> </p>
</center> </center>
<hr> <hr>
@@ -37,34 +37,7 @@
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=udp>UDP</h2> <h2 id="udp">UDP</h2>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp()</b>
</p>
<p class="description">
Creates and returns an unconnected UDP object. Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -89,6 +62,40 @@ Garbage-collected objects are automatically closed before
destruction, though. destruction, though.
</p> </p>
<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getoption">
connected:<b>getoption()</b><br>
unconnected:<b>getoption()</b>
</p>
<p class="description">
Gets an option value from the UDP object.
See <a href=#setoption><tt>setoption</tt></a> for
description of the option names and values.
</p>
<p class="parameters"><tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>dontroute</tt>'
<li> '<tt>broadcast</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>reuseport</tt>'
<li> '<tt>ip-multicast-loop</tt>'
<li> '<tt>ipv6-v6only</tt>'
<li> '<tt>ip-multicast-if</tt>'
<li> '<tt>ip-multicast-ttl</tt>'
<li> '<tt>ip-add-membership</tt>'
<li> '<tt>ip-drop-membership</tt>'
</ul>
</p>
<p class=return>
The method returns the option <tt>value</tt> in case of
success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getpeername"> <p class="name" id="getpeername">
@@ -100,8 +107,12 @@ Retrieves information about the peer
associated with a connected UDP object. associated with a connected UDP object.
</p> </p>
<p class="return">
Returns the IP address and port number of the peer. <p class=return>
Returns a string with the IP address of the peer, the
port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p> </p>
<p class="note"> <p class="note">
@@ -119,10 +130,12 @@ unconnected:<b>getsockname()</b>
Returns the local address information associated to the object. Returns the local address information associated to the object.
</p> </p>
<p class="return">
The method returns a string with local IP <p class=return>
address and a number with the port. In case of error, the method The method returns a string with local IP address, a number with
returns <b><tt>nil</tt></b>. the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p> </p>
<p class="note"> <p class="note">
@@ -133,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the
wild-card address). wild-card address).
</p> </p>
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout">
connected:<b>settimeout(</b>value<b>)</b><br>
unconnected:<b>settimeout(</b>value<b>)</b>
</p>
<p class=description>
Returns the current timeout value.
</p>
<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="receive"> <p class="name" id="receive">
@@ -153,9 +178,12 @@ specifies the maximum size of the datagram to be retrieved. If
there are more than <tt>size</tt> bytes available in the datagram, there are more than <tt>size</tt> bytes available in the datagram,
the excess bytes are discarded. If there are less then the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the <tt>size</tt> bytes available in the current datagram, the
available bytes are returned. If <tt>size</tt> is omitted, the available bytes are returned.
maximum datagram size is used (which is currently limited by the If <tt>size</tt> is omitted, the
implementation to 8192 bytes). compile-time constant <a
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
(it defaults to 8192 bytes). Larger sizes will cause a
temporary buffer to be allocated for the operation.
</p> </p>
<p class="return"> <p class="return">
@@ -171,7 +199,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
</p> </p>
<p class="description"> <p class="description">
Works exactly as the <a href="#receive"><tt>receive</tt></a> Works exactly as the <a href="#receive"><tt>receive</tt></a>
method, except it returns the IP method, except it returns the IP
address and port as extra return values (and is therefore slightly less address and port as extra return values (and is therefore slightly less
efficient). efficient).
@@ -188,7 +216,7 @@ Sends a datagram to the UDP peer of a connected object.
</p> </p>
<p class="parameters"> <p class="parameters">
<tt>Datagram</tt> is a string with the datagram contents. <tt>Datagram</tt> is a string with the datagram contents.
The maximum datagram size for UDP is 64K minus IP layer overhead. The maximum datagram size for UDP is 64K minus IP layer overhead.
However datagrams larger than the link layer packet size will be However datagrams larger than the link layer packet size will be
fragmented, which may deteriorate performance and/or reliability. fragmented, which may deteriorate performance and/or reliability.
@@ -218,11 +246,11 @@ Sends a datagram to the specified IP address and port number.
<p class="parameters"> <p class="parameters">
<tt>Datagram</tt> is a string with the <tt>Datagram</tt> is a string with the
datagram contents. datagram contents.
The maximum datagram size for UDP is 64K minus IP layer overhead. The maximum datagram size for UDP is 64K minus IP layer overhead.
However datagrams larger than the link layer packet size will be However datagrams larger than the link layer packet size will be
fragmented, which may deteriorate performance and/or reliability. fragmented, which may deteriorate performance and/or reliability.
<tt>Ip</tt> is the IP address of the recipient. <tt>Ip</tt> is the IP address of the recipient.
Host names are <em>not</em> allowed for performance reasons. Host names are <em>not</em> allowed for performance reasons.
<tt>Port</tt> is the port number at the recipient. <tt>Port</tt> is the port number at the recipient.
@@ -240,6 +268,75 @@ refuses to send a message to the specified address (i.e. no
interface accepts the address). interface accepts the address).
</p> </p>
<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setoption">
connected:<b>setoption(</b>option [, value]<b>)</b><br>
unconnected:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class="description">
Sets options for the UDP object. Options are
only needed by low-level or time-critical applications. You should
only modify an option if you are sure you need it.</p>
<p class="parameters"><tt>Option</tt> is a string with the option
name, and <tt>value</tt> depends on the option being set:
</p>
<ul>
<li> '<tt>dontroute</tt>': Indicates that outgoing
messages should bypass the standard routing facilities.
Receives a boolean value;
<li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket.
Receives a boolean value;
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
validating addresses supplied in a <tt>bind()</tt> call
should allow reuse of local addresses.
Receives a boolean value;
<li> '<tt>reuseport</tt>': Allows completely duplicate
bindings by multiple processes if they all set
'<tt>reuseport</tt>' before binding the port.
Receives a boolean value;
<li> '<tt>ip-multicast-loop</tt>':
Specifies whether or not a copy of an outgoing multicast
datagram is delivered to the sending host as long as it is a
member of the multicast group.
Receives a boolean value;
<li> '<tt>ipv6-v6only</tt>':
Specifies whether to restrict <tt>inet6</tt> sockets to
sending and receiving only IPv6 packets.
Receive a boolean value;
<li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams
are sent.
Receives an IP address;
<li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing
multicast datagrams.
Receives a number;
<li> '<tt>ip-add-membership</tt>':
Joins the multicast group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address;
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address.
</ul>
<p class="return">
The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setpeername"> <p class="name" id="setpeername">
@@ -257,9 +354,9 @@ object or vice versa.
For connected objects, outgoing datagrams For connected objects, outgoing datagrams
will be sent to the specified peer, and datagrams received from will be sent to the specified peer, and datagrams received from
other peers will be discarded by the OS. Connected UDP objects must other peers will be discarded by the OS. Connected UDP objects must
use the <a href="#send"><tt>send</tt></a> and use the <a href="#send"><tt>send</tt></a> and
<a href="#receive"><tt>receive</tt></a> methods instead of <a href="#receive"><tt>receive</tt></a> methods instead of
<a href="#sendto"><tt>sendto</tt></a> and <a href="#sendto"><tt>sendto</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>. <a href="#receivefrom"><tt>receivefrom</tt></a>.
</p> </p>
@@ -284,6 +381,15 @@ is recommended when the same peer is used for several transmissions
and can result in up to 30% performance gains. and can result in up to 30% performance gains.
</p> </p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by <a
href=#socket.udp><tt>socket.udp</tt></a> or <a
href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from
the appropriate family are tried in succession until the
first success or until the last failure.
</p>
<!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setsockname"> <p class="name" id="setsockname">
@@ -317,40 +423,6 @@ system or explicitly by <tt>setsockname</tt>, it cannot be
changed. changed.
</p> </p>
<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setoption">
connected:<b>setoption(</b>option [, value]<b>)</b><br>
unconnected:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class="description">
Sets options for the UDP object. Options are
only needed by low-level or time-critical applications. You should
only modify an option if you are sure you need it.</p>
<p class="parameters"><tt>Option</tt> is a string with the option
name, and <tt>value</tt> depends on the option being set:
</p>
<ul>
<li>'<tt>dontroute</tt>': Setting this option to <tt>true</tt>
indicates that outgoing messages should bypass the standard routing
facilities;</li>
<li>'<tt>broadcast</tt>': Setting this option to <tt>true</tt>
requests permission to send broadcast datagrams on the
socket.</li>
</ul>
<p class="return">
The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class="note">
Note: The descriptions above come from the man
pages.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="settimeout"> <p class="name" id="settimeout">
@@ -359,14 +431,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
</p> </p>
<p class="description"> <p class="description">
Changes the timeout values for the object. By default, the Changes the timeout values for the object. By default, the
<a href="#receive"><tt>receive</tt></a> and <a href="#receive"><tt>receive</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a> <a href="#receivefrom"><tt>receivefrom</tt></a>
operations are blocking. That is, any call to the methods will block operations are blocking. That is, any call to the methods will block
indefinitely, until data arrives. The <tt>settimeout</tt> function defines indefinitely, until data arrives. The <tt>settimeout</tt> function defines
a limit on the amount of time the functions can block. When a timeout is a limit on the amount of time the functions can block. When a timeout is
set and the specified amount of time has elapsed, the affected methods set and the specified amount of time has elapsed, the affected methods
give up and fail with an error code. give up and fail with an error code.
</p> </p>
<p class="parameters"> <p class="parameters">
@@ -391,17 +463,125 @@ all other method names already contained verbs making their
imperative nature obvious. imperative nature obvious.
</p> </p>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp()</b>
</p>
<p class="description">
Creates and returns an unconnected UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<p class=note>
Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#sendto><tt>sendto</tt></a>, <a
href=#setpeername><tt>setpeername</tt></a>, or <a
href=#setsockname><tt>sockname</tt></a>, depending on the address
family obtained from the resolver.
</p>
<p class=note>
Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail.
</p>
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp4()</b>
</p>
<p class="description">
Creates and returns an unconnected IPv4 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6">
socket.<b>udp6()</b>
</p>
<p class="description">
Creates and returns an unconnected IPv6 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class=footer>
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
</p> </p>
<p> <p>
<small> <small>

View File

@@ -24,8 +24,8 @@
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>
@@ -36,14 +36,13 @@
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=url>URL</h2> <h2 id="url">URL</h2>
<p> <p>
The <tt>url</tt> namespace provides functions to parse, protect, The <tt>url</tt> namespace provides functions to parse, protect,
and build URLs, as well as functions to compose absolute URLs and build URLs, as well as functions to compose absolute URLs
from base and relative URLs, according to from base and relative URLs, according to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
2396</a>.
</p> </p>
<p> <p>
@@ -70,7 +69,7 @@ An URL is defined by the following grammar:
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=absolute> <p class=name id="absolute">
url.<b>absolute(</b>base, relative<b>)</b> url.<b>absolute(</b>base, relative<b>)</b>
</p> </p>
@@ -91,7 +90,7 @@ The function returns a string with the absolute URL.
<p class=note> <p class=note>
Note: The rules that Note: The rules that
govern the composition are fairly complex, and are described in detail in govern the composition are fairly complex, and are described in detail in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC 2396</a>. <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
The example bellow should give an idea of what the rules are. The example bellow should give an idea of what the rules are.
</p> </p>
@@ -126,7 +125,7 @@ g;x?y#s = http://a/b/c/g;x?y#s
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build> <p class=name id="build">
url.<b>build(</b>parsed_url<b>)</b> url.<b>build(</b>parsed_url<b>)</b>
</p> </p>
@@ -147,7 +146,7 @@ The function returns a string with the built URL.
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build_path> <p class=name id="build_path">
url.<b>build_path(</b>segments, unsafe<b>)</b> url.<b>build_path(</b>segments, unsafe<b>)</b>
</p> </p>
@@ -201,7 +200,7 @@ code = url.escape("/#?;")
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse> <p class=name id="parse">
url.<b>parse(</b>url, default<b>)</b> url.<b>parse(</b>url, default<b>)</b>
</p> </p>
@@ -266,7 +265,7 @@ parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse_path> <p class=name id="parse_path">
url.<b>parse_path(</b>path<b>)</b> url.<b>parse_path(</b>path<b>)</b>
</p> </p>
@@ -310,8 +309,8 @@ The function returns the decoded string.
<hr> <hr>
<center> <center>
<p class=bar> <p class=bar>
<a href="home.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="home.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a> <a href="reference.html">reference</a>

View File

@@ -2,7 +2,6 @@
-- Little program to convert to and from Base64 -- Little program to convert to and from Base64
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local mime = require("mime") local mime = require("mime")

View File

@@ -3,7 +3,6 @@
-- non-blocking I/O via the dispatcher module. -- non-blocking I/O via the dispatcher module.
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local url = require("socket.url") local url = require("socket.url")
local dispatch = require("dispatch") local dispatch = require("dispatch")
@@ -12,7 +11,7 @@ dispatch.TIMEOUT = 10
-- make sure the user knows how to invoke us -- make sure the user knows how to invoke us
arg = arg or {} arg = arg or {}
if table.getn(arg) < 1 then if #arg < 1 then
print("Usage:\n luasocket check-links.lua [-n] {<url>}") print("Usage:\n luasocket check-links.lua [-n] {<url>}")
exit() exit()
end end

88
etc/cookie.lua Normal file
View File

@@ -0,0 +1,88 @@
local socket = require"socket"
local http = require"socket.http"
local url = require"socket.url"
local ltn12 = require"ltn12"
local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
local function unquote(t, quoted)
local n = string.match(t, "%$(%d+)$")
if n then n = tonumber(n) end
if quoted[n] then return quoted[n]
else return t end
end
local function parse_set_cookie(c, quoted, cookie_table)
c = c .. ";$last=last;"
local _, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=%s*(.-)%s*;%s*()")
local cookie = {
name = n,
value = unquote(v, quoted),
attributes = {}
}
while 1 do
_, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=?%s*(.-)%s*;%s*()", i)
if not n or n == "$last" then break end
cookie.attributes[#cookie.attributes+1] = {
name = n,
value = unquote(v, quoted)
}
end
cookie_table[#cookie_table+1] = cookie
end
local function split_set_cookie(s, cookie_table)
cookie_table = cookie_table or {}
-- remove quoted strings from cookie list
local quoted = {}
s = string.gsub(s, '"(.-)"', function(q)
quoted[#quoted+1] = q
return "$" .. #quoted
end)
-- add sentinel
s = s .. ",$last="
-- split into individual cookies
i = 1
while 1 do
local _, __, cookie, next_token
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
token_class .. "+)%s*=", i)
if not next_token then break end
parse_set_cookie(cookie, quoted, cookie_table)
if next_token == "$last" then break end
end
return cookie_table
end
local function quote(s)
if string.find(s, "[ %,%;]") then return '"' .. s .. '"'
else return s end
end
local _empty = {}
local function build_cookies(cookies)
s = ""
for i,v in ipairs(cookies or _empty) do
if v.name then
s = s .. v.name
if v.value and v.value ~= "" then
s = s .. '=' .. quote(v.value)
end
end
if v.name and #(v.attributes or _empty) > 0 then s = s .. "; " end
for j,u in ipairs(v.attributes or _empty) do
if u.name then
s = s .. u.name
if u.value and u.value ~= "" then
s = s .. '=' .. quote(u.value)
end
end
if j < #v.attributes then s = s .. "; " end
end
if i < #cookies then s = s .. ", " end
end
return s
end

View File

@@ -2,7 +2,6 @@
-- Little program to download DICT word definitions -- Little program to download DICT word definitions
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -44,48 +43,48 @@ function metat.__index:check(ok)
end end
function metat.__index:getdef() function metat.__index:getdef()
local line = socket.try(self.tp:receive()) local line = socket.try(self.tp:receive())
local def = {} local def = {}
while line ~= "." do while line ~= "." do
table.insert(def, line) table.insert(def, line)
line = socket.try(self.tp:receive()) line = socket.try(self.tp:receive())
end end
return table.concat(def, "\n") return table.concat(def, "\n")
end end
function metat.__index:define(database, word) function metat.__index:define(database, word)
database = database or "!" database = database or "!"
socket.try(self.tp:command("DEFINE", database .. " " .. word)) socket.try(self.tp:command("DEFINE", database .. " " .. word))
local code, count = self:check(150) local code, count = self:check(150)
local defs = {} local defs = {}
for i = 1, count do for i = 1, count do
self:check(151) self:check(151)
table.insert(defs, self:getdef()) table.insert(defs, self:getdef())
end end
self:check(250) self:check(250)
return defs return defs
end end
function metat.__index:match(database, strat, word) function metat.__index:match(database, strat, word)
database = database or "!" database = database or "!"
strat = strat or "." strat = strat or "."
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word)) socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
self:check(152) self:check(152)
local mat = {} local mat = {}
local line = socket.try(self.tp:receive()) local line = socket.try(self.tp:receive())
while line ~= '.' do while line ~= '.' do
database, word = socket.skip(2, string.find(line, "(%S+) (.*)")) database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
if not mat[database] then mat[database] = {} end if not mat[database] then mat[database] = {} end
table.insert(mat[database], word) table.insert(mat[database], word)
line = socket.try(self.tp:receive()) line = socket.try(self.tp:receive())
end end
self:check(250) self:check(250)
return mat return mat
end end
function metat.__index:quit() function metat.__index:quit()
self.tp:command("QUIT") self.tp:command("QUIT")
return self:check(221) return self:check(221)
end end
function metat.__index:close() function metat.__index:close()

View File

@@ -2,10 +2,10 @@
-- A hacked dispatcher module -- A hacked dispatcher module
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local base = _G local base = _G
local table = require("table") local table = require("table")
local string = require("string")
local socket = require("socket") local socket = require("socket")
local coroutine = require("coroutine") local coroutine = require("coroutine")
module("dispatch") module("dispatch")
@@ -44,26 +44,32 @@ end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Mega hack. Don't try to do this at home. -- Mega hack. Don't try to do this at home.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- we can't yield across calls to protect, so we rewrite it with coxpcall -- we can't yield across calls to protect on Lua 5.1, so we rewrite it with
-- coroutines
-- make sure you don't require any module that uses socket.protect before -- make sure you don't require any module that uses socket.protect before
-- loading our hack -- loading our hack
function socket.protect(f) if string.sub(base._VERSION, -3) == "5.1" then
return function(...) local function _protect(co, status, ...)
local co = coroutine.create(f) if not status then
while true do local msg = ...
local results = {coroutine.resume(co, base.unpack(arg))} if base.type(msg) == 'table' then
local status = table.remove(results, 1) return nil, msg[1]
if not status then
if type(results[1]) == 'table' then
return nil, results[1][1]
else base.error(results[1]) end
end
if coroutine.status(co) == "suspended" then
arg = {coroutine.yield(base.unpack(results))}
else else
return base.unpack(results) base.error(msg, 0)
end end
end end
if coroutine.status(co) == "suspended" then
return _protect(co, coroutine.resume(co, coroutine.yield(...)))
else
return ...
end
end
function socket.protect(f)
return function(...)
local co = coroutine.create(f)
return _protect(co, coroutine.resume(co, ...))
end
end end
end end
@@ -77,7 +83,7 @@ local function newset()
insert = function(set, value) insert = function(set, value)
if not reverse[value] then if not reverse[value] then
table.insert(set, value) table.insert(set, value)
reverse[value] = table.getn(set) reverse[value] = #set
end end
end, end,
remove = function(set, value) remove = function(set, value)
@@ -105,8 +111,7 @@ local function cowrap(dispatcher, tcp, error)
-- don't override explicitly. -- don't override explicitly.
local metat = { __index = function(table, key) local metat = { __index = function(table, key)
table[key] = function(...) table[key] = function(...)
arg[1] = tcp return tcp[key](tcp,select(2,...))
return tcp[key](base.unpack(arg))
end end
return table[key] return table[key]
end} end}

View File

@@ -2,7 +2,6 @@
-- Little program to adjust end of line markers. -- Little program to adjust end of line markers.
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local mime = require("mime") local mime = require("mime")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")

View File

@@ -3,7 +3,7 @@ local dispatch = require("dispatch")
local handler = dispatch.newhandler() local handler = dispatch.newhandler()
-- make sure the user knows how to invoke us -- make sure the user knows how to invoke us
if table.getn(arg) < 1 then if #arg < 1 then
print("Usage") print("Usage")
print(" lua forward.lua <iport:ohost:oport> ...") print(" lua forward.lua <iport:ohost:oport> ...")
os.exit(1) os.exit(1)

View File

@@ -2,7 +2,6 @@
-- Little program to download files from URLs -- Little program to download files from URLs
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
local http = require("socket.http") local http = require("socket.http")
@@ -12,53 +11,53 @@ local ltn12 = require("ltn12")
-- formats a number of seconds into human readable form -- formats a number of seconds into human readable form
function nicetime(s) function nicetime(s)
local l = "s" local l = "s"
if s > 60 then if s > 60 then
s = s / 60 s = s / 60
l = "m" l = "m"
if s > 60 then if s > 60 then
s = s / 60 s = s / 60
l = "h" l = "h"
if s > 24 then if s > 24 then
s = s / 24 s = s / 24
l = "d" -- hmmm l = "d" -- hmmm
end end
end end
end end
if l == "s" then return string.format("%5.0f%s", s, l) if l == "s" then return string.format("%5.0f%s", s, l)
else return string.format("%5.2f%s", s, l) end else return string.format("%5.2f%s", s, l) end
end end
-- formats a number of bytes into human readable form -- formats a number of bytes into human readable form
function nicesize(b) function nicesize(b)
local l = "B" local l = "B"
if b > 1024 then if b > 1024 then
b = b / 1024 b = b / 1024
l = "KB" l = "KB"
if b > 1024 then if b > 1024 then
b = b / 1024 b = b / 1024
l = "MB" l = "MB"
if b > 1024 then if b > 1024 then
b = b / 1024 b = b / 1024
l = "GB" -- hmmm l = "GB" -- hmmm
end end
end end
end end
return string.format("%7.2f%2s", b, l) return string.format("%7.2f%2s", b, l)
end end
-- returns a string with the current state of the download -- returns a string with the current state of the download
local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining" local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
local elapsed_s = "%s received, %s/s throughput, %s elapsed " local elapsed_s = "%s received, %s/s throughput, %s elapsed "
function gauge(got, delta, size) function gauge(got, delta, size)
local rate = got / delta local rate = got / delta
if size and size >= 1 then if size and size >= 1 then
return string.format(remaining_s, nicesize(got), nicesize(rate), return string.format(remaining_s, nicesize(got), nicesize(rate),
100*got/size, nicetime((size-got)/rate)) 100*got/size, nicetime((size-got)/rate))
else else
return string.format(elapsed_s, nicesize(got), return string.format(elapsed_s, nicesize(got),
nicesize(rate), nicetime(delta)) nicesize(rate), nicetime(delta))
end end
end end
-- creates a new instance of a receive_cb that saves to disk -- creates a new instance of a receive_cb that saves to disk
@@ -89,10 +88,10 @@ end
-- determines the size of a http file -- determines the size of a http file
function gethttpsize(u) function gethttpsize(u)
local r, c, h = http.request {method = "HEAD", url = u} local r, c, h = http.request {method = "HEAD", url = u}
if c == 200 then if c == 200 then
return tonumber(h["content-length"]) return tonumber(h["content-length"])
end end
end end
-- downloads a file using the http protocol -- downloads a file using the http protocol
@@ -101,7 +100,7 @@ function getbyhttp(u, file)
-- only print feedback if output is not stdout -- only print feedback if output is not stdout
if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
local r, c, h, s = http.request {url = u, sink = save } local r, c, h, s = http.request {url = u, sink = save }
if c ~= 200 then io.stderr:write(s or c, "\n") end if c ~= 200 then io.stderr:write(s or c, "\n") end
end end
-- downloads a file using the ftp protocol -- downloads a file using the ftp protocol
@@ -114,29 +113,29 @@ function getbyftp(u, file)
gett.sink = save gett.sink = save
gett.type = "i" gett.type = "i"
local ret, err = ftp.get(gett) local ret, err = ftp.get(gett)
if err then print(err) end if err then print(err) end
end end
-- determines the scheme -- determines the scheme
function getscheme(u) function getscheme(u)
-- this is an heuristic to solve a common invalid url poblem -- this is an heuristic to solve a common invalid url poblem
if not string.find(u, "//") then u = "//" .. u end if not string.find(u, "//") then u = "//" .. u end
local parsed = url.parse(u, {scheme = "http"}) local parsed = url.parse(u, {scheme = "http"})
return parsed.scheme return parsed.scheme
end end
-- gets a file either by http or ftp, saving as <name> -- gets a file either by http or ftp, saving as <name>
function get(u, name) function get(u, name)
local fout = name and io.open(name, "wb") local fout = name and io.open(name, "wb")
local scheme = getscheme(u) local scheme = getscheme(u)
if scheme == "ftp" then getbyftp(u, fout) if scheme == "ftp" then getbyftp(u, fout)
elseif scheme == "http" then getbyhttp(u, fout) elseif scheme == "http" then getbyhttp(u, fout)
else print("unknown scheme" .. scheme) end else print("unknown scheme" .. scheme) end
end end
-- main program -- main program
arg = arg or {} arg = arg or {}
if table.getn(arg) < 1 then if #arg < 1 then
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n") io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
os.exit(1) os.exit(1)
else get(arg[1], arg[2]) end else get(arg[1], arg[2]) end

View File

@@ -3,7 +3,6 @@
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: David Burgess -- Author: David Burgess
-- Modified by Diego Nehab, but David is in charge -- Modified by Diego Nehab, but David is in charge
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
--[[ --[[
if you have any questions: RFC 1179 if you have any questions: RFC 1179
@@ -268,11 +267,11 @@ send = socket.protect(function(option)
local class = string.sub(option.class or localip or localhost,1,31) local class = string.sub(option.class or localip or localhost,1,31)
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)") local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
ctlfn = string.sub(ctlfn or file,1,131) ctlfn = string.sub(ctlfn or file,1,131)
local cfile = local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n", string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost, localhost,
class, class,
option.job or "LuaSocket", option.job or "LuaSocket",
user, user,
fmt, lpfile, fmt, lpfile,
lpfile, lpfile,

View File

@@ -2,7 +2,6 @@
-- Little program to convert to and from Quoted-Printable -- Little program to convert to and from Quoted-Printable
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local mime = require("mime") local mime = require("mime")

View File

@@ -2,7 +2,6 @@
-- TFTP support for the Lua language -- TFTP support for the Lua language
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -35,18 +34,18 @@ local OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
-- Packet creation functions -- Packet creation functions
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local function RRQ(source, mode) local function RRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0) return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end end
local function WRQ(source, mode) local function WRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0) return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end end
local function ACK(block) local function ACK(block)
local low, high local low, high
low = math.mod(block, 256) low = math.mod(block, 256)
high = (block - low)/256 high = (block - low)/256
return char(0, OP_ACK, high, low) return char(0, OP_ACK, high, low)
end end
local function get_OP(dgram) local function get_OP(dgram)
@@ -58,16 +57,16 @@ end
-- Packet analysis functions -- Packet analysis functions
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local function split_DATA(dgram) local function split_DATA(dgram)
local block = byte(dgram, 3)*256 + byte(dgram, 4) local block = byte(dgram, 3)*256 + byte(dgram, 4)
local data = string.sub(dgram, 5) local data = string.sub(dgram, 5)
return block, data return block, data
end end
local function get_ERROR(dgram) local function get_ERROR(dgram)
local code = byte(dgram, 3)*256 + byte(dgram, 4) local code = byte(dgram, 3)*256 + byte(dgram, 4)
local msg local msg
_,_, msg = string.find(dgram, "(.*)\000", 5) _,_, msg = string.find(dgram, "(.*)\000", 5)
return string.format("error code %d: %s", code, msg) return string.format("error code %d: %s", code, msg)
end end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -77,40 +76,40 @@ local function tget(gett)
local retries, dgram, sent, datahost, dataport, code local retries, dgram, sent, datahost, dataport, code
local last = 0 local last = 0
socket.try(gett.host, "missing host") socket.try(gett.host, "missing host")
local con = socket.try(socket.udp()) local con = socket.try(socket.udp())
local try = socket.newtry(function() con:close() end) local try = socket.newtry(function() con:close() end)
-- convert from name to ip if needed -- convert from name to ip if needed
gett.host = try(socket.dns.toip(gett.host)) gett.host = try(socket.dns.toip(gett.host))
con:settimeout(1) con:settimeout(1)
-- first packet gives data host/port to be used for data transfers -- first packet gives data host/port to be used for data transfers
local path = string.gsub(gett.path or "", "^/", "") local path = string.gsub(gett.path or "", "^/", "")
path = url.unescape(path) path = url.unescape(path)
retries = 0 retries = 0
repeat repeat
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port)) sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
dgram, datahost, dataport = con:receivefrom() dgram, datahost, dataport = con:receivefrom()
retries = retries + 1 retries = retries + 1
until dgram or datahost ~= "timeout" or retries > 5 until dgram or datahost ~= "timeout" or retries > 5
try(dgram, datahost) try(dgram, datahost)
-- associate socket with data host/port -- associate socket with data host/port
try(con:setpeername(datahost, dataport)) try(con:setpeername(datahost, dataport))
-- default sink -- default sink
local sink = gett.sink or ltn12.sink.null() local sink = gett.sink or ltn12.sink.null()
-- process all data packets -- process all data packets
while 1 do while 1 do
-- decode packet -- decode packet
code = get_OP(dgram) code = get_OP(dgram)
try(code ~= OP_ERROR, get_ERROR(dgram)) try(code ~= OP_ERROR, get_ERROR(dgram))
try(code == OP_DATA, "unhandled opcode " .. code) try(code == OP_DATA, "unhandled opcode " .. code)
-- get data packet parts -- get data packet parts
local block, data = split_DATA(dgram) local block, data = split_DATA(dgram)
-- if not repeated, write -- if not repeated, write
if block == last+1 then if block == last+1 then
try(sink(data)) try(sink(data))
last = block last = block
end end
-- last packet brings less than 512 bytes of data -- last packet brings less than 512 bytes of data
if string.len(data) < 512 then if string.len(data) < 512 then
try(con:send(ACK(block))) try(con:send(ACK(block)))
try(con:close()) try(con:close())
try(sink(nil)) try(sink(nil))
@@ -118,13 +117,13 @@ local function tget(gett)
end end
-- get the next packet -- get the next packet
retries = 0 retries = 0
repeat repeat
sent = try(con:send(ACK(last))) sent = try(con:send(ACK(last)))
dgram, err = con:receive() dgram, err = con:receive()
retries = retries + 1 retries = retries + 1
until dgram or err ~= "timeout" or retries > 5 until dgram or err ~= "timeout" or retries > 5
try(dgram, err) try(dgram, err)
end end
end end
local default = { local default = {

View File

@@ -1,2 +0,0 @@
Talk a bout Wim
Move thanks into the acknowledgement section.

View File

@@ -6,7 +6,10 @@
\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%} \DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}} \newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}} \newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
\newcommand{\CR}{\texttt{CR}}
\newcommand{\LF}{\texttt{LF}}
\newcommand{\CRLF}{\texttt{CR~LF}}
\newcommand{\nil}{\texttt{nil}}
\title{Filters, sources, sinks, and pumps\\ \title{Filters, sources, sinks, and pumps\\
{\large or Functional programming for the rest of us}} {\large or Functional programming for the rest of us}}
@@ -17,30 +20,31 @@
\maketitle \maketitle
\begin{abstract} \begin{abstract}
Certain data processing operations can be implemented in the Certain data processing operations can be implemented in the
form of filters. A filter is a function that can process data form of filters. A filter is a function that can process
received in consecutive function calls, returning partial data received in consecutive invocations, returning partial
results after each invocation. Examples of operations that can be results each time it is called. Examples of operations that
implemented as filters include the end-of-line normalization can be implemented as filters include the end-of-line
for text, Base64 and Quoted-Printable transfer content normalization for text, Base64 and Quoted-Printable transfer
encodings, the breaking of text into lines, SMTP dot-stuffing, content encodings, the breaking of text into lines, SMTP
and there are many others. Filters become even dot-stuffing, and there are many others. Filters become
more powerful when we allow them to be chained together to even more powerful when we allow them to be chained together
create composite filters. In this context, filters can be seen to create composite filters. In this context, filters can be
as the middle links in a chain of data transformations. Sources an sinks seen as the internal links in a chain of data transformations.
are the corresponding end points of these chains. A source Sources and sinks are the corresponding end points in these
is a function that produces data, chunk by chunk, and a sink chains. A source is a function that produces data, chunk by
is a function that takes data, chunk by chunk. In this chunk, and a sink is a function that takes data, chunk by
article, we describe the design of an elegant interface for filters, chunk. Finally, pumps are procedures that actively drive
sources, sinks, and chaining, and illustrate each step data from a source to a sink, and indirectly through all
with concrete examples. intervening filters. In this article, we describe the design of an
elegant interface for filters, sources, sinks, chains, and
pumps, and we illustrate each step with concrete examples.
\end{abstract} \end{abstract}
\section{Introduction} \section{Introduction}
Within the realm of networking applications, we are often Within the realm of networking applications, we are often
required apply transformations to streams of data. Examples required to apply transformations to streams of data. Examples
include the end-of-line normalization for text, Base64 and include the end-of-line normalization for text, Base64 and
Quoted-Printable transfer content encodings, breaking text Quoted-Printable transfer content encodings, breaking text
into lines with a maximum number of columns, SMTP into lines with a maximum number of columns, SMTP
@@ -50,38 +54,37 @@ transfer coding, and the list goes on.
Many complex tasks require a combination of two or more such Many complex tasks require a combination of two or more such
transformations, and therefore a general mechanism for transformations, and therefore a general mechanism for
promoting reuse is desirable. In the process of designing promoting reuse is desirable. In the process of designing
\texttt{LuaSocket~2.0}, David Burgess and I were forced to deal with \texttt{LuaSocket~2.0}, we repeatedly faced this problem.
this problem. The solution we reached proved to be very The solution we reached proved to be very general and
general and convenient. It is based on the concepts of convenient. It is based on the concepts of filters, sources,
filters, sources, sinks, and pumps, which we introduce sinks, and pumps, which we introduce below.
below.
\emph{Filters} are functions that can be repeatedly invoked \emph{Filters} are functions that can be repeatedly invoked
with chunks of input, successively returning processed with chunks of input, successively returning processed
chunks of output. More importantly, the result of chunks of output. Naturally, the result of
concatenating all the output chunks must be the same as the concatenating all the output chunks must be the same as the
result of applying the filter to the concatenation of all result of applying the filter to the concatenation of all
input chunks. In fancier language, filters \emph{commute} input chunks. In fancier language, filters \emph{commute}
with the concatenation operator. As a result, chunk with the concatenation operator. More importantly, filters
boundaries are irrelevant: filters correctly handle input must handle input data correctly no matter how the stream
data no matter how it is split. has been split into chunks.
A \emph{chain} transparently combines the effect of one or A \emph{chain} is a function that transparently combines the
more filters. The interface of a chain is effect of one or more filters. The interface of a chain is
indistinguishable from the interface of its components. indistinguishable from the interface of its component
This allows a chained filter to be used wherever an atomic filters. This allows a chained filter to be used wherever
filter is expected. In particular, chains can be an atomic filter is accepted. In particular, chains can be
themselves chained to create arbitrarily complex operations. themselves chained to create arbitrarily complex operations.
Filters can be seen as internal nodes in a network through Filters can be seen as internal nodes in a network through
which data will flow, potentially being transformed many which data will flow, potentially being transformed many
times along its way. Chains connect these nodes together. times along the way. Chains connect these nodes together.
To complete the picture, we need \emph{sources} and The initial and final nodes of the network are
\emph{sinks}. These are the initial and final nodes of the \emph{sources} and \emph{sinks}, respectively. Less
network, respectively. Less abstractly, a source is a abstractly, a source is a function that produces new chunks
function that produces new data every time it is called. of data every time it is invoked. Conversely, sinks are
Conversely, sinks are functions that give a final functions that give a final destination to the chunks of
destination to the data they receive. Naturally, sources data they receive in sucessive calls. Naturally, sources
and sinks can also be chained with filters to produce and sinks can also be chained with filters to produce
filtered sources and sinks. filtered sources and sinks.
@@ -89,37 +92,38 @@ Finally, filters, chains, sources, and sinks are all passive
entities: they must be repeatedly invoked in order for entities: they must be repeatedly invoked in order for
anything to happen. \emph{Pumps} provide the driving force anything to happen. \emph{Pumps} provide the driving force
that pushes data through the network, from a source to a that pushes data through the network, from a source to a
sink. sink, and indirectly through all intervening filters.
In the following sections, we start with a simplified In the following sections, we start with a simplified
interface, which we later refine. The evolution we present interface, which we later refine. The evolution we present
is not contrived: it recreates the steps we followed is not contrived: it recreates the steps we ourselves
ourselves as we consolidated our understanding of these followed as we consolidated our understanding of these
concepts within our application domain. concepts within our application domain.
\subsection{A simple example} \subsection{A simple example}
Let us use the end-of-line normalization of text as an The end-of-line normalization of text is a good
example to motivate our initial filter interface. example to motivate our initial filter interface.
Assume we are given text in an unknown end-of-line Assume we are given text in an unknown end-of-line
convention (including possibly mixed conventions) out of the convention (including possibly mixed conventions) out of the
commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) commonly found Unix (\LF), Mac OS (\CR), and
conventions. We would like to be able to write code like the DOS (\CRLF) conventions. We would like to be able to
following: use the folowing code to normalize the end-of-line markers:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
local in = source.chain(source.file(io.stdin), normalize("\r\n")) local CRLF = "\013\010"
local out = sink.file(io.stdout) local input = source.chain(source.file(io.stdin), normalize(CRLF))
pump.all(in, out) local output = sink.file(io.stdout)
pump.all(input, output)
% %
\end{lua} \end{lua}
\end{quote} \end{quote}
This program should read data from the standard input stream This program should read data from the standard input stream
and normalize the end-of-line markers to the canonic CRLF and normalize the end-of-line markers to the canonic
marker, as defined by the MIME standard. Finally, the \CRLF\ marker, as defined by the MIME standard.
normalized text should be sent to the standard output Finally, the normalized text should be sent to the standard output
stream. We use a \emph{file source} that produces data from stream. We use a \emph{file source} that produces data from
standard input, and chain it with a filter that normalizes standard input, and chain it with a filter that normalizes
the data. The pump then repeatedly obtains data from the the data. The pump then repeatedly obtains data from the
@@ -127,27 +131,28 @@ source, and passes it to the \emph{file sink}, which sends
it to the standard output. it to the standard output.
In the code above, the \texttt{normalize} \emph{factory} is a In the code above, the \texttt{normalize} \emph{factory} is a
function that creates our normalization filter. This filter function that creates our normalization filter, which
will replace any end-of-line marker with the canonic replaces any end-of-line marker with the canonic marker.
`\verb|\r\n|' marker. The initial filter interface is The initial filter interface is
trivial: a filter function receives a chunk of input data, trivial: a filter function receives a chunk of input data,
and returns a chunk of processed data. When there are no and returns a chunk of processed data. When there are no
more input data left, the caller notifies the filter by invoking more input data left, the caller notifies the filter by invoking
it with a \texttt{nil} chunk. The filter responds by returning it with a \nil\ chunk. The filter responds by returning
the final chunk of processed data. the final chunk of processed data (which could of course be
the empty string).
Although the interface is extremely simple, the Although the interface is extremely simple, the
implementation is not so obvious. A normalization filter implementation is not so obvious. A normalization filter
respecting this interface needs to keep some kind of context respecting this interface needs to keep some kind of context
between calls. This is because a chunk boundary may lie between between calls. This is because a chunk boundary may lie between
the CR and LF characters marking the end of a line. This the \CR\ and \LF\ characters marking the end of a single line. This
need for contextual storage motivates the use of need for contextual storage motivates the use of
factories: each time the factory is invoked, it returns a factories: each time the factory is invoked, it returns a
filter with its own context so that we can have several filter with its own context so that we can have several
independent filters being used at the same time. For independent filters being used at the same time. For
efficiency reasons, we must avoid the obvious solution of efficiency reasons, we must avoid the obvious solution of
concatenating all the input into the context before concatenating all the input into the context before
producing any output. producing any output chunks.
To that end, we break the implementation into two parts: To that end, we break the implementation into two parts:
a low-level filter, and a factory of high-level filters. The a low-level filter, and a factory of high-level filters. The
@@ -167,10 +172,10 @@ end-of-line normalization filters:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
function filter.cycle(low, ctx, extra) function filter.cycle(lowlevel, context, extra)
return function(chunk) return function(chunk)
local ret local ret
ret, ctx = low(ctx, chunk, extra) ret, context = lowlevel(context, chunk, extra)
return ret return ret
end end
end end
@@ -178,27 +183,30 @@ end
@stick# @stick#
function normalize(marker) function normalize(marker)
return cycle(eol, 0, marker) return filter.cycle(eol, 0, marker)
end end
% %
\end{lua} \end{lua}
\end{quote} \end{quote}
The \texttt{normalize} factory simply calls a more generic The \texttt{normalize} factory simply calls a more generic
factory, the \texttt{cycle} factory. This factory receives a factory, the \texttt{cycle}~factory, passing the low-level
filter~\texttt{eol}. The \texttt{cycle}~factory receives a
low-level filter, an initial context, and an extra low-level filter, an initial context, and an extra
parameter, and returns a new high-level filter. Each time parameter, and returns a new high-level filter. Each time
the high-level filer is passed a new chunk, it invokes the the high-level filer is passed a new chunk, it invokes the
low-level filter with the previous context, the new chunk, low-level filter with the previous context, the new chunk,
and the extra argument. It is the low-level filter that and the extra argument. It is the low-level filter that
does all the work, producing the chunk of processed data and does all the work, producing the chunk of processed data and
a new context. The high-level filter then updates its a new context. The high-level filter then replaces its
internal context, and returns the processed chunk of data to internal context, and returns the processed chunk of data to
the user. Notice that we take advantage of Lua's lexical the user. Notice that we take advantage of Lua's lexical
scoping to store the context in a closure between function scoping to store the context in a closure between function
calls. calls.
Concerning the low-level filter code, we must first accept \subsection{The C part of the filter}
As for the low-level filter, we must first accept
that there is no perfect solution to the end-of-line marker that there is no perfect solution to the end-of-line marker
normalization problem. The difficulty comes from an normalization problem. The difficulty comes from an
inherent ambiguity in the definition of empty lines within inherent ambiguity in the definition of empty lines within
@@ -208,39 +216,39 @@ mixed input. It also does a reasonable job with empty lines
and serves as a good example of how to implement a low-level and serves as a good example of how to implement a low-level
filter. filter.
The idea is to consider both CR and~LF as end-of-line The idea is to consider both \CR\ and~\LF\ as end-of-line
\emph{candidates}. We issue a single break if any candidate \emph{candidates}. We issue a single break if any candidate
is seen alone, or followed by a different candidate. In is seen alone, or if it is followed by a different
other words, CR~CR~and LF~LF each issue two end-of-line candidate. In other words, \CR~\CR~and \LF~\LF\ each issue
markers, whereas CR~LF~and LF~CR issue only one marker each. two end-of-line markers, whereas \CR~\LF~and \LF~\CR\ issue
This method correctly handles the Unix, DOS/MIME, VMS, and Mac only one marker each. It is easy to see that this method
OS conventions. correctly handles the most common end-of-line conventions.
\subsection{The C part of the filter} With this in mind, we divide the low-level filter into two
simple functions. The inner function~\texttt{pushchar} performs the
Our low-level filter is divided into two simple functions. normalization itself. It takes each input character in turn,
The inner function performs the normalization itself. It takes deciding what to output and how to modify the context. The
each input character in turn, deciding what to output and context tells if the last processed character was an
how to modify the context. The context tells if the last end-of-line candidate, and if so, which candidate it was.
processed character was an end-of-line candidate, and if so, For efficiency, we use Lua's auxiliary library's buffer
which candidate it was. For efficiency, it uses interface:
Lua's auxiliary library's buffer interface:
\begin{quote} \begin{quote}
\begin{C} \begin{C}
@stick# @stick#
@#define candidate(c) (c == CR || c == LF) @#define candidate(c) (c == CR || c == LF)
static int process(int c, int last, const char *marker, static int pushchar(int c, int last, const char *marker,
luaL_Buffer *buffer) { luaL_Buffer *buffer) {
if (candidate(c)) { if (candidate(c)) {
if (candidate(last)) { if (candidate(last)) {
if (c == last) luaL_addstring(buffer, marker); if (c == last)
luaL_addstring(buffer, marker);
return 0; return 0;
} else { } else {
luaL_addstring(buffer, marker); luaL_addstring(buffer, marker);
return c; return c;
} }
} else { } else {
luaL_putchar(buffer, c); luaL_pushchar(buffer, c);
return 0; return 0;
} }
} }
@@ -248,15 +256,20 @@ static int process(int c, int last, const char *marker,
\end{C} \end{C}
\end{quote} \end{quote}
The outer function simply interfaces with Lua. It receives the The outer function~\texttt{eol} simply interfaces with Lua.
context and input chunk (as well as an optional It receives the context and input chunk (as well as an
custom end-of-line marker), and returns the transformed optional custom end-of-line marker), and returns the
output chunk and the new context: transformed output chunk and the new context.
Notice that if the input chunk is \nil, the operation
is considered to be finished. In that case, the loop will
not execute a single time and the context is reset to the
initial state. This allows the filter to be reused many
times:
\begin{quote} \begin{quote}
\begin{C} \begin{C}
@stick# @stick#
static int eol(lua_State *L) { static int eol(lua_State *L) {
int ctx = luaL_checkint(L, 1); int context = luaL_checkint(L, 1);
size_t isize = 0; size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize); const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize; const char *last = input + isize;
@@ -269,24 +282,18 @@ static int eol(lua_State *L) {
return 2; return 2;
} }
while (input < last) while (input < last)
ctx = process(*input++, ctx, marker, &buffer); context = pushchar(*input++, context, marker, &buffer);
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
lua_pushnumber(L, ctx); lua_pushnumber(L, context);
return 2; return 2;
} }
% %
\end{C} \end{C}
\end{quote} \end{quote}
Notice that if the input chunk is \texttt{nil}, the operation When designing filters, the challenging part is usually
is considered to be finished. In that case, the loop will deciding what to store in the context. For line breaking, for
not execute a single time and the context is reset to the instance, it could be the number of bytes that still fit in the
initial state. This allows the filter to be reused many
times.
When designing your own filters, the challenging part is to
decide what will be in the context. For line breaking, for
instance, it could be the number of bytes left in the
current line. For Base64 encoding, it could be a string current line. For Base64 encoding, it could be a string
with the bytes that remain after the division of the input with the bytes that remain after the division of the input
into 3-byte atoms. The MIME module in the \texttt{LuaSocket} into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
@@ -294,19 +301,22 @@ distribution has many other examples.
\section{Filter chains} \section{Filter chains}
Chains add a lot to the power of filters. For example, Chains greatly increase the power of filters. For example,
according to the standard for Quoted-Printable encoding, according to the standard for Quoted-Printable encoding,
text must be normalized to a canonic end-of-line marker text should be normalized to a canonic end-of-line marker
prior to encoding. To help specifying complex prior to encoding. After encoding, the resulting text must
transformations like this, we define a chain factory that be broken into lines of no more than 76 characters, with the
creates a composite filter from one or more filters. A use of soft line breaks (a line terminated by the \texttt{=}
chained filter passes data through all its components, and sign). To help specifying complex transformations like
can be used wherever a primitive filter is accepted. this, we define a chain factory that creates a composite
filter from one or more filters. A chained filter passes
data through all its components, and can be used wherever a
primitive filter is accepted.
The chaining factory is very simple. The auxiliary The chaining factory is very simple. The auxiliary
function~\texttt{chainpair} chains two filters together, function~\texttt{chainpair} chains two filters together,
taking special care if the chunk is the last. This is taking special care if the chunk is the last. This is
because the final \texttt{nil} chunk notification has to be because the final \nil\ chunk notification has to be
pushed through both filters in turn: pushed through both filters in turn:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@@ -322,9 +332,9 @@ end
@stick# @stick#
function filter.chain(...) function filter.chain(...)
local f = arg[1] local f = select(1, ...)
for i = 2, @#arg do for i = 2, select('@#', ...) do
f = chainpair(f, arg[i]) f = chainpair(f, select(i, ...))
end end
return f return f
end end
@@ -337,11 +347,11 @@ define the Quoted-Printable conversion as such:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
local qp = filter.chain(normalize("\r\n"), local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
encode("quoted-printable")) wrap("quoted-printable"))
local in = source.chain(source.file(io.stdin), qp) local input = source.chain(source.file(io.stdin), qp)
local out = sink.file(io.stdout) local output = sink.file(io.stdout)
pump.all(in, out) pump.all(input, output)
% %
\end{lua} \end{lua}
\end{quote} \end{quote}
@@ -360,14 +370,14 @@ gives a final destination to the data.
\subsection{Sources} \subsection{Sources}
A source returns the next chunk of data each time it is A source returns the next chunk of data each time it is
invoked. When there is no more data, it simply returns invoked. When there is no more data, it simply returns~\nil.
\texttt{nil}. In the event of an error, the source can inform the In the event of an error, the source can inform the
caller by returning \texttt{nil} followed by an error message. caller by returning \nil\ followed by the error message.
Below are two simple source factories. The \texttt{empty} source Below are two simple source factories. The \texttt{empty} source
returns no data, possibly returning an associated error returns no data, possibly returning an associated error
message. The \texttt{file} source works harder, and message. The \texttt{file} source yields the contents of a file
yields the contents of a file in a chunk by chunk fashion: in a chunk by chunk fashion:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
@@ -398,22 +408,26 @@ A filtered source passes its data through the
associated filter before returning it to the caller. associated filter before returning it to the caller.
Filtered sources are useful when working with Filtered sources are useful when working with
functions that get their input data from a source (such as functions that get their input data from a source (such as
the pump in our first example). By chaining a source with one or the pumps in our examples). By chaining a source with one or
more filters, the function can be transparently provided more filters, such functions can be transparently provided
with filtered data, with no need to change its interface. with filtered data, with no need to change their interfaces.
Here is a factory that does the job: Here is a factory that does the job:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
function source.chain(src, f) function source.chain(src, f)
return source.simplify(function() return function()
if not src then return nil end if not src then
return nil
end
local chunk, err = src() local chunk, err = src()
if not chunk then if not chunk then
src = nil src = nil
return f(nil) return f(nil)
else return f(chunk) end else
end) return f(chunk)
end
end
end end
% %
\end{lua} \end{lua}
@@ -421,20 +435,20 @@ end
\subsection{Sinks} \subsection{Sinks}
Just as we defined an interface a data source, Just as we defined an interface for a source of data, we can
we can also define an interface for a data destination. also define an interface for a data destination. We call
We call any function respecting this any function respecting this interface a sink. In our first
interface a \emph{sink}. In our first example, we used a example, we used a file sink connected to the standard
file sink connected to the standard output. output.
Sinks receive consecutive chunks of data, until the end of Sinks receive consecutive chunks of data, until the end of
data is signaled by a \texttt{nil} chunk. A sink can be data is signaled by a \nil\ input chunk. A sink can be
notified of an error with an optional extra argument that notified of an error with an optional extra argument that
contains the error message, following a \texttt{nil} chunk. contains the error message, following a \nil\ chunk.
If a sink detects an error itself, and If a sink detects an error itself, and
wishes not to be called again, it can return \texttt{nil}, wishes not to be called again, it can return \nil,
followed by an error message. A return value that followed by an error message. A return value that
is not \texttt{nil} means the source will accept more data. is not \nil\ means the sink will accept more data.
Below are two useful sink factories. Below are two useful sink factories.
The table factory creates a sink that stores The table factory creates a sink that stores
@@ -469,7 +483,7 @@ end
Naturally, filtered sinks are just as useful as filtered Naturally, filtered sinks are just as useful as filtered
sources. A filtered sink passes each chunk it receives sources. A filtered sink passes each chunk it receives
through the associated filter before handing it to the through the associated filter before handing it down to the
original sink. In the following example, we use a source original sink. In the following example, we use a source
that reads from the standard input. The input chunks are that reads from the standard input. The input chunks are
sent to a table sink, which has been coupled with a sent to a table sink, which has been coupled with a
@@ -479,10 +493,10 @@ standard out:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
local in = source.file(io.stdin) local input = source.file(io.stdin)
local out, t = sink.table() local output, t = sink.table()
out = sink.chain(normalize("\r\n"), out) output = sink.chain(normalize(CRLF), output)
pump.all(in, out) pump.all(input, output)
io.write(table.concat(t)) io.write(table.concat(t))
% %
\end{lua} \end{lua}
@@ -490,11 +504,11 @@ io.write(table.concat(t))
\subsection{Pumps} \subsection{Pumps}
Adrian Sietsma noticed that, although not on purpose, our Although not on purpose, our interface for sources is
interface for sources is compatible with Lua iterators. compatible with Lua iterators. That is, a source can be
That is, a source can be neatly used in conjunction neatly used in conjunction with \texttt{for} loops. Using
with \texttt{for} loops. Using our file our file source as an iterator, we can write the following
source as an iterator, we can write the following code: code:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
@@ -539,20 +553,22 @@ end
The \texttt{pump.step} function moves one chunk of data from The \texttt{pump.step} function moves one chunk of data from
the source to the sink. The \texttt{pump.all} function takes the source to the sink. The \texttt{pump.all} function takes
an optional \texttt{step} function and uses it to pump all the an optional \texttt{step} function and uses it to pump all the
data from the source to the sink. We can now use everything data from the source to the sink.
we have to write a program that reads a binary file from Here is an example that uses the Base64 and the
line wrapping filters from the \texttt{LuaSocket}
distribution. The program reads a binary file from
disk and stores it in another file, after encoding it to the disk and stores it in another file, after encoding it to the
Base64 transfer content encoding: Base64 transfer content encoding:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@stick# @stick#
local in = source.chain( local input = source.chain(
source.file(io.open("input.bin", "rb")), source.file(io.open("input.bin", "rb")),
encode("base64")) encode("base64"))
local out = sink.chain( local output = sink.chain(
wrap(76), wrap(76),
sink.file(io.open("output.b64", "w"))) sink.file(io.open("output.b64", "w")))
pump.all(in, out) pump.all(input, output)
% %
\end{lua} \end{lua}
\end{quote} \end{quote}
@@ -561,19 +577,17 @@ The way we split the filters here is not intuitive, on
purpose. Alternatively, we could have chained the Base64 purpose. Alternatively, we could have chained the Base64
encode filter and the line-wrap filter together, and then encode filter and the line-wrap filter together, and then
chain the resulting filter with either the file source or chain the resulting filter with either the file source or
the file sink. It doesn't really matter. The Base64 and the the file sink. It doesn't really matter.
line wrapping filters are part of the \texttt{LuaSocket}
distribution.
\section{Exploding filters} \section{Exploding filters}
Our current filter interface has one flagrant shortcoming. Our current filter interface has one serious shortcoming.
When David Burgess was writing his \texttt{gzip} filter, he Consider for example a \texttt{gzip} decompression filter.
noticed that a decompression filter can explode a small During decompression, a small input chunk can be exploded
input chunk into a huge amount of data. To address this into a huge amount of data. To address this problem, we
problem, we decided to change the filter interface and allow decided to change the filter interface and allow exploding
exploding filters to return large quantities of output data filters to return large quantities of output data in a chunk
in a chunk by chunk manner. by chunk manner.
More specifically, after passing each chunk of input to More specifically, after passing each chunk of input to
a filter, and collecting the first chunk of output, the a filter, and collecting the first chunk of output, the
@@ -582,11 +596,11 @@ filtered data is left. Within these secondary calls, the
caller passes an empty string to the filter. The filter caller passes an empty string to the filter. The filter
responds with an empty string when it is ready for the next responds with an empty string when it is ready for the next
input chunk. In the end, after the user passes a input chunk. In the end, after the user passes a
\texttt{nil} chunk notifying the filter that there is no \nil\ chunk notifying the filter that there is no
more input data, the filter might still have to produce too more input data, the filter might still have to produce too
much output data to return in a single chunk. The user has much output data to return in a single chunk. The user has
to loop again, now passing \texttt{nil} to the filter each time, to loop again, now passing \nil\ to the filter each time,
until the filter itself returns \texttt{nil} to notify the until the filter itself returns \nil\ to notify the
user it is finally done. user it is finally done.
Fortunately, it is very easy to modify a filter to respect Fortunately, it is very easy to modify a filter to respect
@@ -599,13 +613,13 @@ Interestingly, the modifications do not have a measurable
negative impact in the performance of filters that do negative impact in the performance of filters that do
not need the added flexibility. On the other hand, for a not need the added flexibility. On the other hand, for a
small price in complexity, the changes make exploding small price in complexity, the changes make exploding
filters practical. filters practical.
\section{A complex example} \section{A complex example}
The LTN12 module in the \texttt{LuaSocket} distribution The LTN12 module in the \texttt{LuaSocket} distribution
implements the ideas we have described. The MIME implements all the ideas we have described. The MIME
and SMTP modules are especially integrated with LTN12, and SMTP modules are tightly integrated with LTN12,
and can be used to showcase the expressive power of filters, and can be used to showcase the expressive power of filters,
sources, sinks, and pumps. Below is an example sources, sinks, and pumps. Below is an example
of how a user would proceed to define and send a of how a user would proceed to define and send a
@@ -622,9 +636,9 @@ local message = smtp.message{
to = "Fulano <fulano@example.com>", to = "Fulano <fulano@example.com>",
subject = "A message with an attachment"}, subject = "A message with an attachment"},
body = { body = {
preamble = "Hope you can see the attachment\r\n", preamble = "Hope you can see the attachment" .. CRLF,
[1] = { [1] = {
body = "Here is our logo\r\n"}, body = "Here is our logo" .. CRLF},
[2] = { [2] = {
headers = { headers = {
["content-type"] = 'image/png; name="luasocket.png"', ["content-type"] = 'image/png; name="luasocket.png"',
@@ -652,7 +666,7 @@ SMTP dot-stuffing filter, connects a socket sink
with the server, and simply pumps the data. The message is never with the server, and simply pumps the data. The message is never
assembled in memory. Everything is produced on demand, assembled in memory. Everything is produced on demand,
transformed in small pieces, and sent to the server in chunks, transformed in small pieces, and sent to the server in chunks,
including the file attachment that is loaded from disk and including the file attachment which is loaded from disk and
encoded on the fly. It just works. encoded on the fly. It just works.
\section{Conclusions} \section{Conclusions}
@@ -665,6 +679,17 @@ abstraction for final data destinations. Filters define an
interface for data transformations. The chaining of interface for data transformations. The chaining of
filters, sources and sinks provides an elegant way to create filters, sources and sinks provides an elegant way to create
arbitrarily complex data transformations from simpler arbitrarily complex data transformations from simpler
components. Pumps simply move the data through. components. Pumps simply push the data through.
\section{Acknowledgements}
The concepts described in this text are the result of long
discussions with David Burgess. A version of this text has
been released on-line as the Lua Technical Note 012, hence
the name of the corresponding LuaSocket module, LTN12. Wim
Couwenberg contributed to the implementation of the module,
and Adrian Sietsma was the first to notice the
correspondence between sources and Lua iterators.
\end{document} \end{document}

1
linux.cmd Normal file
View File

@@ -0,0 +1 @@
make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/ubuntu/include LUAPREFIX_linux=/home/diego/build/ubuntu

View File

@@ -126,8 +126,9 @@ local function chain2(f1, f2)
end end
function filter.chain(...) function filter.chain(...)
local arg = {...}
local f = arg[1] local f = arg[1]
for i = 2, table.getn(arg) do for i = 2, #arg do
f = chain2(f, arg[i]) f = chain2(f, arg[i])
end end
return f return f
@@ -235,9 +236,10 @@ end
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead. We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
{{{ {{{
function source.cat(...) function source.cat(...)
local arg = {...}
local co = coroutine.create(function() local co = coroutine.create(function()
local i = 1 local i = 1
while i <= table.getn(arg) do while i <= #arg do
local chunk, err = arg[i]() local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk) if chunk then coroutine.yield(chunk)
elseif err then return nil, err elseif err then return nil, err

View File

@@ -73,12 +73,12 @@ Fortunately, all these problems are very easy to solve and that's what we do in
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job: We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
{{{ {{{
local function pack(ok, ...) local function pack(ok, ...)
return ok, arg return ok, {...}
end end
function protect(f) function protect(f)
return function(...) return function(...)
local ok, ret = pack(pcall(f, unpack(arg))) local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret) if ok then return unpack(ret)
else return nil, ret[1] end else return nil, ret[1] end
end end
@@ -157,7 +157,7 @@ function newtry(f)
if f then f() end if f then f() end
error(arg[2], 0) error(arg[2], 0)
else else
return unpack(arg) return ...
end end
end end
end end

View File

@@ -1,37 +1,35 @@
Microsoft Visual Studio Solution File, Format Version 8.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}" # Visual Studio 2012
ProjectSection(ProjectDependencies) = postProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcxproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcxproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libluasocket", "libluasocket.vcproj", "{599EAD40-60EE-4043-9C14-AE090A8A092D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfiguration) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug = Debug Debug|Win32 = Debug|Win32
Release = Release Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.ActiveCfg = Debug|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.ActiveCfg = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.Build.0 = Debug|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.Build.0 = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.ActiveCfg = Release|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.ActiveCfg = Debug|x64
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.Build.0 = Release|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.Build.0 = Debug|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.ActiveCfg = Debug|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.ActiveCfg = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.Build.0 = Debug|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.Build.0 = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.ActiveCfg = Release|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.ActiveCfg = Release|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.Build.0 = Release|Win32 {66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.Build.0 = Release|x64
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.ActiveCfg = Debug|Win32 {128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.ActiveCfg = Debug|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.Build.0 = Debug|Win32 {128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.Build.0 = Debug|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.ActiveCfg = Release|Win32 {128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.ActiveCfg = Debug|x64
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.Build.0 = Release|Win32 {128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.Build.0 = Debug|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.ActiveCfg = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.Build.0 = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.ActiveCfg = Release|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(SolutionProperties) = preSolution
EndGlobalSection HideSolutionNode = FALSE
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

1
macosx.cmd Normal file
View File

@@ -0,0 +1 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/$USER/build/macosx/include LUAPREFIX_macosx=/Users/$USER/build/macosx install-both

84
makefile Normal file → Executable file
View File

@@ -1,51 +1,49 @@
#------ # luasocket makefile
# Load configuration
# #
include config # see src/makefile for description of how to customize the build
#------
# Hopefully no need to change anything below this line
# #
INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket # Targets:
INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket # install install system independent support
INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime # install-unix also install unix-only support
INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime # install-both install for lua51 lua52 lua53
# install-both-unix also install unix-only
# print print the build settings
all clean: PLAT?= linux
cd src; $(MAKE) $@ PLATS= macosx linux win32 win64 mingw freebsd solaris
#------ all: $(PLAT)
# Files to install
#
TO_SOCKET_SHARE:= \
http.lua \
url.lua \
tp.lua \
ftp.lua \
smtp.lua
TO_TOP_SHARE:= \ $(PLATS) none install install-unix local clean:
ltn12.lua \ $(MAKE) -C src $@
socket.lua \
mime.lua
TO_MIME_SHARE:= print:
$(MAKE) -C src $@
#------ test:
# Install LuaSocket according to recommendation lua test/hello.lua
#
install: all install-both:
cd src; mkdir -p $(INSTALL_TOP_SHARE) $(MAKE) clean
cd src; $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE) @cd src; $(MAKE) $(PLAT) LUAV=5.1
cd src; mkdir -p $(INSTALL_SOCKET_SHARE) @cd src; $(MAKE) install LUAV=5.1
cd src; $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE) $(MAKE) clean
cd src; mkdir -p $(INSTALL_SOCKET_LIB) @cd src; $(MAKE) $(PLAT) LUAV=5.2
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT) @cd src; $(MAKE) install LUAV=5.2
#cd src; mkdir -p $(INSTALL_MIME_SHARE) $(MAKE) clean
#cd src; $(INSTALL_DATA) $(TO_MIME_SHARE) $(INSTALL_MIME_SHARE) @cd src; $(MAKE) $(PLAT) LUAV=5.3
cd src; mkdir -p $(INSTALL_MIME_LIB) @cd src; $(MAKE) install LUAV=5.3
cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
install-both-unix:
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install-unix LUAV=5.1
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.2
@cd src; $(MAKE) install-unix LUAV=5.2
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.3
@cd src; $(MAKE) install-unix LUAV=5.3
.PHONY: test
#------
# End of makefile
#

View File

@@ -1,10 +1,11 @@
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
# Distribution makefile # Distribution makefile
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
DIST = luasocket-2.0.2 DIST = luasocket-3.0-rc1
TEST = \ TEST = \
test/README \ test/README \
test/hello.lua \
test/testclnt.lua \ test/testclnt.lua \
test/testsrvr.lua \ test/testsrvr.lua \
test/testsupport.lua test/testsupport.lua
@@ -15,6 +16,8 @@ SAMPLES = \
samples/daytimeclnt.lua \ samples/daytimeclnt.lua \
samples/echoclnt.lua \ samples/echoclnt.lua \
samples/echosrvr.lua \ samples/echosrvr.lua \
samples/mclisten.lua \
samples/mcsend.lua \
samples/listener.lua \ samples/listener.lua \
samples/lpr.lua \ samples/lpr.lua \
samples/talker.lua \ samples/talker.lua \
@@ -62,6 +65,7 @@ SRC = \
src/udp.c \ src/udp.c \
src/udp.h \ src/udp.h \
src/unix.c \ src/unix.c \
src/serial.c \
src/unix.h \ src/unix.h \
src/usocket.c \ src/usocket.c \
src/usocket.h \ src/usocket.h \
@@ -73,20 +77,25 @@ SRC = \
src/mime.lua \ src/mime.lua \
src/smtp.lua \ src/smtp.lua \
src/socket.lua \ src/socket.lua \
src/headers.lua \
src/tp.lua \ src/tp.lua \
src/url.lua src/url.lua
MAKE = \ MAKE = \
makefile \ makefile \
config \
luasocket.sln \ luasocket.sln \
socket.vcproj \ luasocket-scm-0.rockspec \
mime.vcproj Lua51.props \
Lua52.props \
socket.vcxproj.filters \
mime.vcxproj.filters \
socket.vcxproj \
mime.vcxproj
DOC = \ DOC = \
doc/dns.html \ doc/dns.html \
doc/ftp.html \ doc/ftp.html \
doc/home.html \ doc/index.html \
doc/http.html \ doc/http.html \
doc/installation.html \ doc/installation.html \
doc/introduction.html \ doc/introduction.html \

View File

@@ -1,141 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="mime"
ProjectGUID="{128E8BD0-174A-48F0-8771-92B1E8D18713}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;MIME_API=__declspec(dllexport)"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mime.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/mime.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/mime.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mime.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/mime.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="src\mime.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<File
RelativePath="..\..\lib\lua5.1.dll.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

204
mime.vcxproj Executable file
View File

@@ -0,0 +1,204 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\mime.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat />
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>
</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

1
mingw.cmd Normal file
View File

@@ -0,0 +1 @@
make PLAT=mingw LUAINC_mingw_base=/home/diego/build/mingw/include LUALIB_mingw_base=/home/diego/build/mingw/bin LUAPREFIX_mingw=/home/diego/build/mingw/bin DEBUG=DEBUG install-both

View File

@@ -0,0 +1,134 @@
package = "LuaSocket"
version = "3.0rc2-1"
source = {
url = "git://github.com/diegonehab/luasocket.git",
tag = "v3.0-rc2",
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG"
},
mingw32 = {
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501"
}
}
local modules = {
["socket.core"] = {
sources = {
"src/luasocket.c"
, "src/timeout.c"
, "src/buffer.c"
, "src/io.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/inet.c"
, "src/except.c"
, "src/select.c"
, "src/tcp.c"
, "src/udp.c"
, "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["mime.core"] = {
sources = { "src/mime.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["socket.http"] = "src/http.lua",
["socket.url"] = "src/url.lua",
["socket.tp"] = "src/tp.lua",
["socket.ftp"] = "src/ftp.lua",
["socket.headers"] = "src/headers.lua",
["socket.smtp"] = "src/smtp.lua",
ltn12 = "src/ltn12.lua",
socket = "src/socket.lua",
mime = "src/mime.lua"
}
if plat == "unix"
or plat == "macosx"
or plat == "haiku"
then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
if plat == "haiku" then
modules["socket.core"].libraries = {"network"}
end
modules["socket.unix"] = {
sources = {
"src/buffer.c"
, "src/compat.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/timeout.c"
, "src/io.c"
, "src/usocket.c"
, "src/unix.c"
, "src/unixdgram.c"
, "src/unixstream.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = {
"src/buffer.c"
, "src/compat.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/timeout.c"
, "src/io.c"
, "src/usocket.c"
, "src/serial.c" },
defines = defines[plat],
incdir = "/src"
}
end
if plat == "win32"
or plat == "mingw32"
then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" }
end
return { modules = modules }
end
build = {
type = "builtin",
platforms = {
unix = make_plat("unix"),
macosx = make_plat("macosx"),
haiku = make_plat("haiku"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = {
"doc"
, "samples"
, "etc"
, "test" }
}

View File

@@ -0,0 +1,134 @@
package = "LuaSocket"
version = "scm-2"
source = {
url = "git://github.com/diegonehab/luasocket.git"
, branch="master"
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG"
},
mingw32 = {
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501"
}
}
local modules = {
["socket.core"] = {
sources = {
"src/luasocket.c"
, "src/timeout.c"
, "src/buffer.c"
, "src/io.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/inet.c"
, "src/except.c"
, "src/select.c"
, "src/tcp.c"
, "src/udp.c"
, "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["mime.core"] = {
sources = { "src/mime.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["socket.http"] = "src/http.lua",
["socket.url"] = "src/url.lua",
["socket.tp"] = "src/tp.lua",
["socket.ftp"] = "src/ftp.lua",
["socket.headers"] = "src/headers.lua",
["socket.smtp"] = "src/smtp.lua",
ltn12 = "src/ltn12.lua",
socket = "src/socket.lua",
mime = "src/mime.lua"
}
if plat == "unix"
or plat == "macosx"
or plat == "haiku"
then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
if plat == "haiku" then
modules["socket.core"].libraries = {"network"}
end
modules["socket.unix"] = {
sources = {
"src/buffer.c"
, "src/compat.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/timeout.c"
, "src/io.c"
, "src/usocket.c"
, "src/unix.c"
, "src/unixdgram.c"
, "src/unixstream.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = {
"src/buffer.c"
, "src/compat.c"
, "src/auxiliar.c"
, "src/options.c"
, "src/timeout.c"
, "src/io.c"
, "src/usocket.c"
, "src/serial.c" },
defines = defines[plat],
incdir = "/src"
}
end
if plat == "win32"
or plat == "mingw32"
then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" }
end
return { modules = modules }
end
build = {
type = "builtin",
platforms = {
unix = make_plat("unix"),
macosx = make_plat("macosx"),
haiku = make_plat("haiku"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = {
"doc"
, "samples"
, "etc"
, "test" }
}

View File

@@ -32,7 +32,7 @@ end
local host = socket.dns.gethostname() local host = socket.dns.gethostname()
local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6" local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
local url = string.format(query, server, arg[1], arg[2], host) local url = string.format(query, server, arg[1], arg[2], host)
local body, headers, code = http.get(url) local body, headers, code = http.request(url)
if code == 200 then if code == 200 then
local data, code, error = parse(body) local data, code, error = parse(body)

View File

@@ -2,7 +2,6 @@
-- UDP sample: daytime protocol client -- UDP sample: daytime protocol client
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require"socket" local socket = require"socket"
host = host or "127.0.0.1" host = host or "127.0.0.1"

View File

@@ -2,7 +2,6 @@
-- UDP sample: echo protocol client -- UDP sample: echo protocol client
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
host = host or "localhost" host = host or "localhost"

View File

@@ -2,7 +2,6 @@
-- UDP sample: echo protocol server -- UDP sample: echo protocol server
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
host = host or "127.0.0.1" host = host or "127.0.0.1"

View File

@@ -2,7 +2,6 @@
-- TCP sample: Little program to dump lines received at a given port -- TCP sample: Little program to dump lines received at a given port
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
host = host or "*" host = host or "*"

View File

@@ -28,8 +28,8 @@ end
do do
local opt = {} local opt = {}
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)" local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]?.?)"
for i = 2, table.getn(arg), 1 do for i = 2, #arg, 1 do
string.gsub(arg[i], pat, function(name, value) opt[name] = value end) string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
end end
if not arg[2] then if not arg[2] then

18
samples/mclisten.lua Normal file
View File

@@ -0,0 +1,18 @@
local socket = require"socket"
local group = "225.0.0.37"
local port = 12345
local c = assert(socket.udp())
print(assert(c:setoption("reuseport", true)))
print(assert(c:setsockname("*", port)))
--print("loop:", c:getoption("ip-multicast-loop"))
--print(assert(c:setoption("ip-multicast-loop", false)))
--print("loop:", c:getoption("ip-multicast-loop"))
--print("if:", c:getoption("ip-multicast-if"))
--print(assert(c:setoption("ip-multicast-if", "127.0.0.1")))
--print("if:", c:getoption("ip-multicast-if"))
--print(assert(c:setoption("ip-multicast-if", "10.0.1.4")))
--print("if:", c:getoption("ip-multicast-if"))
print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
while 1 do
print(c:receivefrom())
end

20
samples/mcsend.lua Normal file
View File

@@ -0,0 +1,20 @@
local socket = require"socket"
local group = "225.0.0.37"
local port = 12345
local c = assert(socket.udp())
--print(assert(c:setoption("reuseport", true)))
--print(assert(c:setsockname("*", port)))
--print(assert(c:setoption("ip-multicast-loop", false)))
--print(assert(c:setoption("ip-multicast-ttl", 4)))
--print(assert(c:setoption("ip-multicast-if", "10.0.1.3")))
--print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
local i = 0
while 1 do
local message = string.format("hello all %d!", i)
assert(c:sendto(message, group, port))
print("sent " .. message)
socket.sleep(1)
c:settimeout(0.5)
print(c:receivefrom())
i = i + 1
end

View File

@@ -2,7 +2,6 @@
-- TCP sample: Little program to send text lines to a given host/port -- TCP sample: Little program to send text lines to a given host/port
-- LuaSocket sample files -- LuaSocket sample files
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
host = host or "localhost" host = host or "localhost"

View File

@@ -2,7 +2,6 @@
-- Select sample: simple text line server -- Select sample: simple text line server
-- LuaSocket sample files. -- LuaSocket sample files.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local socket = require("socket") local socket = require("socket")
host = host or "*" host = host or "*"
@@ -32,7 +31,7 @@ function newset()
insert = function(set, value) insert = function(set, value)
if not reverse[value] then if not reverse[value] then
table.insert(set, value) table.insert(set, value)
reverse[value] = table.getn(set) reverse[value] = #set
end end
end, end,
remove = function(set, value) remove = function(set, value)

View File

@@ -1,182 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="socket"
ProjectGUID="{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport)"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/socket.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/socket.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/socket.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="./src"
IntermediateDirectory="./src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/socket.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/socket.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="src\auxiliar.c">
</File>
<File
RelativePath="src\buffer.c">
</File>
<File
RelativePath="src\except.c">
</File>
<File
RelativePath="src\inet.c">
</File>
<File
RelativePath="src\io.c">
</File>
<File
RelativePath="src\luasocket.c">
</File>
<File
RelativePath="src\options.c">
</File>
<File
RelativePath="src\select.c">
</File>
<File
RelativePath="src\tcp.c">
</File>
<File
RelativePath="src\timeout.c">
</File>
<File
RelativePath="src\udp.c">
</File>
<File
RelativePath="src\wsocket.c">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
GeneratePreprocessedFile="0"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<File
RelativePath="..\..\lib\lua5.1.dll.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

215
socket.vcxproj Executable file
View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\auxiliar.c" />
<ClCompile Include="src\buffer.c" />
<ClCompile Include="src\except.c" />
<ClCompile Include="src\inet.c" />
<ClCompile Include="src\io.c" />
<ClCompile Include="src\luasocket.c" />
<ClCompile Include="src\options.c" />
<ClCompile Include="src\select.c" />
<ClCompile Include="src\tcp.c" />
<ClCompile Include="src\timeout.c" />
<ClCompile Include="src\udp.c" />
<ClCompile Include="src\wsocket.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat />
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>
</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,17 +1,12 @@
/*=========================================================================*\ /*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation * Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "auxiliar.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes the module * Initializes the module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -24,11 +19,11 @@ int auxiliar_open(lua_State *L) {
* Creates a new class with given methods * Creates a new class with given methods
* Methods whose names start with __ are passed directly to the metatable. * Methods whose names start with __ are passed directly to the metatable.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func) { void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
luaL_newmetatable(L, classname); /* mt */ luaL_newmetatable(L, classname); /* mt */
/* create __index table to place methods */ /* create __index table to place methods */
lua_pushstring(L, "__index"); /* mt,"__index" */ lua_pushstring(L, "__index"); /* mt,"__index" */
lua_newtable(L); /* mt,"__index",it */ lua_newtable(L); /* mt,"__index",it */
/* put class name into class metatable */ /* put class name into class metatable */
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
@@ -81,12 +76,12 @@ void auxiliar_add2group(lua_State *L, const char *classname, const char *groupna
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int auxiliar_checkboolean(lua_State *L, int objidx) { int auxiliar_checkboolean(lua_State *L, int objidx) {
if (!lua_isboolean(L, objidx)) if (!lua_isboolean(L, objidx))
luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, objidx); return lua_toboolean(L, objidx);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given class, abort with * Return userdata pointer if object belongs to a given class, abort with
* error otherwise * error otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
@@ -100,7 +95,7 @@ void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given group, abort with * Return userdata pointer if object belongs to a given group, abort with
* error otherwise * error otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
@@ -123,7 +118,7 @@ void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given group. Return NULL * Get a userdata pointer if object belongs to a given group. Return NULL
* otherwise * otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
@@ -141,9 +136,19 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given class. Return NULL * Get a userdata pointer if object belongs to a given class. Return NULL
* otherwise * otherwise
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
return luaL_checkudata(L, objidx, classname); return luaL_testudata(L, objidx, classname);
}
/*-------------------------------------------------------------------------*\
* Throws error when argument does not have correct type.
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
\*-------------------------------------------------------------------------*/
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
} }

View File

@@ -4,12 +4,12 @@
* Auxiliar routines for class hierarchy manipulation * Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit (but completely independent of other LuaSocket modules) * LuaSocket toolkit (but completely independent of other LuaSocket modules)
* *
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket * A LuaSocket class is a name associated with Lua metatables. A LuaSocket
* group is a name associated with a class. A class can belong to any number * group is a name associated with a class. A class can belong to any number
* of groups. This module provides the functionality to: * of groups. This module provides the functionality to:
* *
* - create new classes * - create new classes
* - add classes to groups * - add classes to groups
* - set the class of objects * - set the class of objects
* - check if an object belongs to a given class or group * - check if an object belongs to a given class or group
* - get the userdata associated to objects * - get the userdata associated to objects
@@ -26,23 +26,29 @@
* "class" with the class name. * "class" with the class name.
* *
* The mapping from class name to the corresponding metatable and the * The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib. * reverse mapping are done using lauxlib.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "lauxlib.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int auxiliar_open(lua_State *L); int auxiliar_open(lua_State *L);
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func); void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
int auxiliar_tostring(lua_State *L);
void auxiliar_add2group(lua_State *L, const char *classname, const char *group); void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
void auxiliar_setclass(lua_State *L, const char *classname, int objidx); int auxiliar_checkboolean(lua_State *L, int objidx);
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_checkboolean(lua_State *L, int objidx); void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_tostring(lua_State *L); int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* AUXILIAR_H */ #endif /* AUXILIAR_H */

View File

@@ -1,12 +1,8 @@
/*=========================================================================*\ /*=========================================================================*\
* Input/Output interface for Lua programs * Input/Output interface for Lua programs
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "lauxlib.h"
#include "buffer.h" #include "buffer.h"
/*=========================================================================*\ /*=========================================================================*\
@@ -39,10 +35,10 @@ int buffer_open(lua_State *L) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes C structure * Initializes C structure
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void buffer_init(p_buffer buf, p_io io, p_timeout tm) { void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
buf->first = buf->last = 0; buf->first = buf->last = 0;
buf->io = io; buf->io = io;
buf->tm = tm; buf->tm = tm;
buf->received = buf->sent = 0; buf->received = buf->sent = 0;
@@ -53,8 +49,8 @@ void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
* object:getstats() interface * object:getstats() interface
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) { int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, buf->received); lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, buf->sent); lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday); lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3; return 3;
} }
@@ -63,8 +59,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
* object:setstats() interface * object:setstats() interface
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) { int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, buf->received); buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, buf->sent); buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
return 1; return 1;
@@ -80,7 +76,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
const char *data = luaL_checklstring(L, 2, &size); const char *data = luaL_checklstring(L, 2, &size);
long start = (long) luaL_optnumber(L, 3, 1); long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1); long end = (long) luaL_optnumber(L, 4, -1);
p_timeout tm = timeout_markstart(buf->tm); timeout_markstart(buf->tm);
if (start < 0) start = (long) (size+start+1); if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1); if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1; if (start < 1) start = (long) 1;
@@ -89,16 +85,16 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
/* check if there was an error */ /* check if there was an error */
if (err != IO_DONE) { if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, sent+start-1); lua_pushnumber(L, (lua_Number) (sent+start-1));
} else { } else {
lua_pushnumber(L, sent+start-1); lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L); lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L);
} }
#ifdef LUASOCKET_DEBUG #ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */ /* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
#endif #endif
return lua_gettop(L) - top; return lua_gettop(L) - top;
} }
@@ -111,8 +107,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
luaL_Buffer b; luaL_Buffer b;
size_t size; size_t size;
const char *part = luaL_optlstring(L, 3, "", &size); const char *part = luaL_optlstring(L, 3, "", &size);
p_timeout tm = timeout_markstart(buf->tm); timeout_markstart(buf->tm);
/* initialize buffer with optional extra prefix /* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */ * (useful for concatenating previous partial results) */
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
luaL_addlstring(&b, part, size); luaL_addlstring(&b, part, size);
@@ -120,18 +116,24 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
if (!lua_isnumber(L, 2)) { if (!lua_isnumber(L, 2)) {
const char *p= luaL_optstring(L, 2, "*l"); const char *p= luaL_optstring(L, 2, "*l");
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern"); else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes (minus what was already partially /* get a fixed number of bytes (minus what was already partially
* received) */ * received) */
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b); } else {
double n = lua_tonumber(L, 2);
size_t wanted = (size_t) n;
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
if (size == 0 || wanted > size)
err = recvraw(buf, wanted-size, &b);
}
/* check if there was an error */ /* check if there was an error */
if (err != IO_DONE) { if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the /* we can't push anyting in the stack before pushing the
* contents of the buffer. this is the reason for the complication */ * contents of the buffer. this is the reason for the complication */
luaL_pushresult(&b); luaL_pushresult(&b);
lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_pushnil(L); lua_pushnil(L);
lua_replace(L, -4); lua_replace(L, -4);
} else { } else {
@@ -141,7 +143,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
} }
#ifdef LUASOCKET_DEBUG #ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */ /* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
#endif #endif
return lua_gettop(L) - top; return lua_gettop(L) - top;
} }
@@ -166,7 +168,7 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
size_t total = 0; size_t total = 0;
int err = IO_DONE; int err = IO_DONE;
while (total < count && err == IO_DONE) { while (total < count && err == IO_DONE) {
size_t done; size_t done = 0;
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm); err = io->send(io->ctx, data+total, step, &done, tm);
total += done; total += done;
@@ -214,7 +216,7 @@ static int recvall(p_buffer buf, luaL_Buffer *b) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
* are not returned by the function and are discarded from the buffer * are not returned by the function and are discarded from the buffer
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int recvline(p_buffer buf, luaL_Buffer *b) { static int recvline(p_buffer buf, luaL_Buffer *b) {
@@ -225,7 +227,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
pos = 0; pos = 0;
while (pos < count && data[pos] != '\n') { while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */ /* we ignore all \r's */
if (data[pos] != '\r') luaL_putchar(b, data[pos]); if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++; pos++;
} }
if (pos < count) { /* found '\n' */ if (pos < count) { /* found '\n' */
@@ -244,7 +246,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
static void buffer_skip(p_buffer buf, size_t count) { static void buffer_skip(p_buffer buf, size_t count) {
buf->received += count; buf->received += count;
buf->first += count; buf->first += count;
if (buffer_isempty(buf)) if (buffer_isempty(buf))
buf->first = buf->last = 0; buf->first = buf->last = 0;
} }

View File

@@ -14,11 +14,8 @@
* *
* The module is built on top of the I/O abstraction defined in io.h and the * The module is built on top of the I/O abstraction defined in io.h and the
* timeout management is done with the timeout.h interface. * timeout management is done with the timeout.h interface.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "io.h" #include "io.h"
#include "timeout.h" #include "timeout.h"
@@ -31,17 +28,25 @@ typedef struct t_buffer_ {
size_t sent, received; /* bytes sent, and bytes received */ size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */ p_io io; /* IO driver used for this buffer */
p_timeout tm; /* timeout management for this buffer */ p_timeout tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */ size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */ char data[BUF_SIZE]; /* storage space for buffer data */
} t_buffer; } t_buffer;
typedef t_buffer *p_buffer; typedef t_buffer *p_buffer;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int buffer_open(lua_State *L); int buffer_open(lua_State *L);
void buffer_init(p_buffer buf, p_io io, p_timeout tm); void buffer_init(p_buffer buf, p_io io, p_timeout tm);
int buffer_meth_send(lua_State *L, p_buffer buf);
int buffer_meth_receive(lua_State *L, p_buffer buf);
int buffer_meth_getstats(lua_State *L, p_buffer buf); int buffer_meth_getstats(lua_State *L, p_buffer buf);
int buffer_meth_setstats(lua_State *L, p_buffer buf); int buffer_meth_setstats(lua_State *L, p_buffer buf);
int buffer_meth_send(lua_State *L, p_buffer buf);
int buffer_meth_receive(lua_State *L, p_buffer buf);
int buffer_isempty(p_buffer buf); int buffer_isempty(p_buffer buf);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* BUF_H */ #endif /* BUF_H */

39
src/compat.c Normal file
View File

@@ -0,0 +1,39 @@
#include "luasocket.h"
#include "compat.h"
#if LUA_VERSION_NUM==501
/*
** Adapted from Lua 5.2
*/
void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup+1, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
lua_pushstring(L, l->name);
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -(nup+1));
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
lua_settable(L, -(nup + 3));
}
lua_pop(L, nup); /* remove upvalues */
}
/*
** Duplicated from Lua 5.2
*/
void *luasocket_testudata (lua_State *L, int ud, const char *tname) {
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
luaL_getmetatable(L, tname); /* get correct metatable */
if (!lua_rawequal(L, -1, -2)) /* not the same? */
p = NULL; /* value is a userdata with wrong metatable */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
return NULL; /* value is not a userdata with a metatable */
}
#endif

22
src/compat.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef COMPAT_H
#define COMPAT_H
#if LUA_VERSION_NUM==501
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
void *luasocket_testudata ( lua_State *L, int arg, const char *tname);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#define luaL_setfuncs luasocket_setfuncs
#define luaL_testudata luasocket_testudata
#endif
#endif

View File

@@ -1,15 +1,19 @@
/*=========================================================================*\ /*=========================================================================*\
* Simple exception support * Simple exception support
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "luasocket.h"
#include "except.h"
#include <stdio.h> #include <stdio.h>
#include "lua.h" #if LUA_VERSION_NUM < 502
#include "lauxlib.h" #define lua_pcallk(L, na, nr, err, ctx, cont) \
(((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
#endif
#include "except.h" #if LUA_VERSION_NUM < 503
typedef int lua_KContext;
#endif
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes. * Internal function prototypes.
@@ -21,7 +25,7 @@ static int finalize(lua_State *L);
static int do_nothing(lua_State *L); static int do_nothing(lua_State *L);
/* except functions */ /* except functions */
static luaL_reg func[] = { static luaL_Reg func[] = {
{"newtry", global_newtry}, {"newtry", global_newtry},
{"protect", global_protect}, {"protect", global_protect},
{NULL, NULL} {NULL, NULL}
@@ -31,18 +35,17 @@ static luaL_reg func[] = {
* Try factory * Try factory
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void wrap(lua_State *L) { static void wrap(lua_State *L) {
lua_newtable(L); lua_createtable(L, 1, 0);
lua_pushnumber(L, 1); lua_pushvalue(L, -2);
lua_pushvalue(L, -3); lua_rawseti(L, -2, 1);
lua_settable(L, -3); lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, -2); lua_setmetatable(L, -2);
lua_pop(L, 1);
} }
static int finalize(lua_State *L) { static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) { if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1)); lua_pushvalue(L, lua_upvalueindex(2));
lua_pcall(L, 0, 0, 0); lua_call(L, 0, 0);
lua_settop(L, 2); lua_settop(L, 2);
wrap(L); wrap(L);
lua_error(L); lua_error(L);
@@ -50,15 +53,17 @@ static int finalize(lua_State *L) {
} else return lua_gettop(L); } else return lua_gettop(L);
} }
static int do_nothing(lua_State *L) { static int do_nothing(lua_State *L) {
(void) L; (void) L;
return 0; return 0;
} }
static int global_newtry(lua_State *L) { static int global_newtry(lua_State *L) {
lua_settop(L, 1); lua_settop(L, 1);
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1); lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, -2);
lua_pushcclosure(L, finalize, 2);
return 1; return 1;
} }
@@ -66,27 +71,49 @@ static int global_newtry(lua_State *L) {
* Protect factory * Protect factory
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int unwrap(lua_State *L) { static int unwrap(lua_State *L) {
if (lua_istable(L, -1)) { if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
lua_pushnumber(L, 1); int r = lua_rawequal(L, -1, lua_upvalueindex(1));
lua_gettable(L, -2); lua_pop(L, 1);
lua_pushnil(L); if (r) {
lua_insert(L, -2); lua_pushnil(L);
return 1; lua_rawgeti(L, -2, 1);
} else return 0; return 1;
}
}
return 0;
} }
static int protected_(lua_State *L) { static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
lua_pushvalue(L, lua_upvalueindex(1)); (void)ctx;
lua_insert(L, 1); if (status != 0 && status != LUA_YIELD) {
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
if (unwrap(L)) return 2; if (unwrap(L)) return 2;
else lua_error(L); else return lua_error(L);
return 0;
} else return lua_gettop(L); } else return lua_gettop(L);
} }
#if LUA_VERSION_NUM == 502
static int protected_cont(lua_State *L) {
int ctx = 0;
int status = lua_getctx(L, &ctx);
return protected_finish(L, status, ctx);
}
#else
#define protected_cont protected_finish
#endif
static int protected_(lua_State *L) {
int status;
lua_pushvalue(L, lua_upvalueindex(2));
lua_insert(L, 1);
status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
return protected_finish(L, status, 0);
}
static int global_protect(lua_State *L) { static int global_protect(lua_State *L) {
lua_pushcclosure(L, protected_, 1); lua_settop(L, 1);
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
lua_pushcclosure(L, protected_, 2);
return 1; return 1;
} }
@@ -94,6 +121,9 @@ static int global_protect(lua_State *L) {
* Init module * Init module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int except_open(lua_State *L) { int except_open(lua_State *L) {
luaL_openlib(L, NULL, func, 0); lua_newtable(L); /* metatable for wrapped exceptions */
lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable");
luaL_setfuncs(L, func, 1);
return 0; return 0;
} }

View File

@@ -9,27 +9,38 @@
* error checking was taking a substantial amount of the coding. These * error checking was taking a substantial amount of the coding. These
* function greatly simplify the task of checking errors. * function greatly simplify the task of checking errors.
* *
* The main idea is that functions should return nil as its first return * The main idea is that functions should return nil as their first return
* value when it finds an error, and return an error message (or value) * values when they find an error, and return an error message (or value)
* following nil. In case of success, as long as the first value is not nil, * following nil. In case of success, as long as the first value is not nil,
* the other values don't matter. * the other values don't matter.
* *
* The idea is to nest function calls with the "try" function. This function * The idea is to nest function calls with the "try" function. This function
* checks the first value, and calls "error" on the second if the first is * checks the first value, and, if it's falsy, wraps the second value in a
* nil. Otherwise, it returns all values it received. * table with metatable and calls "error" on it. Otherwise, it returns all
* values it received. Basically, it works like the Lua "assert" function,
* but it creates errors targeted specifically at "protect".
* *
* The protect function returns a new function that behaves exactly like the * The "newtry" function is a factory for "try" functions that call a
* function it receives, but the new function doesn't throw exceptions: it * finalizer in protected mode before calling "error".
* returns nil followed by the error message instead.
* *
* With these two function, it's easy to write functions that throw * The "protect" function returns a new function that behaves exactly like
* exceptions on error, but that don't interrupt the user script. * the function it receives, but the new function catches exceptions thrown
* by "try" functions and returns nil followed by the error message instead.
* *
* RCS ID: $Id$ * With these three functions, it's easy to write functions that throw
* exceptions on error, but that don't interrupt the user script.
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int except_open(lua_State *L); int except_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif #endif

View File

@@ -2,7 +2,6 @@
-- FTP support for the Lua language -- FTP support for the Lua language
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -16,27 +15,27 @@ local socket = require("socket")
local url = require("socket.url") local url = require("socket.url")
local tp = require("socket.tp") local tp = require("socket.tp")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
module("socket.ftp") socket.ftp = {}
local _M = socket.ftp
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Program constants -- Program constants
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- timeout in seconds before the program gives up on a connection -- timeout in seconds before the program gives up on a connection
TIMEOUT = 60 _M.TIMEOUT = 60
-- default port for ftp service -- default port for ftp service
PORT = 21 local PORT = 21
-- this is the default anonymous password. used when no password is -- this is the default anonymous password. used when no password is
-- provided in url. should be changed to your e-mail. -- provided in url. should be changed to your e-mail.
USER = "ftp" _M.USER = "ftp"
PASSWORD = "anonymous@anonymous.org" _M.PASSWORD = "anonymous@anonymous.org"
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Low level FTP API -- Low level FTP API
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local metat = { __index = {} } local metat = { __index = {} }
function open(server, port, create) function _M.open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create)) local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
local f = base.setmetatable({ tp = tp }, metat) local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception -- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end) f.try = socket.newtry(function() f:close() end)
@@ -44,22 +43,22 @@ function open(server, port, create)
end end
function metat.__index:portconnect() function metat.__index:portconnect()
self.try(self.server:settimeout(TIMEOUT)) self.try(self.server:settimeout(_M.TIMEOUT))
self.data = self.try(self.server:accept()) self.data = self.try(self.server:accept())
self.try(self.data:settimeout(TIMEOUT)) self.try(self.data:settimeout(_M.TIMEOUT))
end end
function metat.__index:pasvconnect() function metat.__index:pasvconnect()
self.data = self.try(socket.tcp()) self.data = self.try(socket.tcp())
self.try(self.data:settimeout(TIMEOUT)) self.try(self.data:settimeout(_M.TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
end end
function metat.__index:login(user, password) function metat.__index:login(user, password)
self.try(self.tp:command("user", user or USER)) self.try(self.tp:command("user", user or _M.USER))
local code, reply = self.try(self.tp:check{"2..", 331}) local code, reply = self.try(self.tp:check{"2..", 331})
if code == 331 then if code == 331 then
self.try(self.tp:command("pass", password or PASSWORD)) self.try(self.tp:command("pass", password or _M.PASSWORD))
self.try(self.tp:check("2..")) self.try(self.tp:check("2.."))
end end
return 1 return 1
@@ -72,32 +71,65 @@ function metat.__index:pasv()
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
self.try(a and b and c and d and p1 and p2, reply) self.try(a and b and c and d and p1 and p2, reply)
self.pasvt = { self.pasvt = {
ip = string.format("%d.%d.%d.%d", a, b, c, d), address = string.format("%d.%d.%d.%d", a, b, c, d),
port = p1*256 + p2 port = p1*256 + p2
} }
if self.server then if self.server then
self.server:close() self.server:close()
self.server = nil self.server = nil
end end
return self.pasvt.ip, self.pasvt.port return self.pasvt.address, self.pasvt.port
end end
function metat.__index:port(ip, port) function metat.__index:epsv()
self.try(self.tp:command("epsv"))
local code, reply = self.try(self.tp:check("229"))
local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
local d, prt, address, port = string.match(reply, pattern)
self.try(port, "invalid epsv response")
self.pasvt = {
address = self.tp:getpeername(),
port = port
}
if self.server then
self.server:close()
self.server = nil
end
return self.pasvt.address, self.pasvt.port
end
function metat.__index:port(address, port)
self.pasvt = nil self.pasvt = nil
if not ip then if not address then
ip, port = self.try(self.tp:getcontrol():getsockname()) address, port = self.try(self.tp:getsockname())
self.server = self.try(socket.bind(ip, 0)) self.server = self.try(socket.bind(address, 0))
ip, port = self.try(self.server:getsockname()) address, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(TIMEOUT)) self.try(self.server:settimeout(_M.TIMEOUT))
end end
local pl = math.mod(port, 256) local pl = math.mod(port, 256)
local ph = (port - pl)/256 local ph = (port - pl)/256
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",")
self.try(self.tp:command("port", arg)) self.try(self.tp:command("port", arg))
self.try(self.tp:check("2..")) self.try(self.tp:check("2.."))
return 1 return 1
end end
function metat.__index:eprt(family, address, port)
self.pasvt = nil
if not address then
address, port = self.try(self.tp:getsockname())
self.server = self.try(socket.bind(address, 0))
address, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(_M.TIMEOUT))
end
local arg = string.format("|%s|%s|%d|", family, address, port)
self.try(self.tp:command("eprt", arg))
self.try(self.tp:check("2.."))
return 1
end
function metat.__index:send(sendt) function metat.__index:send(sendt)
self.try(self.pasvt or self.server, "need port or pasv first") self.try(self.pasvt or self.server, "need port or pasv first")
-- if there is a pasvt table, we already sent a PASV command -- if there is a pasvt table, we already sent a PASV command
@@ -111,12 +143,12 @@ function metat.__index:send(sendt)
-- send the transfer command and check the reply -- send the transfer command and check the reply
self.try(self.tp:command(command, argument)) self.try(self.tp:command(command, argument))
local code, reply = self.try(self.tp:check{"2..", "1.."}) local code, reply = self.try(self.tp:check{"2..", "1.."})
-- if there is not a a pasvt table, then there is a server -- if there is not a pasvt table, then there is a server
-- and we already sent a PORT command -- and we already sent a PORT command
if not self.pasvt then self:portconnect() end if not self.pasvt then self:portconnect() end
-- get the sink, source and step for the transfer -- get the sink, source and step for the transfer
local step = sendt.step or ltn12.pump.step local step = sendt.step or ltn12.pump.step
local readt = {self.tp.c} local readt = { self.tp }
local checkstep = function(src, snk) local checkstep = function(src, snk)
-- check status in control connection while downloading -- check status in control connection while downloading
local readyt = socket.select(readt, nil, 0) local readyt = socket.select(readt, nil, 0)
@@ -143,7 +175,11 @@ function metat.__index:receive(recvt)
if argument == "" then argument = nil end if argument == "" then argument = nil end
local command = recvt.command or "retr" local command = recvt.command or "retr"
self.try(self.tp:command(command, argument)) self.try(self.tp:command(command, argument))
local code = self.try(self.tp:check{"1..", "2.."}) local code,reply = self.try(self.tp:check{"1..", "2.."})
if (code >= 200) and (code <= 299) then
recvt.sink(reply)
return 1
end
if not self.pasvt then self:portconnect() end if not self.pasvt then self:portconnect() end
local source = socket.source("until-closed", self.data) local source = socket.source("until-closed", self.data)
local step = recvt.step or ltn12.pump.step local step = recvt.step or ltn12.pump.step
@@ -200,11 +236,11 @@ end
local function tput(putt) local function tput(putt)
putt = override(putt) putt = override(putt)
socket.try(putt.host, "missing hostname") socket.try(putt.host, "missing hostname")
local f = open(putt.host, putt.port, putt.create) local f = _M.open(putt.host, putt.port, putt.create)
f:greet() f:greet()
f:login(putt.user, putt.password) f:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end if putt.type then f:type(putt.type) end
f:pasv() f:epsv()
local sent = f:send(putt) local sent = f:send(putt)
f:quit() f:quit()
f:close() f:close()
@@ -212,11 +248,11 @@ local function tput(putt)
end end
local default = { local default = {
path = "/", path = "/",
scheme = "ftp" scheme = "ftp"
} }
local function parse(u) local function genericform(u)
local t = socket.try(url.parse(u, default)) local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
socket.try(t.host, "missing hostname") socket.try(t.host, "missing hostname")
@@ -229,13 +265,15 @@ local function parse(u)
return t return t
end end
_M.genericform = genericform
local function sput(u, body) local function sput(u, body)
local putt = parse(u) local putt = genericform(u)
putt.source = ltn12.source.string(body) putt.source = ltn12.source.string(body)
return tput(putt) return tput(putt)
end end
put = socket.protect(function(putt, body) _M.put = socket.protect(function(putt, body)
if base.type(putt) == "string" then return sput(putt, body) if base.type(putt) == "string" then return sput(putt, body)
else return tput(putt) end else return tput(putt) end
end) end)
@@ -243,39 +281,49 @@ end)
local function tget(gett) local function tget(gett)
gett = override(gett) gett = override(gett)
socket.try(gett.host, "missing hostname") socket.try(gett.host, "missing hostname")
local f = open(gett.host, gett.port, gett.create) local f = _M.open(gett.host, gett.port, gett.create)
f:greet() f:greet()
f:login(gett.user, gett.password) f:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end if gett.type then f:type(gett.type) end
f:pasv() f:epsv()
f:receive(gett) f:receive(gett)
f:quit() f:quit()
return f:close() return f:close()
end end
local function sget(u) local function sget(u)
local gett = parse(u) local gett = genericform(u)
local t = {} local t = {}
gett.sink = ltn12.sink.table(t) gett.sink = ltn12.sink.table(t)
tget(gett) tget(gett)
return table.concat(t) return table.concat(t)
end end
command = socket.protect(function(cmdt) _M.command = socket.protect(function(cmdt)
cmdt = override(cmdt) cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname") socket.try(cmdt.host, "missing hostname")
socket.try(cmdt.command, "missing command") socket.try(cmdt.command, "missing command")
local f = open(cmdt.host, cmdt.port, cmdt.create) local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
f:greet() f:greet()
f:login(cmdt.user, cmdt.password) f:login(cmdt.user, cmdt.password)
f.try(f.tp:command(cmdt.command, cmdt.argument)) if type(cmdt.command) == "table" then
if cmdt.check then f.try(f.tp:check(cmdt.check)) end local argument = cmdt.argument or {}
local check = cmdt.check or {}
for i,cmd in ipairs(cmdt.command) do
f.try(f.tp:command(cmd, argument[i]))
if check[i] then f.try(f.tp:check(check[i])) end
end
else
f.try(f.tp:command(cmdt.command, cmdt.argument))
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
end
f:quit() f:quit()
return f:close() return f:close()
end) end)
get = socket.protect(function(gett) _M.get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett) if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end else return tget(gett) end
end) end)
return _M

104
src/headers.lua Normal file
View File

@@ -0,0 +1,104 @@
-----------------------------------------------------------------------------
-- Canonic header field capitalization
-- LuaSocket toolkit.
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local socket = require("socket")
socket.headers = {}
local _M = socket.headers
_M.canonic = {
["accept"] = "Accept",
["accept-charset"] = "Accept-Charset",
["accept-encoding"] = "Accept-Encoding",
["accept-language"] = "Accept-Language",
["accept-ranges"] = "Accept-Ranges",
["action"] = "Action",
["alternate-recipient"] = "Alternate-Recipient",
["age"] = "Age",
["allow"] = "Allow",
["arrival-date"] = "Arrival-Date",
["authorization"] = "Authorization",
["bcc"] = "Bcc",
["cache-control"] = "Cache-Control",
["cc"] = "Cc",
["comments"] = "Comments",
["connection"] = "Connection",
["content-description"] = "Content-Description",
["content-disposition"] = "Content-Disposition",
["content-encoding"] = "Content-Encoding",
["content-id"] = "Content-ID",
["content-language"] = "Content-Language",
["content-length"] = "Content-Length",
["content-location"] = "Content-Location",
["content-md5"] = "Content-MD5",
["content-range"] = "Content-Range",
["content-transfer-encoding"] = "Content-Transfer-Encoding",
["content-type"] = "Content-Type",
["cookie"] = "Cookie",
["date"] = "Date",
["diagnostic-code"] = "Diagnostic-Code",
["dsn-gateway"] = "DSN-Gateway",
["etag"] = "ETag",
["expect"] = "Expect",
["expires"] = "Expires",
["final-log-id"] = "Final-Log-ID",
["final-recipient"] = "Final-Recipient",
["from"] = "From",
["host"] = "Host",
["if-match"] = "If-Match",
["if-modified-since"] = "If-Modified-Since",
["if-none-match"] = "If-None-Match",
["if-range"] = "If-Range",
["if-unmodified-since"] = "If-Unmodified-Since",
["in-reply-to"] = "In-Reply-To",
["keywords"] = "Keywords",
["last-attempt-date"] = "Last-Attempt-Date",
["last-modified"] = "Last-Modified",
["location"] = "Location",
["max-forwards"] = "Max-Forwards",
["message-id"] = "Message-ID",
["mime-version"] = "MIME-Version",
["original-envelope-id"] = "Original-Envelope-ID",
["original-recipient"] = "Original-Recipient",
["pragma"] = "Pragma",
["proxy-authenticate"] = "Proxy-Authenticate",
["proxy-authorization"] = "Proxy-Authorization",
["range"] = "Range",
["received"] = "Received",
["received-from-mta"] = "Received-From-MTA",
["references"] = "References",
["referer"] = "Referer",
["remote-mta"] = "Remote-MTA",
["reply-to"] = "Reply-To",
["reporting-mta"] = "Reporting-MTA",
["resent-bcc"] = "Resent-Bcc",
["resent-cc"] = "Resent-Cc",
["resent-date"] = "Resent-Date",
["resent-from"] = "Resent-From",
["resent-message-id"] = "Resent-Message-ID",
["resent-reply-to"] = "Resent-Reply-To",
["resent-sender"] = "Resent-Sender",
["resent-to"] = "Resent-To",
["retry-after"] = "Retry-After",
["return-path"] = "Return-Path",
["sender"] = "Sender",
["server"] = "Server",
["smtp-remote-recipient"] = "SMTP-Remote-Recipient",
["status"] = "Status",
["subject"] = "Subject",
["te"] = "TE",
["to"] = "To",
["trailer"] = "Trailer",
["transfer-encoding"] = "Transfer-Encoding",
["upgrade"] = "Upgrade",
["user-agent"] = "User-Agent",
["vary"] = "Vary",
["via"] = "Via",
["warning"] = "Warning",
["will-retry-until"] = "Will-Retry-Until",
["www-authenticate"] = "WWW-Authenticate",
["x-mailer"] = "X-Mailer",
}
return _M

View File

@@ -2,7 +2,6 @@
-- HTTP/1.1 client support for the Lua language. -- HTTP/1.1 client support for the Lua language.
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -13,20 +12,38 @@ local url = require("socket.url")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local mime = require("mime") local mime = require("mime")
local string = require("string") local string = require("string")
local headers = require("socket.headers")
local base = _G local base = _G
local table = require("table") local table = require("table")
module("socket.http") socket.http = {}
local _M = socket.http
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Program constants -- Program constants
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- connection timeout in seconds -- connection timeout in seconds
TIMEOUT = 60 _M.TIMEOUT = 60
-- default port for document retrieval
PORT = 80
-- user agent field sent in request -- user agent field sent in request
USERAGENT = socket._VERSION _M.USERAGENT = socket._VERSION
-- supported schemes and their particulars
local SCHEMES = {
http = {
port = 80
, create = function(t)
return socket.tcp end }
, https = {
port = 443
, create = function(t)
local https = assert(
require("ssl.https"), 'LuaSocket: LuaSec not found')
local tcp = assert(
https.tcp, 'LuaSocket: Function tcp() not available from LuaSec')
return tcp(t) end }}
-- default scheme and port for document retrieval
local SCHEME = 'http'
local PORT = SCHEMES[SCHEME].port
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed -- Reads MIME headers from a connection, unfolding where needed
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -105,15 +122,15 @@ end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local metat = { __index = {} } local metat = { __index = {} }
function open(host, port, create) function _M.open(host, port, create)
-- create socket with user connect function, or with default -- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)()) local c = socket.try(create())
local h = base.setmetatable({ c = c }, metat) local h = base.setmetatable({ c = c }, metat)
-- create finalized try -- create finalized try
h.try = socket.newtry(function() h:close() end) h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting -- set timeout before connecting
h.try(c:settimeout(TIMEOUT)) h.try(c:settimeout(_M.TIMEOUT))
h.try(c:connect(host, port or PORT)) h.try(c:connect(host, port))
-- here everything worked -- here everything worked
return h return h
end end
@@ -123,10 +140,11 @@ function metat.__index:sendrequestline(method, uri)
return self.try(self.c:send(reqline)) return self.try(self.c:send(reqline))
end end
function metat.__index:sendheaders(headers) function metat.__index:sendheaders(tosend)
local canonic = headers.canonic
local h = "\r\n" local h = "\r\n"
for i, v in base.pairs(headers) do for f, v in base.pairs(tosend) do
h = i .. ": " .. v .. "\r\n" .. h h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
end end
self.try(self.c:send(h)) self.try(self.c:send(h))
return 1 return 1
@@ -142,7 +160,17 @@ function metat.__index:sendbody(headers, source, step)
end end
function metat.__index:receivestatusline() function metat.__index:receivestatusline()
local status = self.try(self.c:receive()) local status,ec = self.try(self.c:receive(5))
-- identify HTTP/0.9 responses, which do not contain a status line
-- this is just a heuristic, but is what the RFC recommends
if status ~= "HTTP/" then
if ec == "timeout" then
return 408
end
return nil, status
end
-- otherwise proceed reading a status line
status = self.try(self.c:receive("*l", status))
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status) return self.try(base.tonumber(code), status)
end end
@@ -163,6 +191,12 @@ function metat.__index:receivebody(headers, sink, step)
sink, step)) sink, step))
end end
function metat.__index:receive09body(status, sink, step)
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
source(status)
return self.try(ltn12.pump.all(source, sink, step))
end
function metat.__index:close() function metat.__index:close()
return self.c:close() return self.c:close()
end end
@@ -173,7 +207,7 @@ end
local function adjusturi(reqt) local function adjusturi(reqt)
local u = reqt local u = reqt
-- if there is a proxy, we need the full url. otherwise, just a part. -- if there is a proxy, we need the full url. otherwise, just a part.
if not reqt.proxy and not PROXY then if not reqt.proxy and not _M.PROXY then
u = { u = {
path = socket.try(reqt.path, "invalid path 'nil'"), path = socket.try(reqt.path, "invalid path 'nil'"),
params = reqt.params, params = reqt.params,
@@ -185,7 +219,7 @@ local function adjusturi(reqt)
end end
local function adjustproxy(reqt) local function adjustproxy(reqt)
local proxy = reqt.proxy or PROXY local proxy = reqt.proxy or _M.PROXY
if proxy then if proxy then
proxy = url.parse(proxy) proxy = url.parse(proxy)
return proxy.host, proxy.port or 3128 return proxy.host, proxy.port or 3128
@@ -196,16 +230,30 @@ end
local function adjustheaders(reqt) local function adjustheaders(reqt)
-- default headers -- default headers
local host = reqt.host
local port = tostring(reqt.port)
if port ~= tostring(SCHEMES[reqt.scheme].port) then
host = host .. ':' .. port end
local lower = { local lower = {
["user-agent"] = USERAGENT, ["user-agent"] = _M.USERAGENT,
["host"] = reqt.host, ["host"] = host,
["connection"] = "close, TE", ["connection"] = "close, TE",
["te"] = "trailers" ["te"] = "trailers"
} }
-- if we have authentication information, pass it along -- if we have authentication information, pass it along
if reqt.user and reqt.password then if reqt.user and reqt.password then
lower["authorization"] = lower["authorization"] =
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) "Basic " .. (mime.b64(reqt.user .. ":" ..
url.unescape(reqt.password)))
end
-- if we have proxy authentication information, pass it along
local proxy = reqt.proxy or _M.PROXY
if proxy then
proxy = url.parse(proxy)
if proxy.user and proxy.password then
lower["proxy-authorization"] =
"Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password))
end
end end
-- override with user headers -- override with user headers
for i,v in base.pairs(reqt.headers or lower) do for i,v in base.pairs(reqt.headers or lower) do
@@ -216,10 +264,8 @@ end
-- default url parts -- default url parts
local default = { local default = {
host = "", path ="/"
port = PORT, , scheme = "http"
path ="/",
scheme = "http"
} }
local function adjustrequest(reqt) local function adjustrequest(reqt)
@@ -227,25 +273,39 @@ local function adjustrequest(reqt)
local nreqt = reqt.url and url.parse(reqt.url, default) or {} local nreqt = reqt.url and url.parse(reqt.url, default) or {}
-- explicit components override url -- explicit components override url
for i,v in base.pairs(reqt) do nreqt[i] = v end for i,v in base.pairs(reqt) do nreqt[i] = v end
if nreqt.port == "" then nreqt.port = 80 end -- default to scheme particulars
socket.try(nreqt.host and nreqt.host ~= "", local schemedefs, host, port, method
"invalid host '" .. base.tostring(nreqt.host) .. "'") = SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method
if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end
if not (port and port ~= '') then nreqt.port = schemedefs.port end
if not (method and method ~= '') then nreqt.method = 'GET' end
if not (host and host ~= "") then
socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
end
-- compute uri if user hasn't overriden -- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt) nreqt.uri = reqt.uri or adjusturi(nreqt)
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
-- adjust headers in request -- adjust headers in request
nreqt.headers = adjustheaders(nreqt) nreqt.headers = adjustheaders(nreqt)
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
return nreqt return nreqt
end end
local function shouldredirect(reqt, code, headers) local function shouldredirect(reqt, code, headers)
return headers.location and local location = headers.location
string.gsub(headers.location, "%s", "") ~= "" and if not location then return false end
(reqt.redirect ~= false) and location = string.gsub(location, "%s", "")
(code == 301 or code == 302) and if location == "" then return false end
local scheme = url.parse(location).scheme
if scheme and (not SCHEMES[scheme]) then return false end
-- avoid https downgrades
if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end
return (reqt.redirect ~= false) and
(code == 301 or code == 302 or code == 303 or code == 307) and
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
and (not reqt.nredirects or reqt.nredirects < 5) and ((false == reqt.maxredirects)
or ((reqt.nredirects or 0)
< (reqt.maxredirects or 5)))
end end
local function shouldreceivebody(reqt, code) local function shouldreceivebody(reqt, code)
@@ -258,44 +318,60 @@ end
-- forward declarations -- forward declarations
local trequest, tredirect local trequest, tredirect
function tredirect(reqt, location) --[[local]] function tredirect(reqt, location)
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
local newurl = url.absolute(reqt.url, location)
-- if switching schemes, reset port and create function
if url.parse(newurl).scheme ~= reqt.scheme then
reqt.port = nil
reqt.create = nil end
-- make new request
local result, code, headers, status = trequest { local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some url = newurl,
-- servers do not respect that
url = url.absolute(reqt.url, location),
source = reqt.source, source = reqt.source,
sink = reqt.sink, sink = reqt.sink,
headers = reqt.headers, headers = reqt.headers,
proxy = reqt.proxy, proxy = reqt.proxy,
maxredirects = reqt.maxredirects,
nredirects = (reqt.nredirects or 0) + 1, nredirects = (reqt.nredirects or 0) + 1,
create = reqt.create create = reqt.create
} }
-- pass location header back as a hint we redirected -- pass location header back as a hint we redirected
headers = headers or {}
headers.location = headers.location or location headers.location = headers.location or location
return result, code, headers, status return result, code, headers, status
end end
function trequest(reqt) --[[local]] function trequest(reqt)
-- we loop until we get what we want, or -- we loop until we get what we want, or
-- until we are sure there is no way to get it -- until we are sure there is no way to get it
local nreqt = adjustrequest(reqt) local nreqt = adjustrequest(reqt)
local h = open(nreqt.host, nreqt.port, nreqt.create) local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
-- send request line and headers -- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri) h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers) h:sendheaders(nreqt.headers)
local code = 100 -- if there is a body, send it
local headers, status
-- if there is a body, check for server status
if nreqt.source then if nreqt.source then
h:sendbody(nreqt.headers, nreqt.source, nreqt.step) h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
end end
local code, status = h:receivestatusline()
-- if it is an HTTP/0.9 server, simply get the body and we are done
if not code then
h:receive09body(status, nreqt.sink, nreqt.step)
return 1, 200
elseif code == 408 then
return 1, code
end
local headers
-- ignore any 100-continue messages -- ignore any 100-continue messages
while code == 100 do while code == 100 do
code, status = h:receivestatusline()
headers = h:receiveheaders() headers = h:receiveheaders()
code, status = h:receivestatusline()
end end
headers = h:receiveheaders()
-- at this point we should have a honest reply from the server -- at this point we should have a honest reply from the server
-- we can't redirect if we already used the source, so we report the error -- we can't redirect if we already used the source, so we report the error
if shouldredirect(nreqt, code, headers) and not nreqt.source then if shouldredirect(nreqt, code, headers) and not nreqt.source then
h:close() h:close()
return tredirect(reqt, headers.location) return tredirect(reqt, headers.location)
@@ -308,11 +384,13 @@ function trequest(reqt)
return 1, code, headers, status return 1, code, headers, status
end end
local function srequest(u, b) -- turns an url and a body into a generic request
local function genericform(u, b)
local t = {} local t = {}
local reqt = { local reqt = {
url = u, url = u,
sink = ltn12.sink.table(t) sink = ltn12.sink.table(t),
target = t
} }
if b then if b then
reqt.source = ltn12.source.string(b) reqt.source = ltn12.source.string(b)
@@ -322,11 +400,21 @@ local function srequest(u, b)
} }
reqt.method = "POST" reqt.method = "POST"
end end
local code, headers, status = socket.skip(1, trequest(reqt)) return reqt
return table.concat(t), code, headers, status
end end
request = socket.protect(function(reqt, body) _M.genericform = genericform
local function srequest(u, b)
local reqt = genericform(u, b)
local _, code, headers, status = trequest(reqt)
return table.concat(reqt.target), code, headers, status
end
_M.request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body) if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end else return trequest(reqt) end
end) end)
_M.schemes = SCHEMES
return _M

View File

@@ -1,36 +1,34 @@
/*=========================================================================*\ /*=========================================================================*\
* Internet domain functions * Internet domain functions
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <stdio.h> #include "luasocket.h"
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "inet.h" #include "inet.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes. * Internal function prototypes.
\*=========================================================================*/ \*=========================================================================*/
static int inet_global_toip(lua_State *L); static int inet_global_toip(lua_State *L);
static int inet_global_getaddrinfo(lua_State *L);
static int inet_global_tohostname(lua_State *L); static int inet_global_tohostname(lua_State *L);
static int inet_global_getnameinfo(lua_State *L);
static void inet_pushresolved(lua_State *L, struct hostent *hp); static void inet_pushresolved(lua_State *L, struct hostent *hp);
static int inet_global_gethostname(lua_State *L); static int inet_global_gethostname(lua_State *L);
/* DNS functions */ /* DNS functions */
static luaL_reg func[] = { static luaL_Reg func[] = {
{ "toip", inet_global_toip }, { "toip", inet_global_toip},
{ "tohostname", inet_global_tohostname }, { "getaddrinfo", inet_global_getaddrinfo},
{ "tohostname", inet_global_tohostname},
{ "getnameinfo", inet_global_getnameinfo},
{ "gethostname", inet_global_gethostname}, { "gethostname", inet_global_gethostname},
{ NULL, NULL} { NULL, NULL}
}; };
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes module * Initializes module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -38,7 +36,7 @@ int inet_open(lua_State *L)
{ {
lua_pushstring(L, "dns"); lua_pushstring(L, "dns");
lua_newtable(L); lua_newtable(L);
luaL_openlib(L, NULL, func, 0); luaL_setfuncs(L, func, 0);
lua_settable(L, -3); lua_settable(L, -3);
return 0; return 0;
} }
@@ -54,7 +52,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
struct in_addr addr; struct in_addr addr;
if (inet_aton(address, &addr)) if (inet_aton(address, &addr))
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
else else
return socket_gethostbyname(address, hp); return socket_gethostbyname(address, hp);
} }
@@ -64,7 +62,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int inet_global_tohostname(lua_State *L) { static int inet_global_tohostname(lua_State *L) {
const char *address = luaL_checkstring(L, 1); const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL; struct hostent *hp = NULL;
int err = inet_gethost(address, &hp); int err = inet_gethost(address, &hp);
if (err != IO_DONE) { if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
@@ -76,6 +74,50 @@ static int inet_global_tohostname(lua_State *L) {
return 2; return 2;
} }
static int inet_global_getnameinfo(lua_State *L) {
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
int i, ret;
struct addrinfo hints;
struct addrinfo *resolved, *iter;
const char *host = luaL_optstring(L, 1, NULL);
const char *serv = luaL_optstring(L, 2, NULL);
if (!(host || serv))
luaL_error(L, "host and serv cannot be both nil");
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
ret = getaddrinfo(host, serv, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
hbuf, host? (socklen_t) sizeof(hbuf): 0,
sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
if (host) {
lua_pushnumber(L, i);
lua_pushstring(L, hbuf);
lua_settable(L, -3);
}
}
freeaddrinfo(resolved);
if (serv) {
lua_pushstring(L, sbuf);
return 2;
} else {
return 1;
}
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name * Returns all information provided by the resolver given a host name
* or ip address * or ip address
@@ -83,7 +125,7 @@ static int inet_global_tohostname(lua_State *L) {
static int inet_global_toip(lua_State *L) static int inet_global_toip(lua_State *L)
{ {
const char *address = luaL_checkstring(L, 1); const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL; struct hostent *hp = NULL;
int err = inet_gethost(address, &hp); int err = inet_gethost(address, &hp);
if (err != IO_DONE) { if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
@@ -95,6 +137,81 @@ static int inet_global_toip(lua_State *L)
return 2; return 2;
} }
int inet_optfamily(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
int inet_optsocktype(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "stream", "dgram", NULL };
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
static int inet_global_getaddrinfo(lua_State *L)
{
const char *hostname = luaL_checkstring(L, 1);
struct addrinfo *iterator = NULL, *resolved = NULL;
struct addrinfo hints;
int i = 1, ret = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
char hbuf[NI_MAXHOST];
ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
if (ret){
freeaddrinfo(resolved);
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_pushnumber(L, i);
lua_newtable(L);
switch (iterator->ai_family) {
case AF_INET:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet");
lua_settable(L, -3);
break;
case AF_INET6:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet6");
lua_settable(L, -3);
break;
case AF_UNSPEC:
lua_pushliteral(L, "family");
lua_pushliteral(L, "unspec");
lua_settable(L, -3);
break;
default:
lua_pushliteral(L, "family");
lua_pushliteral(L, "unknown");
lua_settable(L, -3);
break;
}
lua_pushliteral(L, "addr");
lua_pushstring(L, hbuf);
lua_settable(L, -3);
lua_settable(L, -3);
i++;
}
freeaddrinfo(resolved);
return 1;
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Gets the host name * Gets the host name
@@ -105,7 +222,7 @@ static int inet_global_gethostname(lua_State *L)
name[256] = '\0'; name[256] = '\0';
if (gethostname(name, 256) < 0) { if (gethostname(name, 256) < 0) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, "gethostname failed"); lua_pushstring(L, socket_strerror(errno));
return 2; return 2;
} else { } else {
lua_pushstring(L, name); lua_pushstring(L, name);
@@ -113,43 +230,74 @@ static int inet_global_gethostname(lua_State *L)
} }
} }
/*=========================================================================*\ /*=========================================================================*\
* Lua methods * Lua methods
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Retrieves socket peer name * Retrieves socket peer name
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int inet_meth_getpeername(lua_State *L, p_socket ps) int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
{ {
struct sockaddr_in peer; int err;
struct sockaddr_storage peer;
socklen_t peer_len = sizeof(peer); socklen_t peer_len = sizeof(peer);
char name[INET6_ADDRSTRLEN];
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, "getpeername failed"); lua_pushstring(L, socket_strerror(errno));
} else { return 2;
lua_pushstring(L, inet_ntoa(peer.sin_addr));
lua_pushnumber(L, ntohs(peer.sin_port));
} }
return 2; err = getnameinfo((struct sockaddr *) &peer, peer_len,
name, INET6_ADDRSTRLEN,
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
lua_pushstring(L, name);
lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
switch (family) {
case AF_INET: lua_pushliteral(L, "inet"); break;
case AF_INET6: lua_pushliteral(L, "inet6"); break;
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
default: lua_pushliteral(L, "unknown"); break;
}
return 3;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Retrieves socket local name * Retrieves socket local name
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int inet_meth_getsockname(lua_State *L, p_socket ps) int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
{ {
struct sockaddr_in local; int err;
socklen_t local_len = sizeof(local); struct sockaddr_storage peer;
if (getsockname(*ps, (SA *) &local, &local_len) < 0) { socklen_t peer_len = sizeof(peer);
char name[INET6_ADDRSTRLEN];
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, "getsockname failed"); lua_pushstring(L, socket_strerror(errno));
} else { return 2;
lua_pushstring(L, inet_ntoa(local.sin_addr));
lua_pushnumber(L, ntohs(local.sin_port));
} }
return 2; err=getnameinfo((struct sockaddr *)&peer, peer_len,
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
lua_pushstring(L, name);
lua_pushstring(L, port);
switch (family) {
case AF_INET: lua_pushliteral(L, "inet"); break;
case AF_INET6: lua_pushliteral(L, "inet6"); break;
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
default: lua_pushliteral(L, "unknown"); break;
}
return 3;
} }
/*=========================================================================*\ /*=========================================================================*\
@@ -198,65 +346,151 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to create a new inet socket * Tries to create a new inet socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_trycreate(p_socket ps, int type) { const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
return socket_strerror(socket_create(ps, AF_INET, type, 0)); const char *err = socket_strerror(socket_create(ps, family, type, protocol));
if (err == NULL && family == AF_INET6) {
int yes = 1;
setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
}
return err;
}
/*-------------------------------------------------------------------------*\
* "Disconnects" a DGRAM socket
\*-------------------------------------------------------------------------*/
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
{
switch (family) {
case AF_INET: {
struct sockaddr_in sin;
memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_UNSPEC;
sin.sin_addr.s_addr = INADDR_ANY;
return socket_strerror(socket_connect(ps, (SA *) &sin,
sizeof(sin), tm));
}
case AF_INET6: {
struct sockaddr_in6 sin6;
struct in6_addr addrany = IN6ADDR_ANY_INIT;
memset((char *) &sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_UNSPEC;
sin6.sin6_addr = addrany;
return socket_strerror(socket_connect(ps, (SA *) &sin6,
sizeof(sin6), tm));
}
}
return NULL;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to connect to remote address (address, port) * Tries to connect to remote address (address, port)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_socket ps, const char *address, const char *inet_tryconnect(p_socket ps, int *family, const char *address,
unsigned short port, p_timeout tm) const char *serv, p_timeout tm, struct addrinfo *connecthints)
{ {
struct sockaddr_in remote; struct addrinfo *iterator = NULL, *resolved = NULL;
int err; const char *err = NULL;
memset(&remote, 0, sizeof(remote)); int current_family = *family;
remote.sin_family = AF_INET; /* try resolving */
remote.sin_port = htons(port); err = socket_gaistrerror(getaddrinfo(address, serv,
if (strcmp(address, "*")) { connecthints, &resolved));
if (!inet_aton(address, &remote.sin_addr)) { if (err != NULL) {
struct hostent *hp = NULL; if (resolved) freeaddrinfo(resolved);
struct in_addr **addr; return err;
err = socket_gethostbyname(address, &hp); }
if (err != IO_DONE) return socket_hoststrerror(err); for (iterator = resolved; iterator; iterator = iterator->ai_next) {
addr = (struct in_addr **) hp->h_addr_list; timeout_markstart(tm);
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); /* create new socket if necessary. if there was no
* bind, we need to create one for every new family
* that shows up while iterating. if there was a
* bind, all families will be the same and we will
* not enter this branch. */
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
socket_destroy(ps);
err = inet_trycreate(ps, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol);
if (err) continue;
current_family = iterator->ai_family;
/* set non-blocking before connect */
socket_setnonblocking(ps);
} }
} else remote.sin_family = AF_UNSPEC; /* try connecting to remote address */
err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm); err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
return socket_strerror(err); (socklen_t) iterator->ai_addrlen, tm));
/* if success or timeout is zero, break out of loop */
if (err == NULL || timeout_iszero(tm)) {
*family = current_family;
break;
}
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
/*-------------------------------------------------------------------------*\
* Tries to accept a socket
\*-------------------------------------------------------------------------*/
const char *inet_tryaccept(p_socket server, int family, p_socket client,
p_timeout tm) {
socklen_t len;
t_sockaddr_storage addr;
switch (family) {
case AF_INET6: len = sizeof(struct sockaddr_in6); break;
case AF_INET: len = sizeof(struct sockaddr_in); break;
default: len = sizeof(addr); break;
}
return socket_strerror(socket_accept(server, client, (SA *) &addr,
&len, tm));
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Tries to bind socket to (address, port) * Tries to bind socket to (address, port)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_trybind(p_socket ps, const char *address, unsigned short port) const char *inet_trybind(p_socket ps, int *family, const char *address,
{ const char *serv, struct addrinfo *bindhints) {
struct sockaddr_in local; struct addrinfo *iterator = NULL, *resolved = NULL;
int err; const char *err = NULL;
memset(&local, 0, sizeof(local)); int current_family = *family;
/* address is either wildcard or a valid ip address */ /* translate luasocket special values to C */
local.sin_addr.s_addr = htonl(INADDR_ANY); if (strcmp(address, "*") == 0) address = NULL;
local.sin_port = htons(port); if (!serv) serv = "0";
local.sin_family = AF_INET; /* try resolving */
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) { err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
struct hostent *hp = NULL; if (err) {
struct in_addr **addr; if (resolved) freeaddrinfo(resolved);
err = socket_gethostbyname(address, &hp); return err;
if (err != IO_DONE) return socket_hoststrerror(err);
addr = (struct in_addr **) hp->h_addr_list;
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
} }
err = socket_bind(ps, (SA *) &local, sizeof(local)); /* iterate over resolved addresses until one is good */
if (err != IO_DONE) socket_destroy(ps); for (iterator = resolved; iterator; iterator = iterator->ai_next) {
return socket_strerror(err); if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
socket_destroy(ps);
err = inet_trycreate(ps, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol);
if (err) continue;
current_family = iterator->ai_family;
}
/* try binding to local address */
err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen));
/* keep trying unless bind succeeded */
if (err == NULL) {
*family = current_family;
/* set to non-blocking after bind */
socket_setnonblocking(ps);
break;
}
}
/* cleanup and return error */
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Some systems do not provide this so that we provide our own. It's not * Some systems do not provide these so that we provide our own.
* marvelously fast, but it works just fine.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#ifdef INET_ATON #ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp) int inet_aton(const char *cp, struct in_addr *inp)
{ {
unsigned int a = 0, b = 0, c = 0, d = 0; unsigned int a = 0, b = 0, c = 0, d = 0;
@@ -278,4 +512,26 @@ int inet_aton(const char *cp, struct in_addr *inp)
} }
#endif #endif
#ifdef LUASOCKET_INET_PTON
int inet_pton(int af, const char *src, void *dst)
{
struct addrinfo hints, *res;
int ret = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = af;
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
if (af == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
} else if (af == AF_INET6) {
struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
} else {
ret = -1;
}
freeaddrinfo(res);
return ret;
}
#endif

View File

@@ -1,42 +1,56 @@
#ifndef INET_H #ifndef INET_H
#define INET_H #define INET_H
/*=========================================================================*\ /*=========================================================================*\
* Internet domain functions * Internet domain functions
* LuaSocket toolkit * LuaSocket toolkit
* *
* This module implements the creation and connection of internet domain * This module implements the creation and connection of internet domain
* sockets, on top of the socket.h interface, and the interface of with the * sockets, on top of the socket.h interface, and the interface of with the
* resolver. * resolver.
* *
* The function inet_aton is provided for the platforms where it is not * The function inet_aton is provided for the platforms where it is not
* available. The module also implements the interface of the internet * available. The module also implements the interface of the internet
* getpeername and getsockname functions as seen by Lua programs. * getpeername and getsockname functions as seen by Lua programs.
* *
* The Lua functions toip and tohostname are also implemented here. * The Lua functions toip and tohostname are also implemented here.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "socket.h" #include "socket.h"
#include "timeout.h" #include "timeout.h"
#ifdef _WIN32 #ifdef _WIN32
#define INET_ATON #define LUASOCKET_INET_ATON
#endif
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif #endif
int inet_open(lua_State *L); int inet_open(lua_State *L);
const char *inet_trycreate(p_socket ps, int type); int inet_optfamily(lua_State* L, int narg, const char* def);
const char *inet_tryconnect(p_socket ps, const char *address, int inet_optsocktype(lua_State* L, int narg, const char* def);
unsigned short port, p_timeout tm);
const char *inet_trybind(p_socket ps, const char *address,
unsigned short port);
int inet_meth_getpeername(lua_State *L, p_socket ps); int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
int inet_meth_getsockname(lua_State *L, p_socket ps); int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
#ifdef INET_ATON const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints);
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints);
#ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp); int inet_aton(const char *cp, struct in_addr *inp);
#endif #endif
#ifdef LUASOCKET_INET_PTON
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
int inet_pton(int af, const char *src, void *dst);
#endif
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* INET_H */ #endif /* INET_H */

View File

@@ -1,14 +1,10 @@
/*=========================================================================*\ /*=========================================================================*\
* Input/Output abstraction * Input/Output abstraction
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "luasocket.h"
#include "io.h" #include "io.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes C structure * Initializes C structure
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -27,6 +23,6 @@ const char *io_strerror(int err) {
case IO_DONE: return NULL; case IO_DONE: return NULL;
case IO_CLOSED: return "closed"; case IO_CLOSED: return "closed";
case IO_TIMEOUT: return "timeout"; case IO_TIMEOUT: return "timeout";
default: return "unknown error"; default: return "unknown error";
} }
} }

View File

@@ -11,12 +11,8 @@
* *
* The module socket.h implements this interface, and thus the module tcp.h * The module socket.h implements this interface, and thus the module tcp.h
* is very simple. * is very simple.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <stdio.h> #include "luasocket.h"
#include "lua.h"
#include "timeout.h" #include "timeout.h"
/* IO error codes */ /* IO error codes */
@@ -60,8 +56,15 @@ typedef struct t_io_ {
} t_io; } t_io;
typedef t_io *p_io; typedef t_io *p_io;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
const char *io_strerror(int err); const char *io_strerror(int err);
#endif /* IO_H */ #ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* IO_H */

View File

@@ -2,7 +2,6 @@
-- LTN12 - Filters, sources, sinks and pumps. -- LTN12 - Filters, sources, sinks and pumps.
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -10,17 +9,25 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local string = require("string") local string = require("string")
local table = require("table") local table = require("table")
local unpack = unpack or table.unpack
local base = _G local base = _G
module("ltn12") local _M = {}
if module then -- heuristic for exporting a global package table
ltn12 = _M
end
local filter,source,sink,pump = {},{},{},{}
filter = {} _M.filter = filter
source = {} _M.source = source
sink = {} _M.sink = sink
pump = {} _M.pump = pump
local unpack = unpack or table.unpack
local select = base.select
-- 2048 seems to be better in windows... -- 2048 seems to be better in windows...
BLOCKSIZE = 2048 _M.BLOCKSIZE = 2048
_VERSION = "LTN12 1.0.1" _M._VERSION = "LTN12 1.0.3"
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Filter stuff -- Filter stuff
@@ -38,7 +45,8 @@ end
-- chains a bunch of filters together -- chains a bunch of filters together
-- (thanks to Wim Couwenberg) -- (thanks to Wim Couwenberg)
function filter.chain(...) function filter.chain(...)
local n = table.getn(arg) local arg = {...}
local n = base.select('#',...)
local top, index = 1, 1 local top, index = 1, 1
local retry = "" local retry = ""
return function(chunk) return function(chunk)
@@ -89,7 +97,7 @@ end
function source.file(handle, io_err) function source.file(handle, io_err)
if handle then if handle then
return function() return function()
local chunk = handle:read(BLOCKSIZE) local chunk = handle:read(_M.BLOCKSIZE)
if not chunk then handle:close() end if not chunk then handle:close() end
return chunk return chunk
end end
@@ -112,14 +120,24 @@ function source.string(s)
if s then if s then
local i = 1 local i = 1
return function() return function()
local chunk = string.sub(s, i, i+BLOCKSIZE-1) local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
i = i + BLOCKSIZE i = i + _M.BLOCKSIZE
if chunk ~= "" then return chunk if chunk ~= "" then return chunk
else return nil end else return nil end
end end
else return source.empty() end else return source.empty() end
end end
-- creates table source
function source.table(t)
base.assert('table' == type(t))
local i = 0
return function()
i = i + 1
return t[i]
end
end
-- creates rewindable source -- creates rewindable source
function source.rewind(src) function source.rewind(src)
base.assert(src) base.assert(src)
@@ -135,7 +153,9 @@ function source.rewind(src)
end end
end end
function source.chain(src, f) -- chains a source with one or several filter(s)
function source.chain(src, f, ...)
if ... then f=filter.chain(f, ...) end
base.assert(src and f) base.assert(src and f)
local last_in, last_out = "", "" local last_in, last_out = "", ""
local state = "feeding" local state = "feeding"
@@ -186,6 +206,7 @@ end
-- other, as if they were concatenated -- other, as if they were concatenated
-- (thanks to Wim Couwenberg) -- (thanks to Wim Couwenberg)
function source.cat(...) function source.cat(...)
local arg = {...}
local src = table.remove(arg, 1) local src = table.remove(arg, 1)
return function() return function()
while src do while src do
@@ -249,8 +270,13 @@ function sink.error(err)
end end
end end
-- chains a sink with a filter -- chains a sink with one or several filter(s)
function sink.chain(f, snk) function sink.chain(f, snk, ...)
if ... then
local args = { f, snk, ... }
snk = table.remove(args, #args)
f = filter.chain(unpack(args))
end
base.assert(f and snk) base.assert(f and snk)
return function(chunk, err) return function(chunk, err)
if chunk ~= "" then if chunk ~= "" then
@@ -290,3 +316,4 @@ function pump.all(src, snk, step)
end end
end end
return _M

24
src/luasocket.c Normal file → Executable file
View File

@@ -10,23 +10,8 @@
* involved in setting up both client and server connections. The provided * involved in setting up both client and server connections. The provided
* IO routines, however, follow the Lua style, being very similar to the * IO routines, however, follow the Lua style, being very similar to the
* standard Lua read and write functions. * standard Lua read and write functions.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
/*=========================================================================*\
* Standard include files
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
/*=========================================================================*\
* LuaSocket includes
\*=========================================================================*/
#include "luasocket.h" #include "luasocket.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "except.h" #include "except.h"
@@ -47,7 +32,7 @@ static int base_open(lua_State *L);
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Modules and functions * Modules and functions
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static const luaL_reg mod[] = { static const luaL_Reg mod[] = {
{"auxiliar", auxiliar_open}, {"auxiliar", auxiliar_open},
{"except", except_open}, {"except", except_open},
{"timeout", timeout_open}, {"timeout", timeout_open},
@@ -59,7 +44,7 @@ static const luaL_reg mod[] = {
{NULL, NULL} {NULL, NULL}
}; };
static luaL_reg func[] = { static luaL_Reg func[] = {
{"skip", global_skip}, {"skip", global_skip},
{"__unload", global_unload}, {"__unload", global_unload},
{NULL, NULL} {NULL, NULL}
@@ -69,7 +54,7 @@ static luaL_reg func[] = {
* Skip a few arguments * Skip a few arguments
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int global_skip(lua_State *L) { static int global_skip(lua_State *L) {
int amount = luaL_checkint(L, 1); int amount = (int) luaL_checkinteger(L, 1);
int ret = lua_gettop(L) - amount - 1; int ret = lua_gettop(L) - amount - 1;
return ret >= 0 ? ret : 0; return ret >= 0 ? ret : 0;
} }
@@ -89,7 +74,8 @@ static int global_unload(lua_State *L) {
static int base_open(lua_State *L) { static int base_open(lua_State *L) {
if (socket_open()) { if (socket_open()) {
/* export functions (and leave namespace table on top of stack) */ /* export functions (and leave namespace table on top of stack) */
luaL_openlib(L, "socket", func, 0); lua_newtable(L);
luaL_setfuncs(L, func, 0);
#ifdef LUASOCKET_DEBUG #ifdef LUASOCKET_DEBUG
lua_pushstring(L, "_DEBUG"); lua_pushstring(L, "_DEBUG");
lua_pushboolean(L, 1); lua_pushboolean(L, 1);

View File

@@ -5,24 +5,28 @@
* Networking support for the Lua language * Networking support for the Lua language
* Diego Nehab * Diego Nehab
* 9/11/1999 * 9/11/1999
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------* \
* Current socket library version * Current socket library version
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 2.0.2" #define LUASOCKET_VERSION "LuaSocket 3.0-rc1"
#define LUASOCKET_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab" #define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
#define LUASOCKET_AUTHORS "Diego Nehab"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* This macro prefixes all exported API functions * This macro prefixes all exported API functions
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#ifndef LUASOCKET_API #ifndef LUASOCKET_API
#define LUASOCKET_API extern #ifdef _WIN32
#define LUASOCKET_API __declspec(dllexport)
#else
#define LUASOCKET_API __attribute__ ((visibility ("default")))
#endif #endif
#endif
#include "lua.h"
#include "lauxlib.h"
#include "compat.h"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes the library. * Initializes the library.

497
src/makefile Normal file → Executable file
View File

@@ -1,90 +1,461 @@
#------ # luasocket src/makefile
# Load configuration
# #
include ../config # Definitions in this section can be overriden on the command line or in the
# environment.
#
# These are equivalent:
#
# export PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
# make
#
# and
#
# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
# PLAT: linux macosx win32 win64 mingw
# platform to build for
PLAT?=linux
# LUAV: 5.1 5.2
# lua version to build against
LUAV?=5.1
# MYCFLAGS: to be set by user if needed
MYCFLAGS?=
# MYLDFLAGS: to be set by user if needed
MYLDFLAGS?=
# DEBUG: NODEBUG DEBUG
# debug mode causes luasocket to collect and returns timing information useful
# for testing and debugging luasocket itself
DEBUG?=NODEBUG
# where lua headers are found for macosx builds
# LUAINC_macosx:
# /opt/local/include
LUAINC_macosx_base?=/opt/local/include
LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) $(LUAINC_macosx_base)/lua$(LUAV) $(LUAINC_macosx_base)/lua-$(LUAV)
# FIXME default should this default to fink or to macports?
# What happens when more than one Lua version is installed?
LUAPREFIX_macosx?=/opt/local
CDIR_macosx?=lib/lua/$(LUAV)
LDIR_macosx?=share/lua/$(LUAV)
# LUAINC_linux:
# /usr/include/lua$(LUAV)
# /usr/local/include
# /usr/local/include/lua$(LUAV)
# where lua headers are found for linux builds
LUAINC_linux_base?=/usr/include
LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) $(LUAINC_linux_base)/lua$(LUAV)
LUAPREFIX_linux?=/usr/local
CDIR_linux?=lib/lua/$(LUAV)
LDIR_linux?=share/lua/$(LUAV)
# LUAINC_freebsd:
# /usr/local/include/lua$(LUAV)
# where lua headers are found for freebsd builds
LUAINC_freebsd_base?=/usr/local/include/
LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua/$(LUAV) $(LUAINC_freebsd_base)/lua$(LUAV)
LUAPREFIX_freebsd?=/usr/local/
CDIR_freebsd?=lib/lua/$(LUAV)
LDIR_freebsd?=share/lua/$(LUAV)
# where lua headers are found for mingw builds
# LUAINC_mingw:
# /opt/local/include
LUAINC_mingw_base?=/usr/include
LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) $(LUAINC_mingw_base)/lua$(LUAV)
LUALIB_mingw_base?=/usr/bin
LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll
LUAPREFIX_mingw?=/usr
CDIR_mingw?=lua/$(LUAV)
LDIR_mingw?=lua/$(LUAV)/lua
# LUAINC_win32:
# LUALIB_win32:
# where lua headers and libraries are found for win32 builds
LUAPREFIX_win32?=
LUAINC_win32?=$(LUAPREFIX_win32)/include/lua/$(LUAV) $(LUAPREFIX_win32)/include/lua$(LUAV)
PLATFORM_win32?=Release
CDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)
LDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)/lua
LUALIB_win32?=$(LUAPREFIX_win32)/lib/lua/$(LUAV)/$(PLATFORM_win32)
LUALIBNAME_win32?=lua$(subst .,,$(LUAV)).lib
# LUAINC_win64:
# LUALIB_win64:
# where lua headers and libraries are found for win64 builds
LUAPREFIX_win64?=
LUAINC_win64?=$(LUAPREFIX_win64)/include/lua/$(LUAV) $(LUAPREFIX_win64)/include/lua$(LUAV)
PLATFORM_win64?=x64/Release
CDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)
LDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)/lua
LUALIB_win64?=$(LUAPREFIX_win64)/lib/lua/$(LUAV)/$(PLATFORM_win64)
LUALIBNAME_win64?=lua$(subst .,,$(LUAV)).lib
# LUAINC_solaris:
LUAINC_solaris_base?=/usr/include
LUAINC_solaris?=$(LUAINC_solaris_base)/lua/$(LUAV) $(LUAINC_solaris_base)/lua$(LUAV)
LUAPREFIX_solaris?=/usr/local
CDIR_solaris?=lib/lua/$(LUAV)
LDIR_solaris?=share/lua/$(LUAV)
# prefix: /usr/local /usr /opt/local /sw
# the top of the default install tree
prefix?=$(LUAPREFIX_$(PLAT))
CDIR?=$(CDIR_$(PLAT))
LDIR?=$(LDIR_$(PLAT))
# DESTDIR: (no default)
# used by package managers to install into a temporary destination
DESTDIR?=
#------ #------
# Hopefully no need to change anything below this line # Definitions below can be overridden on the make command line, but
# shouldn't have to be.
#------
# Install directories
# #
INSTALL_DIR=install -d
INSTALL_DATA=install -m644
INSTALL_EXEC=install
INSTALL_TOP=$(DESTDIR)$(prefix)
INSTALL_TOP_LDIR=$(INSTALL_TOP)/$(LDIR)
INSTALL_TOP_CDIR=$(INSTALL_TOP)/$(CDIR)
INSTALL_SOCKET_LDIR=$(INSTALL_TOP_LDIR)/socket
INSTALL_SOCKET_CDIR=$(INSTALL_TOP_CDIR)/socket
INSTALL_MIME_LDIR=$(INSTALL_TOP_LDIR)/mime
INSTALL_MIME_CDIR=$(INSTALL_TOP_CDIR)/mime
print:
@echo PLAT=$(PLAT)
@echo LUAV=$(LUAV)
@echo DEBUG=$(DEBUG)
@echo prefix=$(prefix)
@echo LUAINC_$(PLAT)=$(LUAINC_$(PLAT))
@echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT))
@echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR)
@echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR)
@echo CFLAGS=$(CFLAGS)
@echo LDFLAGS=$(LDFLAGS)
#------
# Supported platforms
#
PLATS= macosx linux win32 win64 mingw solaris
#------
# Compiler and linker settings
# for Mac OS X
SO_macosx=so
O_macosx=o
CC_macosx=gcc
DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
CFLAGS_macosx=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
LD_macosx=gcc
SOCKET_macosx=usocket.o
#------
# Compiler and linker settings
# for Linux
SO_linux=so
O_linux=o
CC_linux=gcc
DEF_linux=-DLUASOCKET_$(DEBUG)
CFLAGS_linux=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_linux=-O -shared -fpic -o
LD_linux=gcc
SOCKET_linux=usocket.o
#------
# Compiler and linker settings
# for FreeBSD
SO_freebsd=so
O_freebsd=o
CC_freebsd=gcc
DEF_freebsd=-DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
CFLAGS_freebsd=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_freebsd=-O -shared -fpic -o
LD_freebsd=gcc
SOCKET_freebsd=usocket.o
#------
# Compiler and linker settings
# for Solaris
SO_solaris=so
O_solaris=o
CC_solaris=gcc
DEF_solaris=-DLUASOCKET_$(DEBUG)
CFLAGS_solaris=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o
LD_solaris=gcc
SOCKET_solaris=usocket.o
#------
# Compiler and linker settings
# for MingW
SO_mingw=dll
O_mingw=o
CC_mingw=gcc
DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) \
-DWINVER=0x0501
CFLAGS_mingw=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
LD_mingw=gcc
SOCKET_mingw=wsocket.o
#------
# Compiler and linker settings
# for Win32
SO_win32=dll
O_win32=obj
CC_win32=cl
DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
//D "_CRT_SECURE_NO_WARNINGS" \
//D "_WINDLL" \
//D "LUASOCKET_$(DEBUG)"
CFLAGS_win32=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
//MANIFEST //MANIFESTFILE:"intermediate.manifest" \
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
//MACHINE:X86 /LIBPATH:"$(LUALIB)" \
$(LUALIBNAME_win32) ws2_32.lib //OUT:
LD_win32=cl
SOCKET_win32=wsocket.obj
#------
# Compiler and linker settings
# for Win64
SO_win64=dll
O_win64=obj
CC_win64=cl
DEF_win64= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
//D "_CRT_SECURE_NO_WARNINGS" \
//D "_WINDLL" \
//D "LUASOCKET_$(DEBUG)"
CFLAGS_win64=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
LDFLAGS_win64= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
//MANIFEST //MANIFESTFILE:"intermediate.manifest" \
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
/LIBPATH:"$(LUALIB)" \
$(LUALIBNAME_win64) ws2_32.lib //OUT:
LD_win64=cl
SOCKET_win64=wsocket.obj
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) //Fo"$@" //c $<
#------
# Output file names
#
SO=$(SO_$(PLAT))
O=$(O_$(PLAT))
SOCKET_V=3.0-rc1
MIME_V=1.0.3
SOCKET_SO=socket-$(SOCKET_V).$(SO)
MIME_SO=mime-$(MIME_V).$(SO)
UNIX_SO=unix.$(SO)
SERIAL_SO=serial.$(SO)
SOCKET=$(SOCKET_$(PLAT))
#------
# Settings selected for platform
#
CC=$(CC_$(PLAT))
DEF=$(DEF_$(PLAT))
CFLAGS=$(MYCFLAGS) $(CFLAGS_$(PLAT))
LDFLAGS=$(MYLDFLAGS) $(LDFLAGS_$(PLAT))
LD=$(LD_$(PLAT))
LUAINC= $(LUAINC_$(PLAT))
LUALIB= $(LUALIB_$(PLAT))
#------ #------
# Modules belonging to socket-core # Modules belonging to socket-core
# #
SOCKET_OBJS= \
#$(COMPAT)/compat-5.1.o \ luasocket.$(O) \
timeout.$(O) \
SOCKET_OBJS:= \ buffer.$(O) \
luasocket.o \ io.$(O) \
timeout.o \ auxiliar.$(O) \
buffer.o \ compat.$(O) \
io.o \ options.$(O) \
auxiliar.o \ inet.$(O) \
options.o \ $(SOCKET) \
inet.o \ except.$(O) \
tcp.o \ select.$(O) \
udp.o \ tcp.$(O) \
except.o \ udp.$(O)
select.o \
usocket.o
#------ #------
# Modules belonging mime-core # Modules belonging mime-core
# #
#$(COMPAT)/compat-5.1.o \ MIME_OBJS= \
mime.$(O) \
MIME_OBJS:=\ compat.$(O)
mime.o
#------ #------
# Modules belonging unix (local domain sockets) # Modules belonging unix (local domain sockets)
# #
UNIX_OBJS:=\ UNIX_OBJS=\
buffer.o \ buffer.$(O) \
auxiliar.o \ auxiliar.$(O) \
options.o \ options.$(O) \
timeout.o \ timeout.$(O) \
io.o \ io.$(O) \
usocket.o \ usocket.$(O) \
unix.o unixstream.$(O) \
unixdgram.$(O) \
compat.$(O) \
unix.$(O)
all: $(SOCKET_SO) $(MIME_SO) #------
# Modules belonging to serial (device streams)
#
SERIAL_OBJS=\
buffer.$(O) \
compat.$(O) \
auxiliar.$(O) \
options.$(O) \
timeout.$(O) \
io.$(O) \
usocket.$(O) \
serial.$(O)
#------
# Files to install
#
TO_SOCKET_LDIR= \
http.lua \
url.lua \
tp.lua \
ftp.lua \
headers.lua \
smtp.lua
TO_TOP_LDIR= \
ltn12.lua \
socket.lua \
mime.lua
#------
# Targets
#
default: $(PLAT)
freebsd:
$(MAKE) all-unix PLAT=freebsd
macosx:
$(MAKE) all-unix PLAT=macosx
win32:
$(MAKE) all PLAT=win32
win64:
$(MAKE) all PLAT=win64
linux:
$(MAKE) all-unix PLAT=linux
mingw:
$(MAKE) all PLAT=mingw
solaris:
$(MAKE) all-unix PLAT=solaris
none:
@echo "Please run"
@echo " make PLATFORM"
@echo "where PLATFORM is one of these:"
@echo " $(PLATS)"
all: $(SOCKET_SO) $(MIME_SO)
$(SOCKET_SO): $(SOCKET_OBJS) $(SOCKET_SO): $(SOCKET_OBJS)
$(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS) $(LD) $(SOCKET_OBJS) $(LDFLAGS)$@
$(MIME_SO): $(MIME_OBJS) $(MIME_SO): $(MIME_OBJS)
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS) $(LD) $(MIME_OBJS) $(LDFLAGS)$@
all-unix: all $(UNIX_SO) $(SERIAL_SO)
$(UNIX_SO): $(UNIX_OBJS) $(UNIX_SO): $(UNIX_OBJS)
$(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS) $(LD) $(UNIX_OBJS) $(LDFLAGS)$@
$(SERIAL_SO): $(SERIAL_OBJS)
$(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
install:
$(INSTALL_DIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
$(INSTALL_DATA) $(TO_SOCKET_LDIR) $(INSTALL_SOCKET_LDIR)
$(INSTALL_DIR) $(INSTALL_SOCKET_CDIR)
$(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_CDIR)/core.$(SO)
$(INSTALL_DIR) $(INSTALL_MIME_CDIR)
$(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_CDIR)/core.$(SO)
install-unix: install
$(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_CDIR)/$(UNIX_SO)
$(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_CDIR)/$(SERIAL_SO)
local:
$(MAKE) install INSTALL_TOP_CDIR=.. INSTALL_TOP_LDIR=..
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS) $(SERIAL_OBJS)
rm -f $(MIME_SO) $(UNIX_SO) $(SERIAL_SO) $(MIME_OBJS) $(UNIX_OBJS)
.PHONY: all $(PLATS) default clean echo none
#------ #------
# List of dependencies # List of dependencies
# #
auxiliar.o: auxiliar.c auxiliar.h compat.$(O): compat.c compat.h
buffer.o: buffer.c buffer.h io.h timeout.h auxiliar.$(O): auxiliar.c auxiliar.h
except.o: except.c except.h buffer.$(O): buffer.c buffer.h io.h timeout.h
inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h except.$(O): except.c except.h
io.o: io.c io.h timeout.h inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
luasocket.o: luasocket.c luasocket.h auxiliar.h except.h timeout.h \ io.$(O): io.c io.h timeout.h
buffer.h io.h inet.h socket.h usocket.h tcp.h udp.h select.h luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
mime.o: mime.c mime.h timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \ udp.h select.h
usocket.h inet.h mime.$(O): mime.c mime.h
select.o: select.c socket.h io.h timeout.h usocket.h select.h options.$(O): options.c auxiliar.h options.h socket.h io.h \
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \ timeout.h usocket.h inet.h
options.h tcp.h buffer.h select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
timeout.o: timeout.c auxiliar.h timeout.h serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \ options.h unix.h buffer.h
options.h udp.h tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h options.h \ inet.h options.h tcp.h buffer.h
unix.h buffer.h timeout.$(O): timeout.c auxiliar.h timeout.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h udp.$(O): udp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h udp.h
clean: unix.$(O): unix.c auxiliar.h socket.h io.h timeout.h usocket.h \
rm -f $(SOCKET_SO) $(SOCKET_OBJS) options.h unix.h buffer.h
rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS) usocket.$(O): usocket.c socket.h io.h timeout.h usocket.h
wsocket.$(O): wsocket.c socket.h io.h timeout.h usocket.h
#------
# End of makefile configuration
#

View File

@@ -1,14 +1,16 @@
local Public = {} local _M = {}
mbox = Public if module then
mbox = _M
end
function Public.split_message(message_s) function _M.split_message(message_s)
local message = {} local message = {}
message_s = string.gsub(message_s, "\r\n", "\n") message_s = string.gsub(message_s, "\r\n", "\n")
string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end) string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end) string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
if not message.body then if not message.body then
string.gsub(message_s, "^\n(.*)", function (b) message.body = b end) string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
end end
if not message.headers and not message.body then if not message.headers and not message.body then
message.headers = message_s message.headers = message_s
@@ -16,7 +18,7 @@ function Public.split_message(message_s)
return message.headers or "", message.body or "" return message.headers or "", message.body or ""
end end
function Public.split_headers(headers_s) function _M.split_headers(headers_s)
local headers = {} local headers = {}
headers_s = string.gsub(headers_s, "\r\n", "\n") headers_s = string.gsub(headers_s, "\r\n", "\n")
headers_s = string.gsub(headers_s, "\n[ ]+", " ") headers_s = string.gsub(headers_s, "\n[ ]+", " ")
@@ -24,18 +26,18 @@ function Public.split_headers(headers_s)
return headers return headers
end end
function Public.parse_header(header_s) function _M.parse_header(header_s)
header_s = string.gsub(header_s, "\n[ ]+", " ") header_s = string.gsub(header_s, "\n[ ]+", " ")
header_s = string.gsub(header_s, "\n+", "") header_s = string.gsub(header_s, "\n+", "")
local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
return name, value return name, value
end end
function Public.parse_headers(headers_s) function _M.parse_headers(headers_s)
local headers_t = Public.split_headers(headers_s) local headers_t = _M.split_headers(headers_s)
local headers = {} local headers = {}
for i = 1, table.getn(headers_t) do for i = 1, #headers_t do
local name, value = Public.parse_header(headers_t[i]) local name, value = _M.parse_header(headers_t[i])
if name then if name then
name = string.lower(name) name = string.lower(name)
if headers[name] then if headers[name] then
@@ -46,7 +48,7 @@ function Public.parse_headers(headers_s)
return headers return headers
end end
function Public.parse_from(from) function _M.parse_from(from)
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
if not address then if not address then
_, __, address = string.find(from, "%s*(.+)%s*") _, __, address = string.find(from, "%s*(.+)%s*")
@@ -54,35 +56,37 @@ function Public.parse_from(from)
name = name or "" name = name or ""
address = address or "" address = address or ""
if name == "" then name = address end if name == "" then name = address end
name = string.gsub(name, '"', "") name = string.gsub(name, '"', "")
return name, address return name, address
end end
function Public.split_mbox(mbox_s) function _M.split_mbox(mbox_s)
mbox = {} local mbox = {}
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
local nj, i, j = 1, 1, 1 local nj, i, j = 1, 1, 1
while 1 do while 1 do
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
if not i then break end if not i then break end
local message = string.sub(mbox_s, j, i-1) local message = string.sub(mbox_s, j, i-1)
table.insert(mbox, message) table.insert(mbox, message)
j = nj+1 j = nj+1
end end
return mbox return mbox
end end
function Public.parse(mbox_s) function _M.parse(mbox_s)
local mbox = Public.split_mbox(mbox_s) local mbox = _M.split_mbox(mbox_s)
for i = 1, table.getn(mbox) do for i = 1, #mbox do
mbox[i] = Public.parse_message(mbox[i]) mbox[i] = _M.parse_message(mbox[i])
end end
return mbox return mbox
end end
function Public.parse_message(message_s) function _M.parse_message(message_s)
local message = {} local message = {}
message.headers, message.body = Public.split_message(message_s) message.headers, message.body = _M.split_message(message_s)
message.headers = Public.parse_headers(message.headers) message.headers = _M.parse_headers(message.headers)
return message return message
end end
return _M

379
src/mime.c Normal file → Executable file
View File

@@ -1,19 +1,11 @@
/*=========================================================================*\ /*=========================================================================*\
* MIME support functions * MIME support functions
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
#include "mime.h" #include "mime.h"
#include <string.h>
#include <ctype.h>
/*=========================================================================*\ /*=========================================================================*\
* Don't want to trust escape character constants * Don't want to trust escape character constants
@@ -35,20 +27,20 @@ static int mime_global_eol(lua_State *L);
static int mime_global_dot(lua_State *L); static int mime_global_dot(lua_State *L);
static size_t dot(int c, size_t state, luaL_Buffer *buffer); static size_t dot(int c, size_t state, luaL_Buffer *buffer);
static void b64setup(UC *b64unbase); //static void b64setup(UC *base);
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static void qpsetup(UC *qpclass, UC *qpunbase); //static void qpsetup(UC *class, UC *unbase);
static void qpquote(UC c, luaL_Buffer *buffer); static void qpquote(UC c, luaL_Buffer *buffer);
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t qpencode(UC c, UC *input, size_t size, static size_t qpencode(UC c, UC *input, size_t size,
const char *marker, luaL_Buffer *buffer); const char *marker, luaL_Buffer *buffer);
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
/* code support functions */ /* code support functions */
static luaL_reg func[] = { static luaL_Reg func[] = {
{ "dot", mime_global_dot }, { "dot", mime_global_dot },
{ "b64", mime_global_b64 }, { "b64", mime_global_b64 },
{ "eol", mime_global_eol }, { "eol", mime_global_eol },
@@ -63,17 +55,111 @@ static luaL_reg func[] = {
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Quoted-printable globals * Quoted-printable globals
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static UC qpclass[256];
static UC qpbase[] = "0123456789ABCDEF";
static UC qpunbase[256];
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
static const UC qpclass[] = {
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
};
static const UC qpbase[] = "0123456789ABCDEF";
static const UC qpunbase[] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255
};
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Base64 globals * Base64 globals
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static const UC b64base[] = static const UC b64base[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static UC b64unbase[256];
static const UC b64unbase[] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255
};
/*=========================================================================*\ /*=========================================================================*\
* Exported functions * Exported functions
@@ -81,16 +167,17 @@ static UC b64unbase[256];
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes module * Initializes module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
MIME_API int luaopen_mime_core(lua_State *L) LUASOCKET_API int luaopen_mime_core(lua_State *L)
{ {
luaL_openlib(L, "mime", func, 0); lua_newtable(L);
luaL_setfuncs(L, func, 0);
/* make version string available to scripts */ /* make version string available to scripts */
lua_pushstring(L, "_VERSION"); lua_pushstring(L, "_VERSION");
lua_pushstring(L, MIME_VERSION); lua_pushstring(L, MIME_VERSION);
lua_rawset(L, -3); lua_rawset(L, -3);
/* initialize lookup tables */ /* initialize lookup tables */
qpsetup(qpclass, qpunbase); // qpsetup(qpclass, qpunbase);
b64setup(b64unbase); // b64setup(b64unbase);
return 1; return 1;
} }
@@ -100,15 +187,15 @@ MIME_API int luaopen_mime_core(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Incrementaly breaks a string into lines. The string can have CRLF breaks. * Incrementaly breaks a string into lines. The string can have CRLF breaks.
* A, n = wrp(l, B, length) * A, n = wrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes. * A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B. * 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A. * 'n' is the number of bytes left in the last line of A.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int mime_global_wrp(lua_State *L) static int mime_global_wrp(lua_State *L)
{ {
size_t size = 0; size_t size = 0;
int left = (int) luaL_checknumber(L, 1); int left = (int) luaL_checknumber(L, 1);
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
const UC *last = input + size; const UC *last = input + size;
int length = (int) luaL_optnumber(L, 3, 76); int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer; luaL_Buffer buffer;
@@ -120,7 +207,7 @@ static int mime_global_wrp(lua_State *L)
else lua_pushnil(L); else lua_pushnil(L);
lua_pushnumber(L, length); lua_pushnumber(L, length);
return 2; return 2;
} }
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) { while (input < last) {
switch (*input) { switch (*input) {
@@ -135,7 +222,7 @@ static int mime_global_wrp(lua_State *L)
left = length; left = length;
luaL_addstring(&buffer, CRLF); luaL_addstring(&buffer, CRLF);
} }
luaL_putchar(&buffer, *input); luaL_addchar(&buffer, *input);
left--; left--;
break; break;
} }
@@ -146,23 +233,31 @@ static int mime_global_wrp(lua_State *L)
return 2; return 2;
} }
#if 0
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Fill base64 decode map. * Fill base64 decode map.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void b64setup(UC *b64unbase) static void b64setup(UC *unbase)
{ {
int i; int i;
for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255; for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i; for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
b64unbase['='] = 0; unbase['='] = 0;
printf("static const UC b64unbase[] = {\n");
for (int i = 0; i < 256; i++) {
printf("%d, ", unbase[i]);
}
printf("\n}\n;");
} }
#endif
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 3 bytes are available. * Acumulates bytes in input buffer until 3 bytes are available.
* Translate the 3 bytes into Base64 form and append to buffer. * Translate the 3 bytes into Base64 form and append to buffer.
* Returns new number of bytes in buffer. * Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t b64encode(UC c, UC *input, size_t size, static size_t b64encode(UC c, UC *input, size_t size,
luaL_Buffer *buffer) luaL_Buffer *buffer)
{ {
input[size++] = c; input[size++] = c;
@@ -171,7 +266,7 @@ static size_t b64encode(UC c, UC *input, size_t size,
unsigned long value = 0; unsigned long value = 0;
value += input[0]; value <<= 8; value += input[0]; value <<= 8;
value += input[1]; value <<= 8; value += input[1]; value <<= 8;
value += input[2]; value += input[2];
code[3] = b64base[value & 0x3f]; value >>= 6; code[3] = b64base[value & 0x3f]; value >>= 6;
code[2] = b64base[value & 0x3f]; value >>= 6; code[2] = b64base[value & 0x3f]; value >>= 6;
code[1] = b64base[value & 0x3f]; value >>= 6; code[1] = b64base[value & 0x3f]; value >>= 6;
@@ -183,11 +278,11 @@ static size_t b64encode(UC c, UC *input, size_t size,
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Encodes the Base64 last 1 or 2 bytes and adds padding '=' * Encodes the Base64 last 1 or 2 bytes and adds padding '='
* Result, if any, is appended to buffer. * Result, if any, is appended to buffer.
* Returns 0. * Returns 0.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t b64pad(const UC *input, size_t size, static size_t b64pad(const UC *input, size_t size,
luaL_Buffer *buffer) luaL_Buffer *buffer)
{ {
unsigned long value = 0; unsigned long value = 0;
@@ -200,7 +295,7 @@ static size_t b64pad(const UC *input, size_t size,
luaL_addlstring(buffer, (char *) code, 4); luaL_addlstring(buffer, (char *) code, 4);
break; break;
case 2: case 2:
value = input[0]; value <<= 8; value = input[0]; value <<= 8;
value |= input[1]; value <<= 2; value |= input[1]; value <<= 2;
code[2] = b64base[value & 0x3f]; value >>= 6; code[2] = b64base[value & 0x3f]; value >>= 6;
code[1] = b64base[value & 0x3f]; value >>= 6; code[1] = b64base[value & 0x3f]; value >>= 6;
@@ -214,11 +309,11 @@ static size_t b64pad(const UC *input, size_t size,
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 4 bytes are available. * Acumulates bytes in input buffer until 4 bytes are available.
* Translate the 4 bytes from Base64 form and append to buffer. * Translate the 4 bytes from Base64 form and append to buffer.
* Returns new number of bytes in buffer. * Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t b64decode(UC c, UC *input, size_t size, static size_t b64decode(UC c, UC *input, size_t size,
luaL_Buffer *buffer) luaL_Buffer *buffer)
{ {
/* ignore invalid characters */ /* ignore invalid characters */
@@ -236,7 +331,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
decoded[1] = (UC) (value & 0xff); value >>= 8; decoded[1] = (UC) (value & 0xff); value >>= 8;
decoded[0] = (UC) value; decoded[0] = (UC) value;
/* take care of paddding */ /* take care of paddding */
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
luaL_addlstring(buffer, (char *) decoded, valid); luaL_addlstring(buffer, (char *) decoded, valid);
return 0; return 0;
/* need more data */ /* need more data */
@@ -248,7 +343,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
* A, B = b64(C, D) * A, B = b64(C, D)
* A is the encoded version of the largest prefix of C .. D that is * A is the encoded version of the largest prefix of C .. D that is
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. * divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
* The easiest thing would be to concatenate the two strings and * The easiest thing would be to concatenate the two strings and
* encode the result, but we can't afford that or Lua would dupplicate * encode the result, but we can't afford that or Lua would dupplicate
* every chunk we received. * every chunk we received.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -256,7 +351,7 @@ static int mime_global_b64(lua_State *L)
{ {
UC atom[3]; UC atom[3];
size_t isize = 0, asize = 0; size_t isize = 0, asize = 0;
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize; const UC *last = input + isize;
luaL_Buffer buffer; luaL_Buffer buffer;
/* end-of-input blackhole */ /* end-of-input blackhole */
@@ -265,22 +360,27 @@ static int mime_global_b64(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */ /* process first part of the input */
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) while (input < last)
asize = b64encode(*input++, atom, asize, &buffer); asize = b64encode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize); input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */ /* if second part is nil, we are done */
if (!input) { if (!input) {
size_t osize = 0;
asize = b64pad(atom, asize, &buffer); asize = b64pad(atom, asize, &buffer);
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L); /* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* otherwise process the second part */ /* otherwise process the second part */
last = input + isize; last = input + isize;
while (input < last) while (input < last)
asize = b64encode(*input++, atom, asize, &buffer); asize = b64encode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize); lua_pushlstring(L, (char *) atom, asize);
@@ -297,7 +397,7 @@ static int mime_global_unb64(lua_State *L)
{ {
UC atom[4]; UC atom[4];
size_t isize = 0, asize = 0; size_t isize = 0, asize = 0;
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize; const UC *last = input + isize;
luaL_Buffer buffer; luaL_Buffer buffer;
/* end-of-input blackhole */ /* end-of-input blackhole */
@@ -306,21 +406,26 @@ static int mime_global_unb64(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */ /* process first part of the input */
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) while (input < last)
asize = b64decode(*input++, atom, asize, &buffer); asize = b64decode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize); input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second is nil, we are done */ /* if second is nil, we are done */
if (!input) { if (!input) {
size_t osize = 0;
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L); /* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* otherwise, process the rest of the input */ /* otherwise, process the rest of the input */
last = input + isize; last = input + isize;
while (input < last) while (input < last)
asize = b64decode(*input++, atom, asize, &buffer); asize = b64decode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize); lua_pushlstring(L, (char *) atom, asize);
@@ -336,48 +441,80 @@ static int mime_global_unb64(lua_State *L)
* 9 and 32 can be plain, unless in the end of a line, where must be =XX * 9 and 32 can be plain, unless in the end of a line, where must be =XX
* encoded lines must be no longer than 76 not counting CRLF * encoded lines must be no longer than 76 not counting CRLF
* soft line-break are =CRLF * soft line-break are =CRLF
* To encode one byte, we need to see the next two. * To encode one byte, we need to see the next two.
* Worst case is when we see a space, and wonder if a CRLF is comming * Worst case is when we see a space, and wonder if a CRLF is comming
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#if 0
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Split quoted-printable characters into classes * Split quoted-printable characters into classes
* Precompute reverse map for encoding * Precompute reverse map for encoding
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void qpsetup(UC *qpclass, UC *qpunbase) static void qpsetup(UC *cl, UC *unbase)
{ {
int i; int i;
for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED; for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN; for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN; for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
qpclass['\t'] = QP_IF_LAST; cl['\t'] = QP_IF_LAST;
qpclass[' '] = QP_IF_LAST; cl[' '] = QP_IF_LAST;
qpclass['\r'] = QP_CR; cl['\r'] = QP_CR;
for (i = 0; i < 256; i++) qpunbase[i] = 255; for (i = 0; i < 256; i++) unbase[i] = 255;
qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2; unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5; unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8; unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10; unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12; unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13; unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15; unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
qpunbase['f'] = 15; unbase['f'] = 15;
printf("static UC qpclass[] = {");
for (int i = 0; i < 256; i++) {
if (i % 6 == 0) {
printf("\n ");
}
switch(cl[i]) {
case QP_QUOTED:
printf("QP_QUOTED, ");
break;
case QP_PLAIN:
printf("QP_PLAIN, ");
break;
case QP_CR:
printf("QP_CR, ");
break;
case QP_IF_LAST:
printf("QP_IF_LAST, ");
break;
}
}
printf("\n};\n");
printf("static const UC qpunbase[] = {");
for (int i = 0; i < 256; i++) {
int c = qpunbase[i];
printf("%d, ", c);
}
printf("\";\n");
} }
#endif
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Output one character in form =XX * Output one character in form =XX
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void qpquote(UC c, luaL_Buffer *buffer) static void qpquote(UC c, luaL_Buffer *buffer)
{ {
luaL_putchar(buffer, '='); luaL_addchar(buffer, '=');
luaL_putchar(buffer, qpbase[c >> 4]); luaL_addchar(buffer, qpbase[c >> 4]);
luaL_putchar(buffer, qpbase[c & 0x0F]); luaL_addchar(buffer, qpbase[c & 0x0F]);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them. * Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output to the buffer, in the correct form. * Once we are sure, output to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t qpencode(UC c, UC *input, size_t size, static size_t qpencode(UC c, UC *input, size_t size,
const char *marker, luaL_Buffer *buffer) const char *marker, luaL_Buffer *buffer)
{ {
input[size++] = c; input[size++] = c;
@@ -400,7 +537,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
qpquote(input[0], buffer); qpquote(input[0], buffer);
luaL_addstring(buffer, marker); luaL_addstring(buffer, marker);
return 0; return 0;
} else luaL_putchar(buffer, input[0]); } else luaL_addchar(buffer, input[0]);
break; break;
/* might have to be quoted always */ /* might have to be quoted always */
case QP_QUOTED: case QP_QUOTED:
@@ -408,7 +545,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
break; break;
/* might never have to be quoted */ /* might never have to be quoted */
default: default:
luaL_putchar(buffer, input[0]); luaL_addchar(buffer, input[0]);
break; break;
} }
input[0] = input[1]; input[1] = input[2]; input[0] = input[1]; input[1] = input[2];
@@ -418,13 +555,13 @@ static size_t qpencode(UC c, UC *input, size_t size,
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Deal with the final characters * Deal with the final characters
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
{ {
size_t i; size_t i;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]); if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
else qpquote(input[i], buffer); else qpquote(input[i], buffer);
} }
if (size > 0) luaL_addstring(buffer, EQCRLF); if (size > 0) luaL_addstring(buffer, EQCRLF);
@@ -435,16 +572,15 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
* Incrementally converts a string to quoted-printable * Incrementally converts a string to quoted-printable
* A, B = qp(C, D, marker) * A, B = qp(C, D, marker)
* Marker is the text to be used to replace CRLF sequences found in A. * Marker is the text to be used to replace CRLF sequences found in A.
* A is the encoded version of the largest prefix of C .. D that * A is the encoded version of the largest prefix of C .. D that
* can be encoded without doubts. * can be encoded without doubts.
* B has the remaining bytes of C .. D, *without* encoding. * B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int mime_global_qp(lua_State *L) static int mime_global_qp(lua_State *L)
{ {
size_t asize = 0, isize = 0; size_t asize = 0, isize = 0;
UC atom[3]; UC atom[3];
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize; const UC *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF); const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer; luaL_Buffer buffer;
@@ -454,11 +590,13 @@ static int mime_global_qp(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
/* process first part of input */ /* process first part of input */
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) while (input < last)
asize = qpencode(*input++, atom, asize, marker, &buffer); asize = qpencode(*input++, atom, asize, marker, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize); input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */ /* if second part is nil, we are done */
if (!input) { if (!input) {
asize = qppad(atom, asize, &buffer); asize = qppad(atom, asize, &buffer);
@@ -478,7 +616,7 @@ static int mime_global_qp(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them. * Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output the to the buffer, in the correct form. * Once we are sure, output the to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
int d; int d;
@@ -486,23 +624,23 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
/* deal with all characters we can deal */ /* deal with all characters we can deal */
switch (input[0]) { switch (input[0]) {
/* if we have an escape character */ /* if we have an escape character */
case '=': case '=':
if (size < 3) return size; if (size < 3) return size;
/* eliminate soft line break */ /* eliminate soft line break */
if (input[1] == '\r' && input[2] == '\n') return 0; if (input[1] == '\r' && input[2] == '\n') return 0;
/* decode quoted representation */ /* decode quoted representation */
c = qpunbase[input[1]]; d = qpunbase[input[2]]; c = qpunbase[input[1]]; d = qpunbase[input[2]];
/* if it is an invalid, do not decode */ /* if it is an invalid, do not decode */
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
else luaL_putchar(buffer, (c << 4) + d); else luaL_addchar(buffer, (char) ((c << 4) + d));
return 0; return 0;
case '\r': case '\r':
if (size < 2) return size; if (size < 2) return size;
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
return 0; return 0;
default: default:
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
luaL_putchar(buffer, input[0]); luaL_addchar(buffer, input[0]);
return 0; return 0;
} }
} }
@@ -510,15 +648,15 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Incrementally decodes a string in quoted-printable * Incrementally decodes a string in quoted-printable
* A, B = qp(C, D) * A, B = qp(C, D)
* A is the decoded version of the largest prefix of C .. D that * A is the decoded version of the largest prefix of C .. D that
* can be decoded without doubts. * can be decoded without doubts.
* B has the remaining bytes of C .. D, *without* decoding. * B has the remaining bytes of C .. D, *without* decoding.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int mime_global_unqp(lua_State *L) static int mime_global_unqp(lua_State *L)
{ {
size_t asize = 0, isize = 0; size_t asize = 0, isize = 0;
UC atom[3]; UC atom[3];
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize; const UC *last = input + isize;
luaL_Buffer buffer; luaL_Buffer buffer;
/* end-of-input blackhole */ /* end-of-input blackhole */
@@ -527,18 +665,20 @@ static int mime_global_unqp(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of input */ /* process first part of input */
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) while (input < last)
asize = qpdecode(*input++, atom, asize, &buffer); asize = qpdecode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize); input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */ /* if second part is nil, we are done */
if (!input) { if (!input) {
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L); if (!(*lua_tostring(L, -1))) lua_pushnil(L);
lua_pushnil(L); lua_pushnil(L);
return 2; return 2;
} }
/* otherwise process rest of input */ /* otherwise process rest of input */
last = input + isize; last = input + isize;
while (input < last) while (input < last)
@@ -551,9 +691,9 @@ static int mime_global_unqp(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Incrementally breaks a quoted-printed string into lines * Incrementally breaks a quoted-printed string into lines
* A, n = qpwrp(l, B, length) * A, n = qpwrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes. * A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B. * 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A. * 'n' is the number of bytes left in the last line of A.
* There are two complications: lines can't be broken in the middle * There are two complications: lines can't be broken in the middle
* of an encoded =XX, and there might be line breaks already * of an encoded =XX, and there might be line breaks already
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -561,7 +701,7 @@ static int mime_global_qpwrp(lua_State *L)
{ {
size_t size = 0; size_t size = 0;
int left = (int) luaL_checknumber(L, 1); int left = (int) luaL_checknumber(L, 1);
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
const UC *last = input + size; const UC *last = input + size;
int length = (int) luaL_optnumber(L, 3, 76); int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer; luaL_Buffer buffer;
@@ -586,16 +726,16 @@ static int mime_global_qpwrp(lua_State *L)
if (left <= 3) { if (left <= 3) {
left = length; left = length;
luaL_addstring(&buffer, EQCRLF); luaL_addstring(&buffer, EQCRLF);
} }
luaL_putchar(&buffer, *input); luaL_addchar(&buffer, *input);
left--; left--;
break; break;
default: default:
if (left <= 1) { if (left <= 1) {
left = length; left = length;
luaL_addstring(&buffer, EQCRLF); luaL_addstring(&buffer, EQCRLF);
} }
luaL_putchar(&buffer, *input); luaL_addchar(&buffer, *input);
left--; left--;
break; break;
} }
@@ -618,7 +758,7 @@ static int mime_global_qpwrp(lua_State *L)
* last is the previous character * last is the previous character
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#define eolcandidate(c) (c == '\r' || c == '\n') #define eolcandidate(c) (c == '\r' || c == '\n')
static int eolprocess(int c, int last, const char *marker, static int eolprocess(int c, int last, const char *marker,
luaL_Buffer *buffer) luaL_Buffer *buffer)
{ {
if (eolcandidate(c)) { if (eolcandidate(c)) {
@@ -630,21 +770,21 @@ static int eolprocess(int c, int last, const char *marker,
return c; return c;
} }
} else { } else {
luaL_putchar(buffer, c); luaL_addchar(buffer, (char) c);
return 0; return 0;
} }
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Converts a string to uniform EOL convention. * Converts a string to uniform EOL convention.
* A, n = eol(o, B, marker) * A, n = eol(o, B, marker)
* A is the converted version of the largest prefix of B that can be * A is the converted version of the largest prefix of B that can be
* converted unambiguously. 'o' is the context returned by the previous * converted unambiguously. 'o' is the context returned by the previous
* call. 'n' is the new context. * call. 'n' is the new context.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int mime_global_eol(lua_State *L) static int mime_global_eol(lua_State *L)
{ {
int ctx = luaL_checkint(L, 1); int ctx = (int) luaL_checkinteger(L, 1);
size_t isize = 0; size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize); const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize; const char *last = input + isize;
@@ -666,19 +806,20 @@ static int mime_global_eol(lua_State *L)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Takes one byte and stuff it if needed. * Takes one byte and stuff it if needed.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static size_t dot(int c, size_t state, luaL_Buffer *buffer) static size_t dot(int c, size_t state, luaL_Buffer *buffer)
{ {
luaL_putchar(buffer, c); luaL_addchar(buffer, (char) c);
switch (c) { switch (c) {
case '\r': case '\r':
return 1; return 1;
case '\n': case '\n':
return (state == 1)? 2: 0; return (state == 1)? 2: 0;
case '.': case '.':
if (state == 2) if (state == 2)
luaL_putchar(buffer, '.'); luaL_addchar(buffer, '.');
/* Falls through. */
default: default:
return 0; return 0;
} }
@@ -702,10 +843,10 @@ static int mime_global_dot(lua_State *L)
} }
/* process all input */ /* process all input */
luaL_buffinit(L, &buffer); luaL_buffinit(L, &buffer);
while (input < last) while (input < last)
state = dot(*input++, state, &buffer); state = dot(*input++, state, &buffer);
luaL_pushresult(&buffer); luaL_pushresult(&buffer);
lua_pushnumber(L, state); lua_pushnumber(L, (lua_Number) state);
return 2; return 2;
} }

View File

@@ -7,25 +7,16 @@
* This module provides functions to implement transfer content encodings * This module provides functions to implement transfer content encodings
* and formatting conforming to RFC 2045. It is used by mime.lua, which * and formatting conforming to RFC 2045. It is used by mime.lua, which
* provide a higher level interface to this functionality. * provide a higher level interface to this functionality.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Current MIME library version * Current MIME library version
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#define MIME_VERSION "MIME 1.0.2" #define MIME_VERSION "MIME 1.0.3"
#define MIME_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab" #define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab"
#define MIME_AUTHORS "Diego Nehab" #define MIME_AUTHORS "Diego Nehab"
/*-------------------------------------------------------------------------*\ LUASOCKET_API int luaopen_mime_core(lua_State *L);
* This macro prefixes all exported API functions
\*-------------------------------------------------------------------------*/
#ifndef MIME_API
#define MIME_API extern
#endif
MIME_API int luaopen_mime_core(lua_State *L);
#endif /* MIME_H */ #endif /* MIME_H */

View File

@@ -2,7 +2,6 @@
-- MIME support for the Lua language. -- MIME support for the Lua language.
-- Author: Diego Nehab -- Author: Diego Nehab
-- Conforming to RFCs 2045-2049 -- Conforming to RFCs 2045-2049
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -11,14 +10,15 @@
local base = _G local base = _G
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local mime = require("mime.core") local mime = require("mime.core")
local io = require("io")
local string = require("string") local string = require("string")
module("mime") local _M = mime
-- encode, decode and wrap algorithm tables -- encode, decode and wrap algorithm tables
encodet = {} local encodet, decodet, wrapt = {},{},{}
decodet = {}
wrapt = {} _M.encodet = encodet
_M.decodet = decodet
_M.wrapt = wrapt
-- creates a function that chooses a filter by name from a given table -- creates a function that chooses a filter by name from a given table
local function choose(table) local function choose(table)
@@ -35,21 +35,21 @@ end
-- define the encoding filters -- define the encoding filters
encodet['base64'] = function() encodet['base64'] = function()
return ltn12.filter.cycle(b64, "") return ltn12.filter.cycle(_M.b64, "")
end end
encodet['quoted-printable'] = function(mode) encodet['quoted-printable'] = function(mode)
return ltn12.filter.cycle(qp, "", return ltn12.filter.cycle(_M.qp, "",
(mode == "binary") and "=0D=0A" or "\r\n") (mode == "binary") and "=0D=0A" or "\r\n")
end end
-- define the decoding filters -- define the decoding filters
decodet['base64'] = function() decodet['base64'] = function()
return ltn12.filter.cycle(unb64, "") return ltn12.filter.cycle(_M.unb64, "")
end end
decodet['quoted-printable'] = function() decodet['quoted-printable'] = function()
return ltn12.filter.cycle(unqp, "") return ltn12.filter.cycle(_M.unqp, "")
end end
local function format(chunk) local function format(chunk)
@@ -62,26 +62,28 @@ end
-- define the line-wrap filters -- define the line-wrap filters
wrapt['text'] = function(length) wrapt['text'] = function(length)
length = length or 76 length = length or 76
return ltn12.filter.cycle(wrp, length, length) return ltn12.filter.cycle(_M.wrp, length, length)
end end
wrapt['base64'] = wrapt['text'] wrapt['base64'] = wrapt['text']
wrapt['default'] = wrapt['text'] wrapt['default'] = wrapt['text']
wrapt['quoted-printable'] = function() wrapt['quoted-printable'] = function()
return ltn12.filter.cycle(qpwrp, 76, 76) return ltn12.filter.cycle(_M.qpwrp, 76, 76)
end end
-- function that choose the encoding, decoding or wrap algorithm -- function that choose the encoding, decoding or wrap algorithm
encode = choose(encodet) _M.encode = choose(encodet)
decode = choose(decodet) _M.decode = choose(decodet)
wrap = choose(wrapt) _M.wrap = choose(wrapt)
-- define the end-of-line normalization filter -- define the end-of-line normalization filter
function normalize(marker) function _M.normalize(marker)
return ltn12.filter.cycle(eol, 0, marker) return ltn12.filter.cycle(_M.eol, 0, marker)
end end
-- high level stuffing filter -- high level stuffing filter
function stuff() function _M.stuff()
return ltn12.filter.cycle(dot, 2) return ltn12.filter.cycle(_M.dot, 2)
end end
return _M

View File

@@ -1,25 +1,26 @@
/*=========================================================================*\ /*=========================================================================*\
* Common option interface * Common option interface
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include "luasocket.h"
#include "lauxlib.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "options.h" #include "options.h"
#include "inet.h" #include "inet.h"
#include <string.h>
/*=========================================================================*\ /*=========================================================================*\
* Internal functions prototypes * Internal functions prototypes
\*=========================================================================*/ \*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name);
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name, static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_setint(lua_State *L, p_socket ps, int level, int name);
static int opt_getint(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name,
void *val, int len); void *val, int len);
static int opt_get(lua_State *L, p_socket ps, int level, int name,
void *val, int* len);
/*=========================================================================*\ /*=========================================================================*\
* Exported functions * Exported functions
@@ -33,103 +34,380 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
while (opt->name && strcmp(name, opt->name)) while (opt->name && strcmp(name, opt->name))
opt++; opt++;
if (!opt->func) { if (!opt->func) {
char msg[45]; char msg[57];
sprintf(msg, "unsupported option `%.35s'", name); sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg); luaL_argerror(L, 2, msg);
} }
return opt->func(L, ps); return opt->func(L, ps);
} }
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
{
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[57];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
return opt->func(L, ps);
}
// -------------------------------------------------------
/* enables reuse of local address */ /* enables reuse of local address */
int opt_reuseaddr(lua_State *L, p_socket ps) int opt_set_reuseaddr(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
} }
/* disables the Naggle algorithm */ int opt_get_reuseaddr(lua_State *L, p_socket ps)
int opt_tcp_nodelay(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
} }
int opt_keepalive(lua_State *L, p_socket ps) // -------------------------------------------------------
/* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
} }
int opt_dontroute(lua_State *L, p_socket ps) int opt_get_reuseport(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
// -------------------------------------------------------
/* disables the Nagle algorithm */
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
// -------------------------------------------------------
#ifdef TCP_KEEPIDLE
int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
}
int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
}
#endif
// -------------------------------------------------------
#ifdef TCP_KEEPCNT
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
}
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
}
#endif
// -------------------------------------------------------
#ifdef TCP_KEEPINTVL
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
}
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
}
#endif
// -------------------------------------------------------
int opt_set_keepalive(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_get_keepalive(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
// -------------------------------------------------------
int opt_set_dontroute(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
} }
int opt_broadcast(lua_State *L, p_socket ps) int opt_get_dontroute(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
}
// -------------------------------------------------------
int opt_set_broadcast(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
} }
int opt_ip_multicast_loop(lua_State *L, p_socket ps) int opt_get_broadcast(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
}
// -------------------------------------------------------
int opt_set_recv_buf_size(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
}
int opt_get_recv_buf_size(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
}
// -------------------------------------------------------
int opt_get_send_buf_size(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
}
int opt_set_send_buf_size(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
}
// -------------------------------------------------------
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
}
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
}
// -------------------------------------------------------
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
}
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
}
// -------------------------------------------------------
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
} }
int opt_linger(lua_State *L, p_socket ps) int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
// -------------------------------------------------------
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
}
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
}
// -------------------------------------------------------
int opt_set_linger(lua_State *L, p_socket ps)
{ {
struct linger li; /* obj, name, table */ struct linger li; /* obj, name, table */
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE)); if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "on"); lua_pushstring(L, "on");
lua_gettable(L, 3); lua_gettable(L, 3);
if (!lua_isboolean(L, -1)) if (!lua_isboolean(L, -1))
luaL_argerror(L, 3, "boolean 'on' field expected"); luaL_argerror(L, 3, "boolean 'on' field expected");
li.l_onoff = (u_short) lua_toboolean(L, -1); li.l_onoff = (u_short) lua_toboolean(L, -1);
lua_pushstring(L, "timeout"); lua_pushstring(L, "timeout");
lua_gettable(L, 3); lua_gettable(L, 3);
if (!lua_isnumber(L, -1)) if (!lua_isnumber(L, -1))
luaL_argerror(L, 3, "number 'timeout' field expected"); luaL_argerror(L, 3, "number 'timeout' field expected");
li.l_linger = (u_short) lua_tonumber(L, -1); li.l_linger = (u_short) lua_tonumber(L, -1);
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
} }
int opt_ip_multicast_ttl(lua_State *L, p_socket ps) int opt_get_linger(lua_State *L, p_socket ps)
{ {
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */ struct linger li; /* obj, name */
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val)); int len = sizeof(li);
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
if (err)
return err;
lua_newtable(L);
lua_pushboolean(L, li.l_onoff);
lua_setfield(L, -2, "on");
lua_pushinteger(L, li.l_linger);
lua_setfield(L, -2, "timeout");
return 1;
} }
int opt_ip_add_membership(lua_State *L, p_socket ps) // -------------------------------------------------------
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
}
// -------------------------------------------------------
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
{
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
struct in_addr val;
val.s_addr = htonl(INADDR_ANY);
if (strcmp(address, "*") && !inet_aton(address, &val))
luaL_argerror(L, 3, "ip expected");
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &val, sizeof(val));
}
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
{
struct in_addr val;
socklen_t len = sizeof(val);
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, inet_ntoa(val));
return 1;
}
// -------------------------------------------------------
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
{ {
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
} }
int opt_ip_drop_membersip(lua_State *L, p_socket ps) int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
{ {
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
} }
// -------------------------------------------------------
int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
{
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
}
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
{
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
}
// -------------------------------------------------------
int opt_get_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
// -------------------------------------------------------
int opt_get_error(lua_State *L, p_socket ps)
{
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, socket_strerror(val));
return 1;
}
/*=========================================================================*\ /*=========================================================================*\
* Auxiliar functions * Auxiliar functions
\*=========================================================================*/ \*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
{ {
struct ip_mreq val; /* obj, name, table */ struct ip_mreq val; /* obj, name, table */
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE)); if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr"); lua_pushstring(L, "multiaddr");
lua_gettable(L, 3); lua_gettable(L, 3);
if (!lua_isstring(L, -1)) if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected"); luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface"); lua_pushstring(L, "interface");
lua_gettable(L, 3); lua_gettable(L, 3);
if (!lua_isstring(L, -1)) if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'interface' field expected"); luaL_argerror(L, 3, "string 'interface' field expected");
val.imr_interface.s_addr = htonl(INADDR_ANY); val.imr_interface.s_addr = htonl(INADDR_ANY);
if (strcmp(lua_tostring(L, -1), "*") && if (strcmp(lua_tostring(L, -1), "*") &&
!inet_aton(lua_tostring(L, -1), &val.imr_interface)) !inet_aton(lua_tostring(L, -1), &val.imr_interface))
luaL_argerror(L, 3, "invalid 'interface' ip address"); luaL_argerror(L, 3, "invalid 'interface' ip address");
return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
} }
static static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
{
struct ipv6_mreq val; /* obj, opt-name, table */
memset(&val, 0, sizeof(val));
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 3);
/* By default we listen to interface on default route
* (sigh). However, interface= can override it. We should
* support either number, or name for it. Waiting for
* windows port of if_nametoindex */
if (!lua_isnil(L, -1)) {
if (lua_isnumber(L, -1)) {
val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1);
} else
luaL_argerror(L, -1, "number 'interface' field expected");
}
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
{
socklen_t socklen = *len;
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
*len = socklen;
return 0;
}
static
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
{ {
if (setsockopt(*ps, level, name, (char *) val, len) < 0) { if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
@@ -141,9 +419,36 @@ int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
return 1; return 1;
} }
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
int len = sizeof(val);
int err = opt_get(L, ps, level, name, (char *) &val, &len);
if (err)
return err;
lua_pushboolean(L, val);
return 1;
}
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
{ {
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
} }
static int opt_getint(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
int len = sizeof(val);
int err = opt_get(L, ps, level, name, (char *) &val, &len);
if (err)
return err;
lua_pushnumber(L, val);
return 1;
}
static int opt_setint(lua_State *L, p_socket ps, int level, int name)
{
int val = (int) lua_tonumber(L, 3); /* obj, name, int */
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}

View File

@@ -6,11 +6,9 @@
* *
* This module provides a common interface to socket options, used mainly by * This module provides a common interface to socket options, used mainly by
* modules UDP and TCP. * modules UDP and TCP.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "socket.h" #include "socket.h"
/* option registry */ /* option registry */
@@ -20,20 +18,85 @@ typedef struct t_opt {
} t_opt; } t_opt;
typedef t_opt *p_opt; typedef t_opt *p_opt;
/* supported options */ #ifndef _WIN32
int opt_dontroute(lua_State *L, p_socket ps); #pragma GCC visibility push(hidden)
int opt_broadcast(lua_State *L, p_socket ps); #endif
int opt_reuseaddr(lua_State *L, p_socket ps);
int opt_tcp_nodelay(lua_State *L, p_socket ps);
int opt_keepalive(lua_State *L, p_socket ps);
int opt_linger(lua_State *L, p_socket ps);
int opt_reuseaddr(lua_State *L, p_socket ps);
int opt_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_ip_add_membership(lua_State *L, p_socket ps);
int opt_ip_drop_membersip(lua_State *L, p_socket ps);
/* invokes the appropriate option handler */
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_set_reuseport(lua_State *L, p_socket ps);
int opt_get_reuseport(lua_State *L, p_socket ps);
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
#ifdef TCP_KEEPIDLE
int opt_set_tcp_keepidle(lua_State *L, p_socket ps);
int opt_get_tcp_keepidle(lua_State *L, p_socket ps);
#endif
#ifdef TCP_KEEPCNT
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps);
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps);
#endif
#ifdef TCP_KEEPINTVL
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps);
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps);
#endif
int opt_set_keepalive(lua_State *L, p_socket ps);
int opt_get_keepalive(lua_State *L, p_socket ps);
int opt_set_dontroute(lua_State *L, p_socket ps);
int opt_get_dontroute(lua_State *L, p_socket ps);
int opt_set_broadcast(lua_State *L, p_socket ps);
int opt_get_broadcast(lua_State *L, p_socket ps);
int opt_set_recv_buf_size(lua_State *L, p_socket ps);
int opt_get_recv_buf_size(lua_State *L, p_socket ps);
int opt_set_send_buf_size(lua_State *L, p_socket ps);
int opt_get_send_buf_size(lua_State *L, p_socket ps);
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_set_linger(lua_State *L, p_socket ps);
int opt_get_linger(lua_State *L, p_socket ps);
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
int opt_get_ip6_v6only(lua_State *L, p_socket ps);
int opt_get_error(lua_State *L, p_socket ps);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif #endif

28
src/pierror.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef PIERROR_H
#define PIERROR_H
/*=========================================================================*\
* Error messages
* Defines platform independent error messages
\*=========================================================================*/
#define PIE_HOST_NOT_FOUND "host not found"
#define PIE_ADDRINUSE "address already in use"
#define PIE_ISCONN "already connected"
#define PIE_ACCESS "permission denied"
#define PIE_CONNREFUSED "connection refused"
#define PIE_CONNABORTED "closed"
#define PIE_CONNRESET "closed"
#define PIE_TIMEDOUT "timeout"
#define PIE_AGAIN "temporary failure in name resolution"
#define PIE_BADFLAGS "invalid value for ai_flags"
#define PIE_BADHINTS "invalid value for hints"
#define PIE_FAIL "non-recoverable failure in name resolution"
#define PIE_FAMILY "ai_family not supported"
#define PIE_MEMORY "memory allocation failure"
#define PIE_NONAME "host or service not provided, or not known"
#define PIE_OVERFLOW "argument buffer overflow"
#define PIE_PROTOCOL "resolved protocol is unknown"
#define PIE_SERVICE "service not supported for socket type"
#define PIE_SOCKTYPE "ai_socktype not supported"
#endif

View File

@@ -1,45 +1,45 @@
/*=========================================================================*\ /*=========================================================================*\
* Select implementation * Select implementation
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#include "socket.h" #include "socket.h"
#include "timeout.h" #include "timeout.h"
#include "select.h" #include "select.h"
#include <string.h>
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes. * Internal function prototypes.
\*=========================================================================*/ \*=========================================================================*/
static t_socket getfd(lua_State *L); static t_socket getfd(lua_State *L);
static int dirty(lua_State *L); static int dirty(lua_State *L);
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd, static void collect_fd(lua_State *L, int tab, int itab,
int itab, fd_set *set); fd_set *set, t_socket *max_fd);
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start); int itab, int tab, int start);
static void make_assoc(lua_State *L, int tab); static void make_assoc(lua_State *L, int tab);
static int global_select(lua_State *L); static int global_select(lua_State *L);
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_Reg func[] = {
{"select", global_select}, {"select", global_select},
{NULL, NULL} {NULL, NULL}
}; };
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes module * Initializes module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int select_open(lua_State *L) { int select_open(lua_State *L) {
luaL_openlib(L, NULL, func, 0); lua_pushstring(L, "_SETSIZE");
lua_pushinteger(L, FD_SETSIZE);
lua_rawset(L, -3);
lua_pushstring(L, "_SOCKETINVALID");
lua_pushinteger(L, SOCKET_INVALID);
lua_rawset(L, -3);
luaL_setfuncs(L, func, 0);
return 0; return 0;
} }
@@ -51,7 +51,7 @@ int select_open(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int global_select(lua_State *L) { static int global_select(lua_State *L) {
int rtab, wtab, itab, ret, ndirty; int rtab, wtab, itab, ret, ndirty;
t_socket max_fd; t_socket max_fd = SOCKET_INVALID;
fd_set rset, wset; fd_set rset, wset;
t_timeout tm; t_timeout tm;
double t = luaL_optnumber(L, 3, -1); double t = luaL_optnumber(L, 3, -1);
@@ -60,12 +60,12 @@ static int global_select(lua_State *L) {
lua_newtable(L); itab = lua_gettop(L); lua_newtable(L); itab = lua_gettop(L);
lua_newtable(L); rtab = lua_gettop(L); lua_newtable(L); rtab = lua_gettop(L);
lua_newtable(L); wtab = lua_gettop(L); lua_newtable(L); wtab = lua_gettop(L);
max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset); collect_fd(L, 1, itab, &rset, &max_fd);
collect_fd(L, 2, itab, &wset, &max_fd);
ndirty = check_dirty(L, 1, rtab, &rset); ndirty = check_dirty(L, 1, rtab, &rset);
t = ndirty > 0? 0.0: t; t = ndirty > 0? 0.0: t;
timeout_init(&tm, t, -1); timeout_init(&tm, t, -1);
timeout_markstart(&tm); timeout_markstart(&tm);
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
if (ret > 0 || ndirty > 0) { if (ret > 0 || ndirty > 0) {
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
@@ -77,7 +77,7 @@ static int global_select(lua_State *L) {
lua_pushstring(L, "timeout"); lua_pushstring(L, "timeout");
return 3; return 3;
} else { } else {
lua_pushstring(L, "error"); luaL_error(L, "select failed");
return 3; return 3;
} }
} }
@@ -92,9 +92,11 @@ static t_socket getfd(lua_State *L) {
if (!lua_isnil(L, -1)) { if (!lua_isnil(L, -1)) {
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_call(L, 1, 1); lua_call(L, 1, 1);
if (lua_isnumber(L, -1)) if (lua_isnumber(L, -1)) {
fd = (t_socket) lua_tonumber(L, -1); double numfd = lua_tonumber(L, -1);
} fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
}
}
lua_pop(L, 1); lua_pop(L, 1);
return fd; return fd;
} }
@@ -107,17 +109,19 @@ static int dirty(lua_State *L) {
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_call(L, 1, 1); lua_call(L, 1, 1);
is = lua_toboolean(L, -1); is = lua_toboolean(L, -1);
} }
lua_pop(L, 1); lua_pop(L, 1);
return is; return is;
} }
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd, static void collect_fd(lua_State *L, int tab, int itab,
int itab, fd_set *set) { fd_set *set, t_socket *max_fd) {
int i = 1; int i = 1, n = 0;
if (lua_isnil(L, tab)) /* nil is the same as an empty table */
return max_fd; if (lua_isnil(L, tab)) return;
while (1) { /* otherwise we need it to be a table */
luaL_checktype(L, tab, LUA_TTABLE);
for ( ;; ) {
t_socket fd; t_socket fd;
lua_pushnumber(L, i); lua_pushnumber(L, i);
lua_gettable(L, tab); lua_gettable(L, tab);
@@ -125,26 +129,37 @@ static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
lua_pop(L, 1); lua_pop(L, 1);
break; break;
} }
/* getfd figures out if this is a socket */
fd = getfd(L); fd = getfd(L);
if (fd != SOCKET_INVALID) { if (fd != SOCKET_INVALID) {
/* make sure we don't overflow the fd_set */
#ifdef _WIN32
if (n >= FD_SETSIZE)
luaL_argerror(L, tab, "too many sockets");
#else
if (fd >= FD_SETSIZE)
luaL_argerror(L, tab, "descriptor too large for set size");
#endif
FD_SET(fd, set); FD_SET(fd, set);
if (max_fd == SOCKET_INVALID || max_fd < fd) n++;
max_fd = fd; /* keep track of the largest descriptor so far */
lua_pushnumber(L, fd); if (*max_fd == SOCKET_INVALID || *max_fd < fd)
*max_fd = fd;
/* make sure we can map back from descriptor to the object */
lua_pushnumber(L, (lua_Number) fd);
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_settable(L, itab); lua_settable(L, itab);
} }
lua_pop(L, 1); lua_pop(L, 1);
i = i + 1; i = i + 1;
} }
return max_fd;
} }
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
int ndirty = 0, i = 1; int ndirty = 0, i = 1;
if (lua_isnil(L, tab)) if (lua_isnil(L, tab))
return 0; return 0;
while (1) { for ( ;; ) {
t_socket fd; t_socket fd;
lua_pushnumber(L, i); lua_pushnumber(L, i);
lua_gettable(L, tab); lua_gettable(L, tab);
@@ -165,13 +180,13 @@ static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
return ndirty; return ndirty;
} }
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start) { int itab, int tab, int start) {
t_socket fd; t_socket fd;
for (fd = 0; fd < max_fd; fd++) { for (fd = 0; fd < max_fd; fd++) {
if (FD_ISSET(fd, set)) { if (FD_ISSET(fd, set)) {
lua_pushnumber(L, ++start); lua_pushnumber(L, ++start);
lua_pushnumber(L, fd); lua_pushnumber(L, (lua_Number) fd);
lua_gettable(L, itab); lua_gettable(L, itab);
lua_settable(L, tab); lua_settable(L, tab);
} }
@@ -181,7 +196,7 @@ static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
static void make_assoc(lua_State *L, int tab) { static void make_assoc(lua_State *L, int tab) {
int i = 1, atab; int i = 1, atab;
lua_newtable(L); atab = lua_gettop(L); lua_newtable(L); atab = lua_gettop(L);
while (1) { for ( ;; ) {
lua_pushnumber(L, i); lua_pushnumber(L, i);
lua_gettable(L, tab); lua_gettable(L, tab);
if (!lua_isnil(L, -1)) { if (!lua_isnil(L, -1)) {
@@ -197,4 +212,3 @@ static void make_assoc(lua_State *L, int tab) {
i = i+1; i = i+1;
} }
} }

View File

@@ -8,10 +8,16 @@
* method getfd() which returns the descriptor to be passed to the * method getfd() which returns the descriptor to be passed to the
* underlying select function. Another method, dirty(), should return * underlying select function. Another method, dirty(), should return
* true if there is data ready for reading (required for buffered input). * true if there is data ready for reading (required for buffered input).
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int select_open(lua_State *L); int select_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* SELECT_H */ #endif /* SELECT_H */

171
src/serial.c Normal file
View File

@@ -0,0 +1,171 @@
/*=========================================================================*\
* Serial stream
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <string.h>
#include <sys/un.h>
/*
Reuses userdata definition from unix.h, since it is useful for all
stream-like objects.
If we stored the serial path for use in error messages or userdata
printing, we might need our own userdata definition.
Group usage is semi-inherited from unix.c, but unnecessary since we
have only one object type.
*/
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_send(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_close(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
/* serial object methods */
static luaL_Reg serial_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"close", meth_close},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"settimeout", meth_settimeout},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "serial{client}", serial_methods);
/* create class groups */
auxiliar_add2group(L, "serial{client}", "serial{any}");
lua_pushcfunction(L, global_create);
return 1;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a serial object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
const char* path = luaL_checkstring(L, 1);
/* allocate unix object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* open serial device */
t_socket sock = open(path, O_NOCTTY|O_RDWR);
/*printf("open %s on %d\n", path, sock);*/
if (sock < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
lua_pushnumber(L, errno);
return 3;
}
/* set its type as client object */
auxiliar_setclass(L, "serial{client}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
}

View File

@@ -2,7 +2,6 @@
-- SMTP client support for the Lua language. -- SMTP client support for the Lua language.
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -16,23 +15,26 @@ local os = require("os")
local socket = require("socket") local socket = require("socket")
local tp = require("socket.tp") local tp = require("socket.tp")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local headers = require("socket.headers")
local mime = require("mime") local mime = require("mime")
module("socket.smtp")
socket.smtp = {}
local _M = socket.smtp
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Program constants -- Program constants
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- timeout for connection -- timeout for connection
TIMEOUT = 60 _M.TIMEOUT = 60
-- default server used to send e-mails -- default server used to send e-mails
SERVER = "localhost" _M.SERVER = "localhost"
-- default port -- default port
PORT = 25 _M.PORT = 25
-- domain used in HELO command and default sendmail -- domain used in HELO command and default sendmail
-- If we are under a CGI, try to get from environment -- If we are under a CGI, try to get from environment
DOMAIN = os.getenv("SERVER_NAME") or "localhost" _M.DOMAIN = os.getenv("SERVER_NAME") or "localhost"
-- default time zone (means we don't know) -- default time zone (means we don't know)
ZONE = "-0000" _M.ZONE = "-0000"
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Low level SMTP API -- Low level SMTP API
@@ -41,7 +43,7 @@ local metat = { __index = {} }
function metat.__index:greet(domain) function metat.__index:greet(domain)
self.try(self.tp:check("2..")) self.try(self.tp:check("2.."))
self.try(self.tp:command("EHLO", domain or DOMAIN)) self.try(self.tp:command("EHLO", domain or _M.DOMAIN))
return socket.skip(1, self.try(self.tp:check("2.."))) return socket.skip(1, self.try(self.tp:check("2..")))
end end
@@ -75,9 +77,9 @@ end
function metat.__index:login(user, password) function metat.__index:login(user, password)
self.try(self.tp:command("AUTH", "LOGIN")) self.try(self.tp:command("AUTH", "LOGIN"))
self.try(self.tp:check("3..")) self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(user))) self.try(self.tp:send(mime.b64(user) .. "\r\n"))
self.try(self.tp:check("3..")) self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(password))) self.try(self.tp:send(mime.b64(password) .. "\r\n"))
return self.try(self.tp:check("2..")) return self.try(self.tp:check("2.."))
end end
@@ -111,9 +113,9 @@ function metat.__index:send(mailt)
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
end end
function open(server, port, create) function _M.open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT, local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,
TIMEOUT, create)) _M.TIMEOUT, create))
local s = base.setmetatable({tp = tp}, metat) local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception -- make sure tp is closed if we get an exception
s.try = socket.newtry(function() s.try = socket.newtry(function()
@@ -146,10 +148,11 @@ end
local send_message local send_message
-- yield the headers all at once, it's faster -- yield the headers all at once, it's faster
local function send_headers(headers) local function send_headers(tosend)
local canonic = headers.canonic
local h = "\r\n" local h = "\r\n"
for i,v in base.pairs(headers) do for f,v in base.pairs(tosend) do
h = i .. ': ' .. v .. "\r\n" .. h h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h
end end
coroutine.yield(h) coroutine.yield(h)
end end
@@ -220,14 +223,14 @@ end
local function adjust_headers(mesgt) local function adjust_headers(mesgt)
local lower = lower_headers(mesgt.headers) local lower = lower_headers(mesgt.headers)
lower["date"] = lower["date"] or lower["date"] = lower["date"] or
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE)
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
-- this can't be overriden -- this can't be overriden
lower["mime-version"] = "1.0" lower["mime-version"] = "1.0"
return lower return lower
end end
function message(mesgt) function _M.message(mesgt)
mesgt.headers = adjust_headers(mesgt) mesgt.headers = adjust_headers(mesgt)
-- create and return message source -- create and return message source
local co = coroutine.create(function() send_message(mesgt) end) local co = coroutine.create(function() send_message(mesgt) end)
@@ -241,11 +244,13 @@ end
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- High level SMTP API -- High level SMTP API
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
send = socket.protect(function(mailt) _M.send = socket.protect(function(mailt)
local s = open(mailt.server, mailt.port, mailt.create) local s = _M.open(mailt.server, mailt.port, mailt.create)
local ext = s:greet(mailt.domain) local ext = s:greet(mailt.domain)
s:auth(mailt.user, mailt.password, ext) s:auth(mailt.user, mailt.password, ext)
s:send(mailt) s:send(mailt)
s:quit() s:quit()
return s:close() return s:close()
end) end)
return _M

View File

@@ -8,8 +8,6 @@
* differences. Also, not all *nix platforms behave the same. This module * differences. Also, not all *nix platforms behave the same. This module
* (and the associated usocket.h and wsocket.h) factor these differences and * (and the associated usocket.h and wsocket.h) factor these differences and
* creates a interface compatible with the io.h module. * creates a interface compatible with the io.h module.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "io.h" #include "io.h"
@@ -30,47 +28,46 @@
\*=========================================================================*/ \*=========================================================================*/
#include "timeout.h" #include "timeout.h"
/* we are lazy... */ /* convenient shorthand */
typedef struct sockaddr SA; typedef struct sockaddr SA;
/*=========================================================================*\ /*=========================================================================*\
* Functions bellow implement a comfortable platform independent * Functions bellow implement a comfortable platform independent
* interface to sockets * interface to sockets
\*=========================================================================*/ \*=========================================================================*/
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
int socket_open(void); int socket_open(void);
int socket_close(void); int socket_close(void);
void socket_destroy(p_socket ps); void socket_destroy(p_socket ps);
void socket_shutdown(p_socket ps, int how); int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_timeout tm);
int socket_sendto(p_socket ps, const char *data, size_t count,
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_recvfrom(p_socket ps, char *data, size_t count,
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
void socket_setnonblocking(p_socket ps);
void socket_setblocking(p_socket ps);
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm);
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_create(p_socket ps, int domain, int type, int protocol); int socket_create(p_socket ps, int domain, int type, int protocol);
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
int socket_listen(p_socket ps, int backlog); int socket_listen(p_socket ps, int backlog);
int socket_accept(p_socket ps, p_socket pa, SA *addr, void socket_shutdown(p_socket ps, int how);
socklen_t *addr_len, p_timeout tm); int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *addr_len, p_timeout tm);
const char *socket_hoststrerror(int err); int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
const char *socket_strerror(int err); int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
/* these are perfect to use with the io abstraction module
and the buffered input module */
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
const char *socket_ioerror(p_socket ps, int err); int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
int socket_write(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
void socket_setblocking(p_socket ps);
void socket_setnonblocking(p_socket ps);
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
int socket_gethostbyname(const char *addr, struct hostent **hp); int socket_gethostbyname(const char *addr, struct hostent **hp);
const char *socket_hoststrerror(int err);
const char *socket_strerror(int err);
const char *socket_ioerror(p_socket ps, int err);
const char *socket_gaistrerror(int err);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* SOCKET_H */ #endif /* SOCKET_H */

View File

@@ -1,7 +1,6 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- LuaSocket helper module -- LuaSocket helper module
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -11,37 +10,52 @@ local base = _G
local string = require("string") local string = require("string")
local math = require("math") local math = require("math")
local socket = require("socket.core") local socket = require("socket.core")
module("socket")
local _M = socket
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Exported auxiliar functions -- Exported auxiliar functions
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function connect(address, port, laddress, lport) function _M.connect4(address, port, laddress, lport)
local sock, err = socket.tcp() return socket.connect(address, port, laddress, lport, "inet")
if not sock then return nil, err end end
if laddress then
local res, err = sock:bind(laddress, lport, -1) function _M.connect6(address, port, laddress, lport)
if not res then return nil, err end return socket.connect(address, port, laddress, lport, "inet6")
end
function _M.bind(host, port, backlog)
if host == "*" then host = "0.0.0.0" end
local addrinfo, err = socket.dns.getaddrinfo(host);
if not addrinfo then return nil, err end
local sock, res
err = "no info on address"
for i, alt in base.ipairs(addrinfo) do
if alt.family == "inet" then
sock, err = socket.tcp4()
else
sock, err = socket.tcp6()
end
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
res, err = sock:bind(alt.addr, port)
if not res then
sock:close()
else
res, err = sock:listen(backlog)
if not res then
sock:close()
else
return sock
end
end
end end
local res, err = sock:connect(address, port) return nil, err
if not res then return nil, err end
return sock
end end
function bind(host, port, backlog) _M.try = _M.newtry()
local sock, err = socket.tcp()
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
local res, err = sock:bind(host, port)
if not res then return nil, err end
res, err = sock:listen(backlog)
if not res then return nil, err end
return sock
end
try = newtry() function _M.choose(table)
function choose(table)
return function(name, opt1, opt2) return function(name, opt1, opt2)
if base.type(name) ~= "string" then if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1 name, opt1, opt2 = "default", name, opt1
@@ -56,10 +70,11 @@ end
-- Socket sources and sinks, conforming to LTN12 -- Socket sources and sinks, conforming to LTN12
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- create namespaces inside LuaSocket namespace -- create namespaces inside LuaSocket namespace
sourcet = {} local sourcet, sinkt = {}, {}
sinkt = {} _M.sourcet = sourcet
_M.sinkt = sinkt
BLOCKSIZE = 2048 _M.BLOCKSIZE = 2048
sinkt["close-when-done"] = function(sock) sinkt["close-when-done"] = function(sock)
return base.setmetatable({ return base.setmetatable({
@@ -89,7 +104,7 @@ end
sinkt["default"] = sinkt["keep-open"] sinkt["default"] = sinkt["keep-open"]
sink = choose(sinkt) _M.sink = _M.choose(sinkt)
sourcet["by-length"] = function(sock, length) sourcet["by-length"] = function(sock, length)
return base.setmetatable({ return base.setmetatable({
@@ -129,5 +144,6 @@ end
sourcet["default"] = sourcet["until-closed"] sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet) _M.source = _M.choose(sourcet)
return _M

290
src/tcp.c
View File

@@ -1,13 +1,8 @@
/*=========================================================================*\ /*=========================================================================*\
* TCP object * TCP object
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "socket.h" #include "socket.h"
@@ -15,12 +10,18 @@
#include "options.h" #include "options.h"
#include "tcp.h" #include "tcp.h"
#include <string.h>
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes
\*=========================================================================*/ \*=========================================================================*/
static int global_create(lua_State *L); static int global_create(lua_State *L);
static int global_create4(lua_State *L);
static int global_create6(lua_State *L);
static int global_connect(lua_State *L);
static int meth_connect(lua_State *L); static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L); static int meth_listen(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_bind(lua_State *L); static int meth_bind(lua_State *L);
static int meth_send(lua_State *L); static int meth_send(lua_State *L);
static int meth_getstats(lua_State *L); static int meth_getstats(lua_State *L);
@@ -31,14 +32,16 @@ static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L); static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L); static int meth_accept(lua_State *L);
static int meth_close(lua_State *L); static int meth_close(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L); static int meth_setoption(lua_State *L);
static int meth_gettimeout(lua_State *L);
static int meth_settimeout(lua_State *L); static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L); static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L); static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L); static int meth_dirty(lua_State *L);
/* tcp object methods */ /* tcp object methods */
static luaL_reg tcp[] = { static luaL_Reg tcp_methods[] = {
{"__gc", meth_close}, {"__gc", meth_close},
{"__tostring", auxiliar_tostring}, {"__tostring", auxiliar_tostring},
{"accept", meth_accept}, {"accept", meth_accept},
@@ -46,7 +49,9 @@ static luaL_reg tcp[] = {
{"close", meth_close}, {"close", meth_close},
{"connect", meth_connect}, {"connect", meth_connect},
{"dirty", meth_dirty}, {"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd}, {"getfd", meth_getfd},
{"getoption", meth_getoption},
{"getpeername", meth_getpeername}, {"getpeername", meth_getpeername},
{"getsockname", meth_getsockname}, {"getsockname", meth_getsockname},
{"getstats", meth_getstats}, {"getstats", meth_getstats},
@@ -59,22 +64,60 @@ static luaL_reg tcp[] = {
{"setpeername", meth_connect}, {"setpeername", meth_connect},
{"setsockname", meth_bind}, {"setsockname", meth_bind},
{"settimeout", meth_settimeout}, {"settimeout", meth_settimeout},
{"gettimeout", meth_gettimeout},
{"shutdown", meth_shutdown}, {"shutdown", meth_shutdown},
{NULL, NULL} {NULL, NULL}
}; };
/* socket option handlers */ /* socket option handlers */
static t_opt opt[] = { static t_opt optget[] = {
{"keepalive", opt_keepalive}, {"keepalive", opt_get_keepalive},
{"reuseaddr", opt_reuseaddr}, {"reuseaddr", opt_get_reuseaddr},
{"tcp-nodelay", opt_tcp_nodelay}, {"reuseport", opt_get_reuseport},
{"linger", opt_linger}, {"tcp-nodelay", opt_get_tcp_nodelay},
#ifdef TCP_KEEPIDLE
{"tcp-keepidle", opt_get_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
{"tcp-keepcnt", opt_get_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
{"tcp-keepintvl", opt_get_tcp_keepintvl},
#endif
{"linger", opt_get_linger},
{"error", opt_get_error},
{"recv-buffer-size", opt_get_recv_buf_size},
{"send-buffer-size", opt_get_send_buf_size},
{NULL, NULL}
};
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"reuseport", opt_set_reuseport},
{"tcp-nodelay", opt_set_tcp_nodelay},
#ifdef TCP_KEEPIDLE
{"tcp-keepidle", opt_set_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
{"tcp-keepcnt", opt_set_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
{"tcp-keepintvl", opt_set_tcp_keepintvl},
#endif
{"ipv6-v6only", opt_set_ip6_v6only},
{"linger", opt_set_linger},
{"recv-buffer-size", opt_set_recv_buf_size},
{"send-buffer-size", opt_set_send_buf_size},
{NULL, NULL} {NULL, NULL}
}; };
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_Reg func[] = {
{"tcp", global_create}, {"tcp", global_create},
{"tcp4", global_create4},
{"tcp6", global_create6},
{"connect", global_connect},
{NULL, NULL} {NULL, NULL}
}; };
@@ -84,15 +127,15 @@ static luaL_reg func[] = {
int tcp_open(lua_State *L) int tcp_open(lua_State *L)
{ {
/* create classes */ /* create classes */
auxiliar_newclass(L, "tcp{master}", tcp); auxiliar_newclass(L, "tcp{master}", tcp_methods);
auxiliar_newclass(L, "tcp{client}", tcp); auxiliar_newclass(L, "tcp{client}", tcp_methods);
auxiliar_newclass(L, "tcp{server}", tcp); auxiliar_newclass(L, "tcp{server}", tcp_methods);
/* create class groups */ /* create class groups */
auxiliar_add2group(L, "tcp{master}", "tcp{any}"); auxiliar_add2group(L, "tcp{master}", "tcp{any}");
auxiliar_add2group(L, "tcp{client}", "tcp{any}"); auxiliar_add2group(L, "tcp{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}"); auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */ /* define library functions */
luaL_openlib(L, NULL, func, 0); luaL_setfuncs(L, func, 0);
return 0; return 0;
} }
@@ -125,10 +168,16 @@ static int meth_setstats(lua_State *L) {
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call option handler * Just call option handler
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_getoption(L, optget, &tcp->sock);
}
static int meth_setoption(lua_State *L) static int meth_setoption(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_setoption(L, opt, &tcp->sock); return opt_meth_setoption(L, optset, &tcp->sock);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -145,7 +194,7 @@ static int meth_getfd(lua_State *L)
static int meth_setfd(lua_State *L) static int meth_setfd(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
tcp->sock = (t_socket) luaL_checknumber(L, 2); tcp->sock = (t_socket) luaL_checknumber(L, 2);
return 0; return 0;
} }
@@ -157,43 +206,50 @@ static int meth_dirty(lua_State *L)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the * Waits for and returns a client object attempting connection to the
* server object * server object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L) static int meth_accept(lua_State *L)
{ {
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
p_timeout tm = timeout_markstart(&server->tm); p_timeout tm = timeout_markstart(&server->tm);
t_socket sock; t_socket sock;
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
/* if successful, push client socket */ /* if successful, push client socket */
if (err == IO_DONE) { if (err == NULL) {
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
auxiliar_setclass(L, "tcp{client}", -1); auxiliar_setclass(L, "tcp{client}", -1);
/* initialize structure fields */ /* initialize structure fields */
memset(clnt, 0, sizeof(t_tcp));
socket_setnonblocking(&sock); socket_setnonblocking(&sock);
clnt->sock = sock; clnt->sock = sock;
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &clnt->sock); (p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1); timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm); buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
clnt->family = server->family;
return 1; return 1;
} else { } else {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, socket_strerror(err)); lua_pushstring(L, err);
return 2; return 2;
} }
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Binds an object to an address * Binds an object to an address
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L) static int meth_bind(lua_State *L) {
{
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3); const char *port = luaL_checkstring(L, 3);
const char *err = inet_trybind(&tcp->sock, address, port); const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = tcp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
if (err) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, err); lua_pushstring(L, err);
@@ -206,13 +262,19 @@ static int meth_bind(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master tcp object into a client object. * Turns a master tcp object into a client object.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_connect(lua_State *L) static int meth_connect(lua_State *L) {
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3); const char *port = luaL_checkstring(L, 3);
p_timeout tm = timeout_markstart(&tcp->tm); struct addrinfo connecthints;
const char *err = inet_tryconnect(&tcp->sock, address, port, tm); const char *err;
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = tcp->family;
timeout_markstart(&tcp->tm);
err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
&tcp->tm, &connecthints);
/* have to set the class even if it failed due to non-blocking connects */ /* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1); auxiliar_setclass(L, "tcp{client}", 1);
if (err) { if (err) {
@@ -220,13 +282,12 @@ static int meth_connect(lua_State *L)
lua_pushstring(L, err); lua_pushstring(L, err);
return 2; return 2;
} }
/* turn master object into a client object */
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Closes socket used by object * Closes socket used by object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L) static int meth_close(lua_State *L)
{ {
@@ -236,6 +297,24 @@ static int meth_close(lua_State *L)
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
if (tcp->family == AF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else if (tcp->family == AF_INET) {
lua_pushliteral(L, "inet4");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode * Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -260,27 +339,13 @@ static int meth_listen(lua_State *L)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L) static int meth_shutdown(lua_State *L)
{ {
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
const char *how = luaL_optstring(L, 2, "both"); int how = luaL_checkoption(L, 2, "both", methods);
switch (how[0]) { socket_shutdown(&tcp->sock, how);
case 'b':
if (strcmp(how, "both")) goto error;
socket_shutdown(&tcp->sock, 2);
break;
case 's':
if (strcmp(how, "send")) goto error;
socket_shutdown(&tcp->sock, 1);
break;
case 'r':
if (strcmp(how, "receive")) goto error;
socket_shutdown(&tcp->sock, 0);
break;
}
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
return 1; return 1;
error:
luaL_argerror(L, 2, "invalid shutdown method");
return 0;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -289,13 +354,13 @@ error:
static int meth_getpeername(lua_State *L) static int meth_getpeername(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getpeername(L, &tcp->sock); return inet_meth_getpeername(L, &tcp->sock, tcp->family);
} }
static int meth_getsockname(lua_State *L) static int meth_getsockname(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getsockname(L, &tcp->sock); return inet_meth_getsockname(L, &tcp->sock, tcp->family);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -307,33 +372,100 @@ static int meth_settimeout(lua_State *L)
return timeout_meth_settimeout(L, &tcp->tm); return timeout_meth_settimeout(L, &tcp->tm);
} }
static int meth_gettimeout(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return timeout_meth_gettimeout(L, &tcp->tm);
}
/*=========================================================================*\ /*=========================================================================*\
* Library functions * Library functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master tcp object * Creates a master tcp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) static int tcp_create(lua_State *L, int family) {
{ p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
t_socket sock; memset(tcp, 0, sizeof(t_tcp));
const char *err = inet_trycreate(&sock, SOCK_STREAM); /* set its type as master object */
/* try to allocate a system socket */ auxiliar_setclass(L, "tcp{master}", -1);
if (!err) { /* if family is AF_UNSPEC, we leave the socket invalid and
/* allocate tcp object */ * store AF_UNSPEC into family. This will allow it to later be
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); * replaced with an AF_INET6 or AF_INET socket upon first use. */
/* set its type as master object */ tcp->sock = SOCKET_INVALID;
auxiliar_setclass(L, "tcp{master}", -1); tcp->family = family;
/* initialize remaining structure fields */ io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
socket_setnonblocking(&sock); (p_error) socket_ioerror, &tcp->sock);
tcp->sock = sock; timeout_init(&tcp->tm, -1, -1);
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
(p_error) socket_ioerror, &tcp->sock); if (family != AF_UNSPEC) {
timeout_init(&tcp->tm, -1, -1); const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm); if (err != NULL) {
return 1; lua_pushnil(L);
} else { lua_pushstring(L, err);
return 2;
}
socket_setnonblocking(&tcp->sock);
}
return 1;
}
static int global_create(lua_State *L) {
return tcp_create(L, AF_UNSPEC);
}
static int global_create4(lua_State *L) {
return tcp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return tcp_create(L, AF_INET6);
}
static int global_connect(lua_State *L) {
const char *remoteaddr = luaL_checkstring(L, 1);
const char *remoteserv = luaL_checkstring(L, 2);
const char *localaddr = luaL_optstring(L, 3, NULL);
const char *localserv = luaL_optstring(L, 4, "0");
int family = inet_optfamily(L, 5, "unspec");
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
struct addrinfo bindhints, connecthints;
const char *err = NULL;
/* initialize tcp structure */
memset(tcp, 0, sizeof(t_tcp));
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->sock = SOCKET_INVALID;
tcp->family = AF_UNSPEC;
/* allow user to pick local address and port */
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = family;
bindhints.ai_flags = AI_PASSIVE;
if (localaddr) {
err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
localserv, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
/* try to connect to remote address and port */
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = tcp->family;
err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
&tcp->tm, &connecthints);
if (err) {
socket_destroy(&tcp->sock);
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, err); lua_pushstring(L, err);
return 2; return 2;
} }
auxiliar_setclass(L, "tcp{client}", -1);
return 1;
} }

View File

@@ -13,10 +13,8 @@
* objects are tcp objects bound to some local address. Client objects are * objects are tcp objects bound to some local address. Client objects are
* tcp objects either connected to some address or returned by the accept * tcp objects either connected to some address or returned by the accept
* method of a server object. * method of a server object.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "buffer.h" #include "buffer.h"
#include "timeout.h" #include "timeout.h"
@@ -27,10 +25,19 @@ typedef struct t_tcp_ {
t_io io; t_io io;
t_buffer buf; t_buffer buf;
t_timeout tm; t_timeout tm;
int family;
} t_tcp; } t_tcp;
typedef t_tcp *p_tcp; typedef t_tcp *p_tcp;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int tcp_open(lua_State *L); int tcp_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* TCP_H */ #endif /* TCP_H */

View File

@@ -1,17 +1,16 @@
/*=========================================================================*\ /*=========================================================================*\
* Timeout management functions * Timeout management functions
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <stdio.h> #include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "timeout.h" #include "timeout.h"
#include <stdio.h>
#include <limits.h>
#include <float.h>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#else #else
@@ -33,7 +32,7 @@
static int timeout_lua_gettime(lua_State *L); static int timeout_lua_gettime(lua_State *L);
static int timeout_lua_sleep(lua_State *L); static int timeout_lua_sleep(lua_State *L);
static luaL_reg func[] = { static luaL_Reg func[] = {
{ "gettime", timeout_lua_gettime }, { "gettime", timeout_lua_gettime },
{ "sleep", timeout_lua_sleep }, { "sleep", timeout_lua_sleep },
{ NULL, NULL } { NULL, NULL }
@@ -52,7 +51,7 @@ void timeout_init(p_timeout tm, double block, double total) {
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Determines how much time we have left for the next system call, * Determines how much time we have left for the next system call,
* if the previous call was successful * if the previous call was successful
* Input * Input
* tm: timeout control structure * tm: timeout control structure
* Returns * Returns
@@ -107,7 +106,7 @@ double timeout_getretry(p_timeout tm) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Marks the operation start time in structure * Marks the operation start time in structure
* Input * Input
* tm: timeout control structure * tm: timeout control structure
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -117,7 +116,7 @@ p_timeout timeout_markstart(p_timeout tm) {
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Gets time in s, relative to January 1, 1970 (UTC) * Gets time in s, relative to January 1, 1970 (UTC)
* Returns * Returns
* time in s. * time in s.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
@@ -144,7 +143,7 @@ double timeout_gettime(void) {
* Initializes module * Initializes module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int timeout_open(lua_State *L) { int timeout_open(lua_State *L) {
luaL_openlib(L, NULL, func, 0); luaL_setfuncs(L, func, 0);
return 0; return 0;
} }
@@ -159,7 +158,7 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
const char *mode = luaL_optstring(L, 3, "b"); const char *mode = luaL_optstring(L, 3, "b");
switch (*mode) { switch (*mode) {
case 'b': case 'b':
tm->block = t; tm->block = t;
break; break;
case 'r': case 't': case 'r': case 't':
tm->total = t; tm->total = t;
@@ -172,6 +171,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\
* Gets timeout values for IO operations
* Lua Output: block, total
\*-------------------------------------------------------------------------*/
int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
lua_pushnumber(L, tm->block);
lua_pushnumber(L, tm->total);
return 2;
}
/*=========================================================================*\ /*=========================================================================*\
* Test support functions * Test support functions
\*=========================================================================*/ \*=========================================================================*/
@@ -187,13 +196,23 @@ static int timeout_lua_gettime(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Sleep for n seconds. * Sleep for n seconds.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#ifdef _WIN32
int timeout_lua_sleep(lua_State *L) int timeout_lua_sleep(lua_State *L)
{ {
double n = luaL_checknumber(L, 1); double n = luaL_checknumber(L, 1);
#ifdef _WIN32 if (n < 0.0) n = 0.0;
Sleep((int)(n*1000)); if (n < DBL_MAX/1000.0) n *= 1000.0;
if (n > INT_MAX) n = INT_MAX;
Sleep((int)n);
return 0;
}
#else #else
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
struct timespec t, r; struct timespec t, r;
if (n < 0.0) n = 0.0;
if (n > INT_MAX) n = INT_MAX;
t.tv_sec = (int) n; t.tv_sec = (int) n;
n -= t.tv_sec; n -= t.tv_sec;
t.tv_nsec = (int) (n * 1000000000); t.tv_nsec = (int) (n * 1000000000);
@@ -202,6 +221,6 @@ int timeout_lua_sleep(lua_State *L)
t.tv_sec = r.tv_sec; t.tv_sec = r.tv_sec;
t.tv_nsec = r.tv_nsec; t.tv_nsec = r.tv_nsec;
} }
#endif
return 0; return 0;
} }
#endif

View File

@@ -3,10 +3,8 @@
/*=========================================================================*\ /*=========================================================================*\
* Timeout management functions * Timeout management functions
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
/* timeout control structure */ /* timeout control structure */
typedef struct t_timeout_ { typedef struct t_timeout_ {
@@ -16,14 +14,26 @@ typedef struct t_timeout_ {
} t_timeout; } t_timeout;
typedef t_timeout *p_timeout; typedef t_timeout *p_timeout;
int timeout_open(lua_State *L); #ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
void timeout_init(p_timeout tm, double block, double total); void timeout_init(p_timeout tm, double block, double total);
double timeout_get(p_timeout tm); double timeout_get(p_timeout tm);
double timeout_getstart(p_timeout tm);
double timeout_getretry(p_timeout tm); double timeout_getretry(p_timeout tm);
p_timeout timeout_markstart(p_timeout tm); p_timeout timeout_markstart(p_timeout tm);
double timeout_getstart(p_timeout tm);
double timeout_gettime(void); double timeout_gettime(void);
int timeout_open(lua_State *L);
int timeout_meth_settimeout(lua_State *L, p_timeout tm); int timeout_meth_settimeout(lua_State *L, p_timeout tm);
int timeout_meth_gettimeout(lua_State *L, p_timeout tm);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#define timeout_iszero(tm) ((tm)->block == 0.0) #define timeout_iszero(tm) ((tm)->block == 0.0)

View File

@@ -2,7 +2,6 @@
-- Unified SMTP/FTP subsystem -- Unified SMTP/FTP subsystem
-- LuaSocket toolkit. -- LuaSocket toolkit.
-- Author: Diego Nehab -- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@@ -12,12 +11,14 @@ local base = _G
local string = require("string") local string = require("string")
local socket = require("socket") local socket = require("socket")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
module("socket.tp")
socket.tp = {}
local _M = socket.tp
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Program constants -- Program constants
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
TIMEOUT = 60 _M.TIMEOUT = 60
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Implementation -- Implementation
@@ -45,6 +46,14 @@ end
-- metatable for sock object -- metatable for sock object
local metat = { __index = {} } local metat = { __index = {} }
function metat.__index:getpeername()
return self.c:getpeername()
end
function metat.__index:getsockname()
return self.c:getpeername()
end
function metat.__index:check(ok) function metat.__index:check(ok)
local code, reply = get_reply(self.c) local code, reply = get_reply(self.c)
if not code then return nil, reply end if not code then return nil, reply end
@@ -64,6 +73,7 @@ function metat.__index:check(ok)
end end
function metat.__index:command(cmd, arg) function metat.__index:command(cmd, arg)
cmd = string.upper(cmd)
if arg then if arg then
return self.c:send(cmd .. " " .. arg.. "\r\n") return self.c:send(cmd .. " " .. arg.. "\r\n")
else else
@@ -72,7 +82,7 @@ function metat.__index:command(cmd, arg)
end end
function metat.__index:sink(snk, pat) function metat.__index:sink(snk, pat)
local chunk, err = c:receive(pat) local chunk, err = self.c:receive(pat)
return snk(chunk, err) return snk(chunk, err)
end end
@@ -105,14 +115,14 @@ end
-- closes the underlying c -- closes the underlying c
function metat.__index:close() function metat.__index:close()
self.c:close() self.c:close()
return 1 return 1
end end
-- connect with server and return c object -- connect with server and return c object
function connect(host, port, timeout, create) function _M.connect(host, port, timeout, create)
local c, e = (create or socket.tcp)() local c, e = (create or socket.tcp)()
if not c then return nil, e end if not c then return nil, e end
c:settimeout(timeout or TIMEOUT) c:settimeout(timeout or _M.TIMEOUT)
local r, e = c:connect(host, port) local r, e = c:connect(host, port)
if not r then if not r then
c:close() c:close()
@@ -121,3 +131,4 @@ function connect(host, port, timeout, create)
return base.setmetatable({c = c}, metat) return base.setmetatable({c = c}, metat)
end end
return _M

338
src/udp.c
View File

@@ -1,13 +1,8 @@
/*=========================================================================*\ /*=========================================================================*\
* UDP object * UDP object
* LuaSocket toolkit * LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h" #include "auxiliar.h"
#include "socket.h" #include "socket.h"
@@ -15,39 +10,48 @@
#include "options.h" #include "options.h"
#include "udp.h" #include "udp.h"
#include <string.h>
#include <stdlib.h>
/* min and max macros */ /* min and max macros */
#ifndef MIN #ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y) #define MIN(x, y) ((x) < (y) ? x : y)
#endif #endif
#ifndef MAX #ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y) #define MAX(x, y) ((x) > (y) ? x : y)
#endif #endif
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes
\*=========================================================================*/ \*=========================================================================*/
static int global_create(lua_State *L); static int global_create(lua_State *L);
static int global_create4(lua_State *L);
static int global_create6(lua_State *L);
static int meth_send(lua_State *L); static int meth_send(lua_State *L);
static int meth_sendto(lua_State *L); static int meth_sendto(lua_State *L);
static int meth_receive(lua_State *L); static int meth_receive(lua_State *L);
static int meth_receivefrom(lua_State *L); static int meth_receivefrom(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_getsockname(lua_State *L); static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L); static int meth_getpeername(lua_State *L);
static int meth_gettimeout(lua_State *L);
static int meth_setsockname(lua_State *L); static int meth_setsockname(lua_State *L);
static int meth_setpeername(lua_State *L); static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L); static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L); static int meth_setoption(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_settimeout(lua_State *L); static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L); static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L); static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L); static int meth_dirty(lua_State *L);
/* udp object methods */ /* udp object methods */
static luaL_reg udp[] = { static luaL_Reg udp_methods[] = {
{"__gc", meth_close}, {"__gc", meth_close},
{"__tostring", auxiliar_tostring}, {"__tostring", auxiliar_tostring},
{"close", meth_close}, {"close", meth_close},
{"dirty", meth_dirty}, {"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd}, {"getfd", meth_getfd},
{"getpeername", meth_getpeername}, {"getpeername", meth_getpeername},
{"getsockname", meth_getsockname}, {"getsockname", meth_getsockname},
@@ -57,52 +61,87 @@ static luaL_reg udp[] = {
{"sendto", meth_sendto}, {"sendto", meth_sendto},
{"setfd", meth_setfd}, {"setfd", meth_setfd},
{"setoption", meth_setoption}, {"setoption", meth_setoption},
{"getoption", meth_getoption},
{"setpeername", meth_setpeername}, {"setpeername", meth_setpeername},
{"setsockname", meth_setsockname}, {"setsockname", meth_setsockname},
{"settimeout", meth_settimeout}, {"settimeout", meth_settimeout},
{"gettimeout", meth_gettimeout},
{NULL, NULL} {NULL, NULL}
}; };
/* socket options */ /* socket options for setoption */
static t_opt opt[] = { static t_opt optset[] = {
{"dontroute", opt_dontroute}, {"dontroute", opt_set_dontroute},
{"broadcast", opt_broadcast}, {"broadcast", opt_set_broadcast},
{"reuseaddr", opt_reuseaddr}, {"reuseaddr", opt_set_reuseaddr},
{"ip-multicast-ttl", opt_ip_multicast_ttl}, {"reuseport", opt_set_reuseport},
{"ip-multicast-loop", opt_ip_multicast_loop}, {"ip-multicast-if", opt_set_ip_multicast_if},
{"ip-add-membership", opt_ip_add_membership}, {"ip-multicast-ttl", opt_set_ip_multicast_ttl},
{"ip-drop-membership", opt_ip_drop_membersip}, {"ip-multicast-loop", opt_set_ip_multicast_loop},
{NULL, NULL} {"ip-add-membership", opt_set_ip_add_membership},
{"ip-drop-membership", opt_set_ip_drop_membersip},
{"ipv6-unicast-hops", opt_set_ip6_unicast_hops},
{"ipv6-multicast-hops", opt_set_ip6_unicast_hops},
{"ipv6-multicast-loop", opt_set_ip6_multicast_loop},
{"ipv6-add-membership", opt_set_ip6_add_membership},
{"ipv6-drop-membership", opt_set_ip6_drop_membersip},
{"ipv6-v6only", opt_set_ip6_v6only},
{"recv-buffer-size", opt_set_recv_buf_size},
{"send-buffer-size", opt_set_send_buf_size},
{NULL, NULL}
};
/* socket options for getoption */
static t_opt optget[] = {
{"dontroute", opt_get_dontroute},
{"broadcast", opt_get_broadcast},
{"reuseaddr", opt_get_reuseaddr},
{"reuseport", opt_get_reuseport},
{"ip-multicast-if", opt_get_ip_multicast_if},
{"ip-multicast-loop", opt_get_ip_multicast_loop},
{"error", opt_get_error},
{"ipv6-unicast-hops", opt_get_ip6_unicast_hops},
{"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
{"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
{"ipv6-v6only", opt_get_ip6_v6only},
{"recv-buffer-size", opt_get_recv_buf_size},
{"send-buffer-size", opt_get_send_buf_size},
{NULL, NULL}
}; };
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_Reg func[] = {
{"udp", global_create}, {"udp", global_create},
{"udp4", global_create4},
{"udp6", global_create6},
{NULL, NULL} {NULL, NULL}
}; };
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes module * Initializes module
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int udp_open(lua_State *L) int udp_open(lua_State *L) {
{
/* create classes */ /* create classes */
auxiliar_newclass(L, "udp{connected}", udp); auxiliar_newclass(L, "udp{connected}", udp_methods);
auxiliar_newclass(L, "udp{unconnected}", udp); auxiliar_newclass(L, "udp{unconnected}", udp_methods);
/* create class groups */ /* create class groups */
auxiliar_add2group(L, "udp{connected}", "udp{any}"); auxiliar_add2group(L, "udp{connected}", "udp{any}");
auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
auxiliar_add2group(L, "udp{connected}", "select{able}"); auxiliar_add2group(L, "udp{connected}", "select{able}");
auxiliar_add2group(L, "udp{unconnected}", "select{able}"); auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */ /* define library functions */
luaL_openlib(L, NULL, func, 0); luaL_setfuncs(L, func, 0);
/* export default UDP size */
lua_pushliteral(L, "_DATAGRAMSIZE");
lua_pushinteger(L, UDP_DATAGRAMSIZE);
lua_rawset(L, -3);
return 0; return 0;
} }
/*=========================================================================*\ /*=========================================================================*\
* Lua methods * Lua methods
\*=========================================================================*/ \*=========================================================================*/
const char *udp_strerror(int err) { static const char *udp_strerror(int err) {
/* a 'closed' error on an unconnected means the target address was not /* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */ * accepted by the transport layer */
if (err == IO_CLOSED) return "refused"; if (err == IO_CLOSED) return "refused";
@@ -125,7 +164,7 @@ static int meth_send(lua_State *L) {
lua_pushstring(L, udp_strerror(err)); lua_pushstring(L, udp_strerror(err));
return 2; return 2;
} }
lua_pushnumber(L, sent); lua_pushnumber(L, (lua_Number) sent);
return 1; return 1;
} }
@@ -137,24 +176,55 @@ static int meth_sendto(lua_State *L) {
size_t count, sent = 0; size_t count, sent = 0;
const char *data = luaL_checklstring(L, 2, &count); const char *data = luaL_checklstring(L, 2, &count);
const char *ip = luaL_checkstring(L, 3); const char *ip = luaL_checkstring(L, 3);
unsigned short port = (unsigned short) luaL_checknumber(L, 4); const char *port = luaL_checkstring(L, 4);
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
struct sockaddr_in addr;
int err; int err;
memset(&addr, 0, sizeof(addr)); struct addrinfo aihint;
if (!inet_aton(ip, &addr.sin_addr)) struct addrinfo *ai;
luaL_argerror(L, 3, "invalid ip address"); memset(&aihint, 0, sizeof(aihint));
addr.sin_family = AF_INET; aihint.ai_family = udp->family;
addr.sin_port = htons(port); aihint.ai_socktype = SOCK_DGRAM;
aihint.ai_flags = AI_NUMERICHOST;
#ifdef AI_NUMERICSERV
aihint.ai_flags |= AI_NUMERICSERV;
#endif
err = getaddrinfo(ip, port, &aihint, &ai);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
/* create socket if on first sendto if AF_UNSPEC was set */
if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) {
struct addrinfo *ap;
const char *errstr = NULL;
for (ap = ai; ap != NULL; ap = ap->ai_next) {
errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0);
if (errstr == NULL) {
socket_setnonblocking(&udp->sock);
udp->family = ap->ai_family;
break;
}
}
if (errstr != NULL) {
lua_pushnil(L);
lua_pushstring(L, errstr);
freeaddrinfo(ai);
return 2;
}
}
timeout_markstart(tm); timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent, err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
(SA *) &addr, sizeof(addr), tm); (socklen_t) ai->ai_addrlen, tm);
freeaddrinfo(ai);
if (err != IO_DONE) { if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, udp_strerror(err)); lua_pushstring(L, udp_strerror(err));
return 2; return 2;
} }
lua_pushnumber(L, sent); lua_pushnumber(L, (lua_Number) sent);
return 1; return 1;
} }
@@ -163,19 +233,27 @@ static int meth_sendto(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_receive(lua_State *L) { static int meth_receive(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
char buffer[UDP_DATAGRAMSIZE]; char buf[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
int err; int err;
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
count = MIN(count, sizeof(buffer));
timeout_markstart(tm); timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm); if (!dgram) {
if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, udp_strerror(err)); lua_pushliteral(L, "out of memory");
return 2; return 2;
} }
lua_pushlstring(L, buffer, got); err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
if (wanted > sizeof(buf)) free(dgram);
return 1; return 1;
} }
@@ -184,26 +262,57 @@ static int meth_receive(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L) { static int meth_receivefrom(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
struct sockaddr_in addr; char buf[UDP_DATAGRAMSIZE];
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
char buffer[UDP_DATAGRAMSIZE]; char addrstr[INET6_ADDRSTRLEN];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); char portstr[6];
int err; int err;
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
timeout_markstart(tm); timeout_markstart(tm);
count = MIN(count, sizeof(buffer)); if (!dgram) {
err = socket_recvfrom(&udp->sock, buffer, count, &got, lua_pushnil(L);
(SA *) &addr, &addr_len, tm); lua_pushliteral(L, "out of memory");
if (err == IO_DONE) { return 2;
lua_pushlstring(L, buffer, got); }
lua_pushstring(L, inet_ntoa(addr.sin_addr)); err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
lua_pushnumber(L, ntohs(addr.sin_port)); &addr_len, tm);
return 3; /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
} else { if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, udp_strerror(err)); lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2; return 2;
} }
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
lua_pushstring(L, addrstr);
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
if (wanted > sizeof(buf)) free(dgram);
return 3;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
if (udp->family == AF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -234,12 +343,12 @@ static int meth_dirty(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_getpeername(lua_State *L) { static int meth_getpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
return inet_meth_getpeername(L, &udp->sock); return inet_meth_getpeername(L, &udp->sock, udp->family);
} }
static int meth_getsockname(lua_State *L) { static int meth_getsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return inet_meth_getsockname(L, &udp->sock); return inet_meth_getsockname(L, &udp->sock, udp->family);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -247,7 +356,15 @@ static int meth_getsockname(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) { static int meth_setoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_setoption(L, opt, &udp->sock); return opt_meth_setoption(L, optset, &udp->sock);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_getoption(L, optget, &udp->sock);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@@ -258,32 +375,47 @@ static int meth_settimeout(lua_State *L) {
return timeout_meth_settimeout(L, &udp->tm); return timeout_meth_settimeout(L, &udp->tm);
} }
static int meth_gettimeout(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return timeout_meth_gettimeout(L, &udp->tm);
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master udp object into a client object. * Turns a master udp object into a client object.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_setpeername(lua_State *L) { static int meth_setpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
int connecting = strcmp(address, "*"); int connecting = strcmp(address, "*");
unsigned short port = connecting ? const char *port = connecting? luaL_checkstring(L, 3): "0";
(unsigned short) luaL_checknumber(L, 3) : struct addrinfo connecthints;
(unsigned short) luaL_optnumber(L, 3, 0); const char *err;
const char *err = inet_tryconnect(&udp->sock, address, port, tm); memset(&connecthints, 0, sizeof(connecthints));
if (err) { connecthints.ai_socktype = SOCK_DGRAM;
lua_pushnil(L); /* make sure we try to connect only to the same family */
lua_pushstring(L, err); connecthints.ai_family = udp->family;
return 2; if (connecting) {
err = inet_tryconnect(&udp->sock, &udp->family, address,
port, tm, &connecthints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
auxiliar_setclass(L, "udp{connected}", 1);
} else {
/* we ignore possible errors because Mac OS X always
* returns EAFNOSUPPORT */
inet_trydisconnect(&udp->sock, udp->family, tm);
auxiliar_setclass(L, "udp{unconnected}", 1);
} }
/* change class to connected or unconnected depending on address */
if (connecting) auxiliar_setclass(L, "udp{connected}", 1);
else auxiliar_setclass(L, "udp{unconnected}", 1);
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Closes socket used by object * Closes socket used by object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L) { static int meth_close(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
@@ -298,8 +430,14 @@ static int meth_close(lua_State *L) {
static int meth_setsockname(lua_State *L) { static int meth_setsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3); const char *port = luaL_checkstring(L, 3);
const char *err = inet_trybind(&udp->sock, address, port); const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_DGRAM;
bindhints.ai_family = udp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
if (err) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, err); lua_pushstring(L, err);
@@ -313,24 +451,38 @@ static int meth_setsockname(lua_State *L) {
* Library functions * Library functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master udp object * Creates a master udp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) { static int udp_create(lua_State *L, int family) {
t_socket sock; /* allocate udp object */
const char *err = inet_trycreate(&sock, SOCK_DGRAM); p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
/* try to allocate a system socket */ auxiliar_setclass(L, "udp{unconnected}", -1);
if (!err) { /* if family is AF_UNSPEC, we leave the socket invalid and
/* allocate tcp object */ * store AF_UNSPEC into family. This will allow it to later be
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); * replaced with an AF_INET6 or AF_INET socket upon first use. */
auxiliar_setclass(L, "udp{unconnected}", -1); udp->sock = SOCKET_INVALID;
/* initialize remaining structure fields */ timeout_init(&udp->tm, -1, -1);
socket_setnonblocking(&sock); udp->family = family;
udp->sock = sock; if (family != AF_UNSPEC) {
timeout_init(&udp->tm, -1, -1); const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
return 1; if (err != NULL) {
} else { lua_pushnil(L);
lua_pushnil(L); lua_pushstring(L, err);
lua_pushstring(L, err); return 2;
return 2; }
socket_setnonblocking(&udp->sock);
} }
return 1;
}
static int global_create(lua_State *L) {
return udp_create(L, AF_UNSPEC);
}
static int global_create4(lua_State *L) {
return udp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return udp_create(L, AF_INET6);
} }

View File

@@ -8,26 +8,32 @@
* (AF_INET, SOCK_DGRAM). * (AF_INET, SOCK_DGRAM).
* *
* Two classes are defined: connected and unconnected. UDP objects are * Two classes are defined: connected and unconnected. UDP objects are
* originally unconnected. They can be "connected" to a given address * originally unconnected. They can be "connected" to a given address
* with a call to the setpeername function. The same function can be used to * with a call to the setpeername function. The same function can be used to
* break the connection. * break the connection.
*
* RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "lua.h" #include "luasocket.h"
#include "timeout.h" #include "timeout.h"
#include "socket.h" #include "socket.h"
/* can't be larger than wsocket.c MAXCHUNK!!! */
#define UDP_DATAGRAMSIZE 8192 #define UDP_DATAGRAMSIZE 8192
typedef struct t_udp_ { typedef struct t_udp_ {
t_socket sock; t_socket sock;
t_timeout tm; t_timeout tm;
int family;
} t_udp; } t_udp;
typedef t_udp *p_udp; typedef t_udp *p_udp;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int udp_open(lua_State *L); int udp_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* UDP_H */ #endif /* UDP_H */

Some files were not shown because too many files have changed in this diff Show More