421 Commits

Author SHA1 Message Date
95b7efa9da chore: Release v3.1.0 2022-07-27 10:07:00 +03:00
80503077db ci: Echo correct platform in job title 2022-07-27 09:55:54 +03:00
5a7e3f0888 fix(build): Use gai_strerrorA not gai_strerror on Windows
* Explicitly call gai_strerrorA (for Windows builds), so that the code work correctly in 32bit or 64bit builds.

* Implement GAI_STRERROR macro to deal with Windows vs. Non-Windows compiles for 64-bit.

* make usocket.c consistent with other modules that call macro GAI_STRERROR

* Use different name not just different case for macro wrapping function

Co-authored-by: Caleb Maclennan <caleb@alerque.com>
2022-07-27 09:51:35 +03:00
d1ad8160cb feat(tcp): Add support for TCP Defer Accept
This makes it so that a listening socket does not become readable for
accept() until a connection has been fully established *and* started
sending something, thus the program doesn't have to wait for the first
data. This only makes sense for client-speaks-first protocols.

Co-authored-by: Caleb Maclennan <caleb@alerque.com>
2022-07-27 09:40:18 +03:00
0c7df119c2 feat(tcp): Add support for TCP Fast Open 2022-07-27 09:16:43 +03:00
cff09ffb32 chore(rockspec): Move recent PR change to proper rockspec (#384) 2022-07-26 23:39:17 +03:00
38c7b5161b fix(rockspec): Fixup Windows (mingw32) builds (#383) 2022-07-26 23:24:25 +03:00
1d61853ab8 chore: Update internal version references to match release (#370) 2022-03-28 11:53:32 +00:00
88c8a85cb6 chore: Release v3.0.0 2022-03-25 11:05:48 +03:00
020c2c746b chore: Copy-edit description in dev rockspec 2022-03-25 10:59:23 +03:00
f7f0a77a3d docs: Drop obsolete changelog from docs index 2022-03-25 10:59:23 +03:00
d3777f9d06 chore: Start a Markdown era readme 2022-03-25 10:59:23 +03:00
e863315729 chore: Draft v3 release notes 2022-03-25 10:59:23 +03:00
b5b60f9d6f chore: Refactor existing news file as a changelog 2022-03-25 10:59:23 +03:00
e47d98f401 Merge pull request #356 from lunarmodules/test-builds 2022-03-24 18:15:42 +03:00
bac0b8dc27 ci: Use reusable workflow for luarocks deploy 2022-03-24 18:14:43 +03:00
2de8ddfbb8 Merge remote-tracking branch 'upstream/master' into test-builds 2022-03-24 18:11:07 +03:00
5ed8b66e6d ci: Utilize new upstream Luacheck Action (#367) 2022-03-24 13:22:31 +01:00
78d2cbfdee Merge pull request #366 from lunarmodules/54 2022-03-23 17:17:49 +01:00
d9c08114da chore; add Lua 5.4 to make files 2022-03-23 17:11:43 +01:00
58f94e47d2 Update LICENSE to be recognizable as MIT (#363) 2022-03-23 15:12:49 +03:00
af0ddb6ea8 Merge pull request #361 from lunarmodules/docs 2022-03-23 07:55:45 +01:00
2eac895039 Update URL references to source repository 2022-03-23 00:16:23 +03:00
f98977b2da Move doc→docs so we can serve it with GitHub Pages 2022-03-23 00:11:24 +03:00
c1eacfa6d2 fix(docs) references to some constants added (#359) 2022-03-22 21:24:38 +03:00
f97dc8489d fix(docs) fix html linter issues in the docs (#358) 2022-03-22 21:21:58 +03:00
f9e1d03f3c ci: Don't bother doing user-local install in ephemeral runner 2022-03-22 15:53:22 +03:00
52c72694c2 ci: Disable unsupported Windows and avoid duplicate runs 2022-03-22 15:53:22 +03:00
9787c17e58 ci: Expand test matrix to cover Windows and macOS 2022-03-22 15:53:22 +03:00
fdd741da5c Ci: Run regression tests after successful build 2022-03-22 15:53:21 +03:00
d3434c0198 Merge pull request #318 from tokenrove/transfer-encoding-chunked 2022-03-22 09:39:02 +01:00
2a76cb906c http.lua: set transfer-encoding if source and no content-length
If a source is specified without a content-length header, LuaSocket
sends the data in the chunked transfer coding; however, it doesn't set
the transfer-encoding header.  While I recognize that the user can set
this manually, this is a gotcha that has caught me multiple times.

RFC7230, section 3.3.3
  (https://tools.ietf.org/html/rfc7230#section-3.3.3)
is clear about this; if neither content-length nor transfer-encoding
chunked are specified, the request message body length is zero.  While
some servers may ignore this, I have encountered several that follow
the RFC in this regard, most recently golang's net/http.
2022-03-22 09:38:14 +01:00
e178b1e018 Update URLs in (and to) SCM rockspec, start an epoch #355 2022-03-22 09:34:30 +01:00
642433e771 Merge pull request #275 from ewestbrook/vcxproj-mime-socket 2022-03-22 09:30:25 +01:00
e3c17b002a Add src\compat.c to mime.vcxproj and socket.vcxproj 2022-03-22 09:29:04 +01:00
b57ca9bfa3 Merge pull request #351 from jyoui/patch-1 2022-03-21 11:08:48 +01:00
46ecb7e2dc src/ltn12.lua: remove duplicated codes 2022-03-21 11:07:26 +01:00
2cc6f8a55c ci: Add workflow to confirm build completes 2022-03-19 21:05:22 +03:00
844165ff89 ci: Drop obsolete Travis configs 2022-03-19 18:24:15 +03:00
91aa6522a0 chore: Drop rockspec for never-published RC2 release 2022-03-19 18:20:52 +03:00
335f647075 chore: Add current most recent rockspec as published 2022-03-19 18:20:05 +03:00
36428e07cd chore: Rename rockspec dir to be plural 2022-03-19 18:01:53 +03:00
d0f2d132bf chore: Move SCM rockspec to root and bump rockrel to 3 2022-03-19 18:01:53 +03:00
a36818d3f3 Merge pull request #354 from lunarmodules/linter 2022-03-19 17:42:53 +03:00
8390d07774 chore: Bump Lua version used in linter 2022-03-19 17:34:28 +03:00
989a5b1131 chore: Include luacheck config in editorconfig setup 2022-03-19 17:28:25 +03:00
601ad8d59f refactor: Address issues raised by linter 2022-03-19 17:13:15 +03:00
480c052572 ci: Add workflow to run luacheck linter 2022-03-19 17:13:15 +03:00
f6509d4fd5 chore: Add luacheck linter project configuration 2022-03-19 17:13:15 +03:00
52b22da7e3 chore: Add editorconfig setup file 2022-03-19 17:05:43 +03:00
6952262e6a style: Use C-style comment syntax throughout (#309)
Co-authored-by: Denise Cullassnekuff <19711487+BlackCutpoint@users.noreply.github.com>
2022-03-18 17:54:11 +03:00
d9cc531e3b Fixe an issue with aux buffer init overwriting optional parameters in receive() (#334)
Fixes use on Lua >= 5.4.3
2022-03-18 12:23:09 +03:00
5b18e475f3 test/find-connect-limit: add missing "socket =" 2020-03-28 22:21:23 +00:00
743a5f1bcf test/udp-zero-length-send-recv: add missing "socket ="; use shebang "#!/usr/bin/env lua" 2020-03-28 22:21:23 +00:00
a7baf8dc25 test/udp-zero-length-send: add missing "socket ="; use shebang "#!/usr/bin/env lua" 2020-03-28 22:21:23 +00:00
c8b4fdf858 test/getoptions: guard calls with pcall(); check result of getoption"linger" 2020-03-28 22:21:23 +00:00
84e5336e8b test/tcp-getoptions: bugfix: missing "socket =" in require"socket" 2020-03-28 22:21:23 +00:00
78a1657c7d src/makefile: remove -DLUASOCKET_INET_PTON as current mingw builds don't want it 2020-03-28 16:46:49 +00:00
733af884f1 Merge pull request #280 from ewestbrook/rockspec-scm
SCM rockspec housekeeping
2019-04-22 00:27:05 -03:00
ab3b0ef5c9 rockspec/luasocket-scm-2.rockspec 2019-04-21 09:41:17 -06:00
9acb6dc81a move SCM rockspec to rockspec folder; rename consistent with luarocks repository 2019-04-21 09:31:08 -06:00
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
21514304be wrap visibility pragmas in #ifndef _WIN32 2019-03-10 00:04:20 -07:00
3a37ab8890 rockspecs: unix += compat 2019-03-10 00:04:20 -07:00
33883e78c8 rockspecs: serial += compat 2019-03-10 00:04:20 -07:00
c8d0fdda54 src/makefile: serial += compat 2019-03-10 00:04:20 -07:00
8b2dcdcf7d usocket: pragma visibility 2019-03-10 00:04:20 -07:00
4e363330a3 unixstream: pragma visibility 2019-03-10 00:04:20 -07:00
d27b1a7945 unixdgram: pragma visibility 2019-03-10 00:04:20 -07:00
5d07d9b227 unix: include reorg 2019-03-10 00:04:20 -07:00
d71e6bc459 udp: pragma visibility 2019-03-10 00:04:20 -07:00
42a1a732b7 timeout: pragma visibility 2019-03-10 00:04:20 -07:00
86e1b3f45f tcp: pragma visibility 2019-03-10 00:04:20 -07:00
1fa10673f7 socket.h: pragma visibility 2019-03-10 00:04:20 -07:00
c8b9b40eda serial.c: pragma visibiliity 2019-03-10 00:04:20 -07:00
c2245f35c5 select: pragma visibility 2019-03-10 00:04:20 -07:00
ce6a08d57d options: pragma visibility 2019-03-10 00:04:20 -07:00
83648f8df2 mime: include reorg 2019-03-10 00:04:20 -07:00
2015290cb4 luasocket: include centralization 2019-03-10 00:03:04 -07:00
ee30e4643d io: pragma visibility 2019-03-10 00:03:04 -07:00
611cdd19cc inet: pragma visibility 2019-03-10 00:03:04 -07:00
4bf3eb6db2 except: pragma visibility 2019-03-10 00:03:04 -07:00
133774cd3d compat: pragma visibility 2019-03-10 00:03:04 -07:00
e3ac49efbd buffer: pragma visibility 2019-03-10 00:03:04 -07:00
98800e9129 auxiliar: pragma visibility 2019-03-10 00:03:04 -07:00
2af4872a40 Fix formatting. 2019-03-10 00:47:17 -03:00
03b72d8f7e Use static initialization
This helps with multi-threaded apps.
2019-03-09 23:23:48 -03:00
c7215bef07 Remove .filters and hardcoded platform. 2019-03-02 17:47:18 -03:00
1e4255e2a9 Update Windows projects vor Visual Studio 2017 2019-03-01 20:46:37 -03:00
5cc91ab600 Merge pull request #272 from ewestbrook/pr268bugfix
bugfix: http.lua confict resolution omission
2019-03-01 00:38:44 -03:00
297f9d0277 bugfix: http.lua multischeme change that got dropped during PR conflict resolution 2019-02-28 18:40:30 -07:00
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
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
c0fba03e4f Merge pull request #270 from ewestbrook/functionvisibility
Tag functions explicitly for shared library visibility
2019-02-26 00:06:02 -03:00
e2e43d62fa rockspecs: remove visibility and dllexport defines in favor of in-source labeling 2019-02-25 16:07:36 -07:00
2d8f0d9901 src/makefile: remove visibility and dllexport defines in favor of in-source labeling 2019-02-25 16:04:49 -07:00
f8183bab87 usocket.c: use LUASOCKET_PRIVATE 2019-02-25 16:04:29 -07:00
d7ffc2f4e6 usocket.c use LUASOCKET_PRIVATE 2019-02-25 16:04:16 -07:00
fe437ee844 unixstream.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:44 -07:00
678d558c5f unixdgram.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:33 -07:00
30a0a6003b udp.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:21 -07:00
87c2dee13e timeout.c: use LUASOCKET_PRIVATE 2019-02-25 16:01:04 -07:00
525d703e16 tcp.c: use LUASOCKET_PRIVATE 2019-02-25 16:00:51 -07:00
898f2df025 serial.c: include luasocket.h 2019-02-25 16:00:38 -07:00
fae993c118 select.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:29 -07:00
ef2a3fcedb options.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:19 -07:00
3f19a052e8 io.c: use LUASOCKET_PRIVATE 2019-02-25 15:59:09 -07:00
731b23bc89 inet.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:54 -07:00
395729d431 except.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:45 -07:00
2bf6730fd5 pragma.c: use LUASOCKET_PRIVATE 2019-02-25 15:58:30 -07:00
b95527e140 buffer.c: use LUASOCKET_PRIVATE 2019-02-25 15:57:25 -07:00
c0374dd46f auxiliar.c: use LUASOCKET_PRIVATE 2019-02-25 15:57:01 -07:00
16b0026e27 unix.c: use LUASOCKET_API 2019-02-25 15:56:28 -07:00
1f6035070f mime.c: use LUASOCKET_API 2019-02-25 15:56:17 -07:00
c23bf865ce unix.h: use LUASOCKET_API 2019-02-25 15:55:36 -07:00
efc4bb3e2d mime.h: use LUASOCKET_API 2019-02-25 15:55:04 -07:00
f06b17c4c9 luasocket.h: define LUASOCKET_API and LUASOCKET_PRIVATE for export visibility 2019-02-25 15:54:09 -07:00
9b3f7a4304 Merge pull request #268 from ewestbrook/prc-multischeme
Scheme-independent connection and redirection
2019-02-24 21:29:19 -03:00
2a467001f6 http.lua: Error informatively if insufficient LuaSec support 2019-02-24 16:24:42 -07:00
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
38865fad3a Merge pull request #224 from pdgendt/patch-2
mime.lua: Obsolete require("io")
2019-02-24 18:06:00 -03:00
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
a9c75cb099 Merge pull request #244 from leyyer/options
add options:
2019-02-24 17:57:23 -03:00
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
f6ba23d463 Merge pull request #259 from davidgumberg/patch-1
Make macosx.cmd generic
2019-02-24 17:54:11 -03:00
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
c5cef32897 Merge pull request #262 from fregie/master
compile unixdgram.c, unixstream.c into unix.so
2019-02-24 17:45:58 -03:00
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
40f79c1961 Merge pull request #266 from siffiejoe/luajit-static-linking
Fix static linking problem with LuaJIT
2019-02-24 17:42:27 -03:00
e136dd3df3 Merge pull request #267 from ewestbrook/prc-maxredirects
Allow overriding of hard-coded redirect limit
2019-02-24 17:41:10 -03:00
09ff9b650c http.lua: allow override of hard-coded 5 max redirects 2019-02-23 12:23:17 -07:00
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
5858c8e776 src/makefile: support both lua/$(LUAV) and lua$(LUAV) include paths 2019-02-22 16:16:03 -07:00
686f2ce822 http.lua: if default for scheme, omit port number in "Host:" header 2019-02-20 02:42:40 -07:00
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
024646de54 Use SUN_LEN macro 2019-02-19 10:05:10 -07:00
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
531012df1a src/unixdgram.c: allow connect() and bind() on freebsd without dummy char, and simplify calculations 2019-02-19 04:51:23 -07:00
d1e35c9573 src/makefile: define UNIX_HAS_SUN_LEN for FreeBSD builds 2019-02-19 04:02:37 -07:00
4950294c26 compile unixdgram.c, unixstream.c into unix.so 2019-01-11 16:04:34 +08:00
e2bb1d3b42 Make macosx.cmd generic 2018-09-29 16:29:58 -07:00
288219fd6b Update to Visual Studio 2017. 2018-08-22 17:37:32 -03:00
648d81281f Merge pull request #256 from ewestbrook/luasocket254
url.lua:absolute_path(): fix issue #254
2018-08-22 14:18:43 -03:00
043e997713 url.lua:remove_dot_components(): avoid ambiguous numeric representation as empty-path-segment marker 2018-08-21 12:43:30 -06:00
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
38d936ec0e url.lua:remove_dot_components(): empty path component double-dot corner case 2018-08-21 11:27:42 -06:00
5b862e6a3c url.lua:absolute_path(): ensure a separator between base_path and relative_path 2018-08-21 10:43:04 -06:00
7ccea58776 url.lua:remove_dot_components(): avoid overconsuming dot segments 2018-08-21 09:59:45 -06:00
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
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
17a95c126a url.lua:absolute_path(): fix issue #254, simplify, add more test cases 2018-08-19 11:32:42 -06:00
5813cd0505 Merge pull request #253 from flyingdutchman23/master
Fix gcc-8.1.0 warning.
2018-08-06 13:15:58 -03:00
9b82c7871d Fix gcc-8.1.0 warning. 2018-08-06 15:30:13 +02:00
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
cc42bcbf80 Merge pull request #251 from ewestbrook/ltn12tblsrc
Add ltn12.source.table()
2018-06-05 09:56:59 -03:00
8fee636309 Add ltn12.source.table() 2018-06-05 00:00:39 -06:00
5848de4851 src/compat.c: provide luaL_testudata() for use by auxiliar.c under Lua 5.1 2018-06-04 20:14:13 -06:00
e1e41be948 Update auxiliar.c 2018-06-03 20:08:02 +08:00
4a3504612c Fixed an issue that was mistaken for HTTP 0.9 when timeout 2018-04-26 16:39:33 +08:00
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
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
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
88b13a825b Merge pull request #238 from hleuwer/master
Fix URL parsing of userinfo containing # character.
2017-11-23 13:28:25 -02:00
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
3ee89515a0 fixed URL parsing in url.lua: parse fragment after parsing username and password. 2017-11-19 19:48:37 +01:00
053c032a70 mime.lua: Obsolete require("io")
The `io` package is included but never used.
2017-09-04 10:26:11 +02:00
5a17f79b03 Merge pull request #213 from elliptica/master
Fix typo
2017-05-15 15:29:49 -03:00
aef7bcf288 Fix typo 2017-04-17 18:47:48 +03:00
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
47e644031f Preserve path when parsing urls. 2017-03-20 16:56:15 -03:00
1b4debffee Fix issue #196 2017-03-20 15:50:47 -03:00
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
44fb9e9112 correct typo 2017-03-16 17:53:02 +01:00
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
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
29e5ad610a Merge pull request #207 from cbane/unix-sockets
Add backwards compatibility wrappers for socket.unix
2017-01-25 23:25:55 -02:00
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
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
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
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
3a33c37b9c rename unix.tcp to unix.stream, unix.udp to unix.dgram 2016-12-25 23:33:10 +08:00
ac3201d620 Merge pull request #192 from mmaxs/master
Allow DESTDIR to be set from the environment
2016-11-11 02:28:07 -05:00
cd1e52eb7a allow DESTDIR to be set from the environment 2016-11-08 22:07:20 +03:00
316a9455b9 Merge pull request #181 from enginix/master
Add support for datagram unix domain sockets
2016-07-22 14:06:30 -03:00
2205c2053c add getsockname api for unix {udp,tcp} socket 2016-07-22 22:52:13 +08:00
c87f953d81 fix unixudp object checking issue 2016-07-04 16:38:37 +08:00
9f77f8b24f unix socket: compat lua 5.1 2016-06-30 15:40:51 +08:00
aa1b8cc9bc support datagram unix domain sockets 2016-06-24 21:33:19 +08:00
30a64c585a Merge pull request #178 from pdxmeshnet/master
Add rockspec to current development version.
2016-06-17 11:17:26 -03:00
3abd1f2dd0 Added future release rockspec file 2016-06-15 15:27:07 -07:00
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
e2acf378ea Merge pull request #171 from JonasKunze/feature/overwriteFlags
Enabled overwriting of MYCF/MYLDFlAGS
2016-04-12 09:29:14 -03:00
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
624924a77b Enabled overwriting of MYCF/MYLDFlAGS 2016-04-12 13:06:47 +02:00
b9f6fd215a URL-decode user password before adding to authorization header. 2016-04-12 00:04:21 +01:00
9984741d94 Update comments for url.unescape() function. 2016-04-12 00:01:51 +01:00
6fa6462636 Given LuaRocks support Haiku as a valid platform, link the network library 2016-03-11 16:05:21 -03:00
23ce5aeaa2 Hide ftp.PORT "constant" as a local 2016-03-07 01:33:08 -03:00
916b548240 Family agostic FTP and expose HTTP/FTP url parsing 2016-03-07 01:30:30 -03:00
5b4b915879 Remove global PORT. Fix https redirect. 2016-03-04 16:16:41 -03:00
944305dc21 Added gettimeout for completeness.
Also documented.
Rordered manuals so order is alphabetical.
2016-03-04 15:36:32 -03:00
cdce73b226 Added support for FTP command lists 2016-03-04 14:38:56 -03:00
fe7b37aced Merge pull request #166 from siffiejoe/exception-tweaks
Exception tweaks
2016-02-24 13:23:20 -03:00
0341516a29 Clarify documentation for try/protect. 2016-02-24 06:59:37 +01:00
4392bdcdd4 Always put metatable in first upvalue. 2016-02-24 00:57:42 +01:00
9fe38c654f Don't swallow errors in finalizers. 2016-02-24 00:48:43 +01:00
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
7cab8a5006 Update comment in except.h 2016-02-21 12:28:13 +01:00
7c1df8a7cd Update HTML docs for try/protect 2016-02-21 12:10:25 +01:00
fb713cdedb Add more tests for socket.try/protect 2016-02-21 12:09:58 +01:00
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
bf13ec7fd4 Merge pull request #155 from JonasKunze/feature/solaris
Added Solaris platform
2016-02-11 11:02:58 -02:00
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
9192881346 Don't break global mbox table in mbox.split_mbox 2016-02-11 15:57:56 +03:00
52bb99af35 Fix sink method in tp module 2016-02-11 15:56:57 +03:00
700ece0721 Fix base_parsed global in url module 2016-02-11 15:54:59 +03:00
3c3a5d0011 Use base.select instead of just select 2016-02-11 15:53:53 +03:00
a7f21e8ec4 Fix error in ltn12 under Lua 5.3 2016-02-11 15:51:54 +03:00
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
83880dbed7 When zero-timeout, only try first address in connect. 2015-12-03 12:56:18 -02:00
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
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
d1ec29be7f Merge branch 'KateAdams-tcp_reuseport' 2015-10-05 10:28:54 +08:00
f4b4720073 Merge branch 'tcp_reuseport' of https://github.com/KateAdams/luasocket into KateAdams-tcp_reuseport 2015-10-05 10:28:29 +08:00
4110e4125d Merge branch 'agnostic'
Seems safe to move to master.
2015-08-25 15:43:48 -03:00
77bba625d7 Fixes suggested by @Florob in #147. 2015-08-25 15:41:40 -03:00
46d7e75f3e Merge pull request #96 from chastabor/master
Generate headers before proxy changes host and port
2015-08-24 16:41:24 -03:00
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
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
b211838648 Fix rockspec and serial.c module. 2015-08-21 22:31:29 -03:00
9322eacefd Merge pull request #141 from cjtallman/master
Added missing options for UDP getoption.
2015-08-21 15:51:52 -03:00
e75444ccd1 New compat.h module implements luaL_setfuncs.
Makes initialization code simpler everywhere.
2015-08-21 15:39:34 -03:00
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
321c0c9b1f Merge branch 'Tieske-errormsg' 2015-03-03 19:20:44 -03:00
863a54cbaf Fix cut-paste typo on PIE_HOST_NOT_FOUND. 2015-03-03 19:20:13 -03:00
892ea1791a Merge branch 'errormsg' of https://github.com/Tieske/luasocket into Tieske-errormsg 2015-03-03 19:17:53 -03:00
8066a90e87 Merge pull request #115 from tst2005/patch-1
white background
2015-03-03 19:11:15 -03:00
bbcbbf845e Merge pull request #119 from gatzka/master
Make casts const correct.
2015-03-03 19:01:00 -03:00
d3ed08616b updated error messages, less error prone, platform independent 2015-03-03 21:17:06 +01:00
8396a0291b Better solution to luaL_checkint... 2015-03-01 22:49:04 -03:00
9d49cdcf05 Merge pull request #128 from Tieske/accidental_global
fixed accidental global in `ftp.lua`
2015-03-01 22:01:15 -03:00
59869b8bf6 fixed accidental global in ftp.lua 2015-03-01 20:34:53 +01:00
76ed24fe8a Fix inet_global_getaddrinfo leak of getnameinfo
Issue #127 closed.
2015-02-18 20:54:27 -02:00
ddf4292824 Out of the box support for Lua 5.3. 2015-02-18 20:51:37 -02:00
d8f77cca64 Remove unused function luaL_typerror(). 2014-12-21 07:45:36 +01:00
9178451ef9 Add missing prototype for opt_get_reuseport(). 2014-12-21 07:45:17 +01:00
c6f136c7f5 Make local function udp_strerror() static. 2014-12-21 07:44:11 +01:00
41692dfb4b Make casts const correct. 2014-12-21 06:57:10 +01:00
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
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
0b03eec16b make socket.protect yieldable on Lua 5.2/5.3 2014-11-10 18:49:40 +01:00
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
7006ae120d fixed yieldable socket.protect in etc/dispatch.lua 2014-11-10 18:17:10 +01:00
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
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
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
d80bb0d82b Fix Host: header according to RFC7230 2014-07-15 14:49:20 -03:00
2314235b3a Add proxy authentication headers if present. 2014-03-27 14:40:04 -05:00
36aa87e031 Generate headers before proxy changes host and port 2014-03-21 14:25:44 -05:00
534dfed859 the universe has only existed for 43.8 years 2013-11-07 19:13:36 -05:00
833333e131 Added ability to set the option reuseport of a tcp socket. 2013-09-12 00:46:32 +01:00
6d5e40c324 Add MYCFLAGS and MYLDFLAGS go allow for customization 2013-09-09 14:55:20 -03:00
d0b1f5b4c1 Add support for FreeBSD in makefile
Thanks to Leryan. See issue #78.
2013-09-09 14:29:14 -03:00
396e9e5ee6 Fixed timeout bug introduced by commit e81a6ff 2013-09-09 14:23:00 -03:00
244e5d34a0 Merge pull request #74 from catwell/pull-hostport
Include port in default Host header
2013-09-09 09:54:08 -07:00
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
87d72dce4e include port in default Host header
See RFC 2616 section 14.23.
2013-08-14 14:41:57 +02:00
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
1f9ccb2b58 http: look for PROXY in _M, not as a global 2013-07-05 18:00:29 +02:00
ddf88aca09 http: do not set global TIMEOUT 2013-07-05 17:59:52 +02:00
480a818bf0 support multiple filters in ltn12.{sink,source}.chain() 2013-06-18 11:01:46 +02:00
22cd5833fc Change link to github page. 2013-06-14 19:27:32 +08:00
19bd8baf9b Add files to distribution. 2013-06-14 19:21:27 +08:00
de58cb417a Change 2.1 to 3.0 2013-06-14 19:16:16 +08:00
bf7bc59a4d Change 2.1 to 3.0-rc1 2013-06-14 19:15:37 +08:00
ea812a755e Update NEW file and section 2013-06-14 19:12:44 +08:00
2cc51443c2 Download archive with https rather than git scheme 2013-06-13 17:35:52 +08:00
85aa5e3d9c Fix version in rockspec. 2013-06-13 17:13:14 +08:00
9ddfe92820 Fix path for rockspec in travis file. 2013-06-13 16:40:14 +08:00
c07ad19ca1 Merging moteus suggestions for rockspec and travis 2013-06-13 16:19:03 +08:00
7cad902bb7 Fix makefile and test_socket_error.lua 2013-06-12 21:45:15 +08:00
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
cce138c8e5 new rockspec using builtin build type 2013-06-11 17:23:50 -03:00
6e00ffd62f Changing from 2.1-rc1 to 3.0-rc1. 2013-06-11 19:10:03 +08:00
906abf29d1 Fix unix export marker. 2013-06-11 17:20:27 +08:00
bc709ac7b7 Export global table only if "module()" is defined. 2013-06-05 18:36:51 +08:00
b1d1e721d1 No need for inet_pton. 2013-06-04 16:26:49 +08:00
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
ebde49944b Unix domain tests still broken. 2013-05-30 17:59:28 +08:00
5eefc73b57 Remove warnings. Move windows specific code. 2013-05-30 16:50:28 +08:00
a233e27865 Leaving if in src/ but out of build for now. 2013-05-30 16:20:34 +08:00
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
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
1de617e355 Add. Allow get error option to socket. 2013-05-29 14:33:27 +04:00
b84a5f3d08 Change VC12 project to no LUA_COMPAT_MODUULE 2013-05-29 17:19:24 +08:00
79e6c4915d Export global only if LUA_COMPAT_MODULE defined. 2013-05-29 16:56:56 +08:00
5167ddaf49 Merge branch 'unstable' of git://github.com/diegonehab/luasocket into moteus-lua52 2013-05-28 14:06:18 +04:00
2d51d61688 Fix "final" bug in pton and TCP connreset handling 2013-05-28 17:27:06 +08:00
27fd725c6d Typo fixed. 2013-05-28 01:54:49 +08:00
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
66cd8cfcee Fix wrong usage of inet_pton. 2013-05-27 22:17:51 +08:00
056d7653f3 Link only against ws2_32.lib. 2013-05-27 21:58:41 +08:00
3d61b0fe36 Merge branch 'pkulchenko' into unstable 2013-05-27 21:17:00 +08:00
834a3cf520 Simplifying getaddrinfo treatment. 2013-05-27 21:05:48 +08:00
5e0b56b8d3 Merge branch 'moteus' of https://github.com/moteus/luasocket into moteus 2013-05-27 20:32:54 +08:00
26704061a4 Fix Visual Studio 2012 projects 2013-05-27 20:30:06 +08:00
45ff0e1775 Fix. use table.unpack in mimetest on Lua 5.2. 2013-05-27 13:11:07 +04:00
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
bd51d8c1a5 Fix. Optional IPv6 test 2013-05-27 11:26:35 +04:00
e54f78c61c Fix. setsockname fails with "*" as host.
Add. test_bind.lua
2013-05-27 11:25:31 +04:00
56dbda39ed Fix. getaddrinfo returns garbage as address on Windows.
Add. test_getaddrinfo.lua
2013-05-27 11:20:52 +04:00
fbe184f28a No need for build script: makefile target instead. 2013-05-26 21:27:18 +08:00
427220c7b1 Merge tryconnect6 into inet_tryconnect. 2013-05-26 21:26:26 +08:00
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
22107bb9fc Check linux build. 2013-05-25 07:25:02 -03:00
5d3a78b4a6 Added my test command lines. 2013-05-25 18:10:46 +08:00
bb0b31301a Add MingW support. 2013-05-25 18:07:38 +08:00
afe0494318 Change Mac OS Lua directory 2013-05-25 15:26:12 +08:00
cbc77440c8 Merge branch 'lua52-mingw' of https://github.com/pkulchenko/luasocket into pkulchenko 2013-05-24 18:33:43 +08:00
ca48baf495 Merge pull request #37 from davidm/unstable
lpr.lua: fix invalid string escape sequence \?
2013-04-17 20:55:19 -07:00
817d47df42 lpr.lua: fix invalid string escape sequence \?
Not valid in 5.2 and luajit.
2013-04-17 23:35:56 -04:00
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
c28fa1d309 Merge pull request #27 from catwell/pull-noarg
fix more uses of arg
2013-04-17 19:38:21 -07:00
00435529bb Merge pull request #32 from ideka/unstable
Use the length operator (#) instead of table.getn.
2013-04-17 19:13:28 -07:00
571308a94e Updated IPV6_V6ONLY to match header files on Windows. 2013-04-09 09:25:40 -07:00
5a58786a39 Added inet_pton/inet_ntop for MinGW on Windows; compiles with Lua52. 2013-04-07 12:39:56 -07:00
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
94c9588719 rockspec for luasocket 2.1 unstable 2013-01-24 15:28:17 -02:00
33b4f0cfc7 remove uses of arg in the codebase 2013-01-23 19:13:32 +01:00
eea1bc04d7 fix use of arg in ltn documentation 2013-01-23 19:03:46 +01:00
d548a78e55 Cookie modifications. 2013-01-10 01:10:34 -02:00
72a5347f97 Remove warnings and fix makefile for Win32. 2012-12-11 17:43:49 -02:00
618ce43ee3 Fix socket_accept usage to depend on family. 2012-12-11 16:35:27 -02:00
66670c3541 Move Visual Studio projects to 2012. 2012-12-10 18:45:05 -02:00
9d97d39575 Fix ltn12 version. 2012-12-10 15:50:44 -02:00
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
114080d835 Merge pull request #24 from catwell/tracking-diego
fix use of arg in ltn12
2012-12-10 09:25:21 -08:00
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
ffddaf4a2e fix use of arg in ltn12 2012-09-17 23:44:04 +02:00
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
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
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
03ba06f70c Add new bug fix comment. 2012-08-01 03:34:06 -03:00
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
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
6370b61414 Merge pull request #20 from Florob/sendto
IPv6 support for udp:sendto() and udp:receivefrom()
2012-07-31 22:04:06 -07:00
5616f3a0ae Merge pull request #15 from darkrain42/unstable
tcp: Initialize clnt->family in :accept()
2012-07-31 22:02:10 -07:00
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
7503bb0ca3 Add IPv6 support to udp:receivefrom() 2012-07-18 21:05:30 +02:00
a6cf48596d Add IPv6 support to udp:sendto() 2012-07-17 19:02:20 +02:00
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
36461db5bb src/makefile: Use install instead of cp and mkdir. 2012-05-15 18:44:38 +02:00
c624761d32 src/makefile: Move mkdir to a variable 2012-05-15 18:27:46 +02:00
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
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
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
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
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
ee7c53c3e5 Merge pull request #6 from Florob/getnameinfo
Add a getnameinfo() wrapper
2012-05-08 11:48:54 -07:00
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
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
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
04be61f88d Test server exits gracefully at command of test client 2012-05-01 16:21:06 +08:00
af55d25675 Merge branch 'tests52' of https://github.com/Florob/luasocket into Florob-tests52 2012-05-01 16:12:16 +08:00
6de0aa54fd Update method list in tests 2012-04-29 21:03:28 +02:00
cf4d29f86d Select loadstring or load for Lua 5.1/5.2 respectively 2012-04-29 20:46:35 +02:00
46736a3355 Test method registration for IPv6 sockets 2012-04-29 20:44:15 +02:00
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
30d1aae140 Added Sam's suggestion to TODO 2012-04-27 02:03:09 +08:00
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
1acf8188cd socket.bind also tries all addresses returned by getaddrinfo. 2012-04-23 01:40:31 +08:00
966642f76a socket.connect() loops over addresses returned by getaddrinfo 2012-04-23 01:29:41 +08:00
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
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
b3c4f46179 merged lua_typerrror.{c,h} into auxiliar.{c,h} 2012-04-16 20:41:48 +08:00
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
195b2a74bb On failure, exit with a message instead of blocking indefinitely. 2012-04-11 13:54:01 -07:00
38b99b80a2 Add Wurldtech note to README. 2012-04-11 13:54:01 -07:00
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
8bb542baaf Support getoption method for tcp objects. 2012-04-11 13:54:01 -07:00
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
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
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
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
12bde801f6 Document dirty, getfd, and setfd for select and tcp. 2012-04-11 13:45:59 -07:00
3a0fd4744d Reference index was missing documented APIs, and only partially alphabetized. 2012-04-11 13:45:59 -07:00
b1f7c349b5 Add support for serial devices as socket streams on unix. 2012-04-11 13:45:59 -07:00
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
dace50628c Utility to find how many TCP connections can be made. 2012-04-11 13:45:59 -07:00
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
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
c37f71d062 Test showing failure to receive a zero-length packet. 2012-04-11 13:45:59 -07:00
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
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
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
826589afcd Add location of Ubuntu's lua5.1 headers to config. 2012-04-11 13:45:59 -07:00
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
e3e0dee639 ignore build output 2012-04-11 13:45:58 -07:00
f399ab25fc inet: Honor the strict aliasing rule 2012-04-11 13:33:35 -07:00
e81a6ff623 Conditional creation of p_timeout instance 'tm' 2012-04-11 13:33:34 -07:00
9a58252528 change localhost to loopback ip to prevent error on my mac box???? 2012-04-11 13:33:34 -07:00
51187ecc90 Updated readme version and os tested 2012-04-11 13:33:34 -07:00
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
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
a984607f28 inet: return more useful errors 2012-04-11 13:33:34 -07:00
7893d9ece2 inet: refactor getpeername to allocate the struct on the stack 2012-04-11 13:33:34 -07:00
8393c76180 Fix getpeername to work with IPv6 addresses 2012-04-11 13:33:34 -07:00
594f826aa1 Add support for connecting to IPv6 hosts 2012-04-11 13:33:34 -07:00
5874d47f55 dns.getaddrinfo: Return proper error messages 2012-04-11 13:33:34 -07:00
f871a29f27 Add support for the IPV6_V6ONLY socket option defaulting to on. 2012-04-11 13:33:34 -07:00
4df1618aab Adapt socket.bind() to create a IPv4 or IPv6 depending on the address given 2012-04-11 13:33:34 -07:00
5065a2585c dns: Rename toip6() to getaddrinfo() since the old name is misleading 2012-04-11 13:33:34 -07:00
923eef1929 Rework binding IPv6 sockets by harmonizing it with the IPv4 variant 2012-04-11 13:33:34 -07:00
5c33ef9997 url.escape/url.unescape: Fix to return *only* the encoded/decoded string (thanks moodydeath) 2012-04-11 13:33:34 -07:00
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
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
2778766d67 Preliminary IPv6 support for v2.1 2012-04-11 13:25:11 -07:00
3a8ba90dfb Saving before big changes to support IPv6. 2011-05-25 20:57:22 +00:00
bce60be30f Decent makefiles! 2009-05-27 09:31:38 +00:00
d1a72435d5 New release. 2007-10-13 23:55:20 +00:00
162 changed files with 10292 additions and 5274 deletions

23
.editorconfig Normal file
View File

@ -0,0 +1,23 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
[{*.lua,*.rockspec,.luacheckrc}]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 4
[*.html]
indent_style = space
indent_size = 4
[*.{c,h}]
indent_style = space
indent_size = 4

45
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: Build
on:
push:
branches:
- master
pull_request:
jobs:
build:
name: Test build on ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
luaVersion: [ "5.4", "5.3", "5.2", "5.1", "luajit", "luajit-openresty" ]
platform: [ "ubuntu-20.04", "macos-11" ] # "windows-2022" not supported by gh-actions-lua
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup lua
uses: leafo/gh-actions-lua@v9
with:
luaVersion: ${{ matrix.luaVersion }}
- name: Setup luarocks
uses: leafo/gh-actions-luarocks@v4
- name: Make and install
run: |
export DEBUG=DEBUG
luarocks make -- luasocket-scm-3.rockspec
- name: Run regression tests
run: |
cd test
lua hello.lua
lua testsrvr.lua > /dev/null &
lua testclnt.lua
lua stufftest.lua
lua excepttest.lua
lua test_bind.lua
lua test_getaddrinfo.lua
lua ltn12test.lua
lua mimetest.lua
lua urltest.lua
lua test_socket_error.lua
kill %1

34
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Deploy
on: [ push, workflow_dispatch ]
jobs:
affected:
uses: lunarmodules/.github/.github/workflows/list_affected_rockspecs.yml@main
build:
needs: affected
if: ${{ needs.affected.outputs.rockspecs }}
uses: lunarmodules/.github/.github/workflows/test_build_rock.yml@main
with:
rockspecs: ${{ needs.affected.outputs.rockspecs }}
upload:
needs: [ affected, build ]
# Only run upload if:
# 1. We are on the canonical repository (no uploads from forks)
# 2. The current commit is either tagged or on the default branch (the workflow will upload dev/scm rockspecs any
# time they are touched, tagged ones whenever the edited rockspec and tag match)
# 3. Some rockspecs were changed — this implies the commit changing the rockspec is the same one that gets tagged
if: >-
${{
github.repository == 'lunarmodules/luasocket' &&
( github.ref_name == 'master' || startsWith(github.ref, 'refs/tags/') ) &&
needs.affected.outputs.rockspecs
}}
uses: lunarmodules/.github/.github/workflows/upload_to_luarocks.yml@main
with:
rockspecs: ${{ needs.affected.outputs.rockspecs }}
secrets:
apikey: ${{ secrets.LUAROCKS_APIKEY }}

13
.github/workflows/luacheck.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Luacheck
on: [push, pull_request]
jobs:
luacheck:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Luacheck
uses: lunarmodules/luacheck@v0

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

31
.luacheckrc Normal file
View File

@ -0,0 +1,31 @@
unused_args = false
redefined = false
max_line_length = false
not_globals = {
"string.len",
"table.getn",
}
include_files = {
"**/*.lua",
"**/*.rockspec",
".busted",
".luacheckrc",
}
exclude_files = {
"etc/*.lua",
"etc/**/*.lua",
"test/*.lua",
"test/**/*.lua",
"samples/*.lua",
"samples/**/*.lua",
"gem/*.lua",
"gem/**/*.lua",
-- GH Actions Lua Environment
".lua",
".luarocks",
".install",
}

65
CHANGELOG.md Normal file
View File

@ -0,0 +1,65 @@
# Changelog
## [v3.1.0](https://github.com/lunarmodules/luasocket/releases/v3.1.0) — 2022-07-27
* Add support for TCP Defer Accept @Zash
* Add support for TCP Fast Open @Zash
* Fix Windows (mingw32) builds @goldenstein64
* Avoid build warnings on 64-bit Windows @rpatters1
## [v3.0.0](https://github.com/lunarmodules/luasocket/releases/v3.0.0) — 2022-03-25
The last time LuaSocket had a stable release tag was 14 years ago when 2.0.2 was tagged.
A v3 release candidate was tagged 9 years ago.
Since then it has been downloaded over 3 million times.
Additionally the Git repository regularly gets several hundred clones a day.
But 9 years is a long time and even the release candidate has grown a bit long in the tooth.
Many Linux distros have packaged the current Git HEAD or some specific tested point as dated or otherwise labeled releases.
256 commits later and having been migrated to the @lunarmodules org namespace on GitHub, please welcome v3.
This release is a "safe-harbor" tag that represents a minimal amount of changes to get a release tagged.
Beyond some CI tooling, very little code has changed since migration to @lunarmodules ([5b18e47..e47d98f](https://github.com/lunarmodules/luasocket/compare/5b18e47..e47d98f?w=1)):
* Lua 5.4.3+ support @pkulchenko, @Zash
* Cleanup minor issues to get a code linter to pass @Tieske, @jyoui, @alerque
* Update Visual Studio build rules for Lua 5.1 @ewestbrook
* Set http transfer-encoding even without content-length @tokenrove
Prior to migration to @lunarmodules ([v3.0-rc1..5b18e47](https://github.com/lunarmodules/luasocket/compare/v3.0-rc1..5b18e47?w=1)) many things happened of which the author of this changelog is not fully apprised.
Your best bet if it affects your project somehow is to read the commit log & diffs yourself.
## [v3.0-rc1](https://github.com/lunarmodules/luasocket/releases/v3.0-rc1) — 2013-06-14
Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
* Added: Compatible with Lua 5.2
- Note that unless you define LUA_COMPAT_MODULE, package tables will not be exported as globals!
* Added: IPv6 support;
- Socket.connect and socket.bind support IPv6 addresses;
- Getpeername and getsockname support IPv6 addresses, and 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).
## [v2.0.2](https://github.com/lunarmodules/luasocket/releases/v2.0.2) — 2007-09-11

13
FIX
View File

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

View File

@ -1,5 +1,4 @@
LuaSocket 2.0.2 license
Copyright <20> 2004-2007 Diego Nehab
Copyright (C) 2004-2022 Diego Nehab
Permission is hereby granted, free of charge, to any person obtaining a
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>

11
NEW
View File

@ -1,11 +0,0 @@
What's New
This is just a bug-fix/update release.
* Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
* Fixed: return values are consistent when reading from closed sockets;
* Fixed: case sensitivity in headers of multipart messages in
smtp.message() (Graham Henstridge);
* Fixed a couple instances of error() being called instead of base.error(). These would cause an error when an error was reported. :) (Ketmar Dark);
* Fixed: test script now uses pairs() iterator instead of the old
Lua syntax (Robert Dodier).

6
README
View File

@ -1,6 +0,0 @@
This is the LuaSocket 2.0.1. It has been tested on WinXP, Mac OS X,
and Linux. Please use the Lua mailing list to report any bugs
(or "features") you encounter.
Have fun,
Diego Nehab.

12
README.md Normal file
View File

@ -0,0 +1,12 @@
# LuaSocket
[![Build](https://img.shields.io/github/workflow/status/lunarmodules/luasocket/Build?label=Build=Lua)](https://github.com/lunarmodules/luasocket/actions?workflow=Build)
[![Luacheck](https://img.shields.io/github/workflow/status/lunarmodules/luasocket/Luacheck?label=Luacheck&logo=Lua)](https://github.com/lunarmodules/luasocket/actions?workflow=Luacheck)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/lunarmodules/luasocket?label=Tag&logo=GitHub)](https://github.com/lunarmodules/luasocket/releases)
[![Luarocks](https://img.shields.io/luarocks/v/lunarmodules/luasocket?label=Luarocks&logo=Lua)](https://luarocks.org/modules/lunarmodules/luasocket)
LuaSocket is a Lua extension library composed of two parts:
1. a set of C modules that provide support for the TCP and UDP transport layers, and
2. a set of Lua modules that provide functions commonly needed by applications that deal with the Internet.

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
ftp send should return server replies?
make sure there are no object files in the distribution tarball
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

@ -1,132 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: DNS support">
<meta name="keywords" content="Lua, LuaSocket, DNS, Network, Library, Support">
<title>LuaSocket: DNS support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=dns>DNS</h2>
<p>
Name resolution functions return <em>all</em> information obtained from the
resolver in a table of the form:
</p>
<blockquote><tt>
resolved = {<br>
&nbsp;&nbsp;name = <i>canonic-name</i>,<br>
&nbsp;&nbsp;alias = <i>alias-list</i>,<br>
&nbsp;&nbsp;ip = <i>ip-address-list</i><br>
}
</tt> </blockquote>
<p>
Note that the <tt>alias</tt> list can be empty.
</p>
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gethostname>
socket.dns.<b>gethostname()</b>
</p>
<p class=description>
Returns the standard host name for the machine as a string.
</p>
<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=tohostname>
socket.dns.<b>tohostname(</b>address<b>)</b>
</p>
<p class=description>
Converts from IP address to host name.
</p>
<p class=parameters>
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
The function returns a string with the canonic host name of the given
<tt>address</tt>, followed by 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>
<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=toip>
socket.dns.<b>toip(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to IP address.
</p>
<p class=parameters>
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
Returns a string with the first IP address found for <tt>address</tt>,
followed by 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>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:07 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View File

@ -1,205 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="The LuaSocket Homepage">
<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
<title>LuaSocket: Network support for the Lua language </title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=whatis>What is LuaSocket?</h2>
<p>
LuaSocket is a <a href="http://www.lua.org">Lua</a> 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.
</p>
<p>
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
properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and Unix platforms. </p>
<p>
Among the support modules, the most commonly used implement the
<a href=smtp.html>SMTP</a>
(sending e-mails),
<a href=http.html>HTTP</a>
(WWW access) and
<a href=ftp.html>FTP</a>
(uploading and downloading files) client
protocols. These provide a very natural and generic interface to the
functionality defined by each protocol.
In addition, you will find that the
<a href=mime.html>MIME</a> (common encodings),
<a href=url.html>URL</a>
(anything you could possible want to do with one) and
<a href=ltn12.html>LTN12</a>
(filters, sinks, sources and pumps) modules can be very handy.
</p>
<p>
The library is available under the same
<a href="http://www.lua.org/copyright.html">
terms and conditions</a> as the Lua language, the MIT license. The idea is
that if you can use Lua in a project, you should also be able to use
LuaSocket.
</p>
<p>
Copyright &copy; 2004-2007 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
</p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=download>Download</h2>
<p>
LuaSocket version 2.0.2 is now available for download! It is
compatible with Lua&nbsp;5.1, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
are it works well on most UNIX distributions and Windows flavors.
</p>
<p>
The library can be downloaded in source code from the
<a href=http://luaforge.net/projects/luasocket/>LuaSocket
project page</a> at LuaForge.
Besides the full C and Lua source code for the library, the distribution
contains several examples, 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> Take a look at the <a
href=installation.html>installation</a> section of the
manual to find out how to properly install the library.
</p>
<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=thanks>Special thanks</h2>
<p>
Throughout LuaSocket's history, many people gave suggestions that helped
improve it. For that, I thank the Lua community.
Special thanks go to
David Burgess, who has helped push the library to a new level of quality and
from whom I have learned a lot of stuff that doesn't show up in RFCs.
Special thanks also to Carlos Cassino, who played a big part in the
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall
has been helping a lot too! Thanks to you all!
</p>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=new>What's New</h2>
<p>
2.0.2 is just a bug-fix/update release.
</p>
<ul>
<li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
<li> Fixed: return values are consistent when reading from closed sockets;
<li> Fixed: case sensitivity in headers of multipart
messages in smtp.message() (Graham Henstridge);
<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>
<p>
2.0.1 is just a bug-fix/update release.
</p>
<ul>
<li> Updated: now using <tt>compat-5.1r5</tt>;
<li> Improved: <tt>http.request</tt> is more robust to
malformed URLs (Adrian Sietsma);
<li> Improved: the simple <tt>http.request</tt> interface sends a
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
header (William Trenker);
<li> Improved: <tt>http.request</tt> is robust to evil
servers that send inappropriate 100-continue messages
(David Burgess);
<li> Fixed: <tt>http.request</tt> was using the old host header during
redirects (Florian Berger);
<li> Fixed: sample <tt>unix.c</tt> had fallen through the
cracks during development (Matthew Percival);
<li> Fixed: error code was not being propagated correctly in
ftp.lua (David Burgess).
</ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=old>Old Versions</h2>
<p>
All previous versions of the LuaSocket library can be downloaded <a
href="http://www.cs.princeton.edu/~diego/professional/luasocket/old">
here</a>. Although these versions are no longer supported, they are
still available for those that have compatibility issues.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="home.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:23 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View File

@ -1,405 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The core namespace">
<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support">
<title>LuaSocket: The socket namespace</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=socket>The socket namespace</h2>
<p>
The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
</p>
<p>
To obtain the <tt>socket</tt> namespace, run:
</p>
<pre class=example>
-- loads the socket module
local socket = require("socket")
</pre>
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind>
socket.<b>bind(</b>address, port [, backlog]<b>)</b>
</p>
<p class=description>
This function is a shortcut that creates and returns a TCP server object
bound to a local <tt>address</tt> and <tt>port</tt>, ready to
accept client connections. Optionally,
user can also specify the <tt>backlog</tt> argument to the
<a href=tcp.html#listen><tt>listen</tt></a> method (defaults to 32).
</p>
<p class=note>
Note: The server object returned will have the option "<tt>reuseaddr</tt>"
set to <tt><b>true</b></tt>.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect>
socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b>
</p>
<p class=description>
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,
the user can also specify the local address and port to bind
(<tt>locaddr</tt> and <tt>locport</tt>).
</p>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
socket.<b>_DEBUG</b>
</p>
<p class=description>
This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support.
</p>
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry>
socket.<b>newtry(</b>finalizer<b>)</b>
</p>
<p class=description>
Creates and returns a <em>clean</em>
<a href="#try"><tt>try</tt></a>
function that allows for cleanup before the exception
is raised.
</p>
<p class=parameters>
<tt>Finalizer</tt> is a function that will be called before
<tt>try</tt> throws the exception. It will be called
in <em>protected</em> mode.
</p>
<p class=return>
The function returns your customized <tt>try</tt> function.
</p>
<p class=note>
Note: This idea saved a <em>lot</em> of work with the
implementation of protocols in LuaSocket:
</p>
<pre class=example>
foo = socket.protect(function()
-- connect somewhere
local c = socket.try(socket.connect("somewhere", 42))
-- create a try function that closes 'c' on error
local try = socket.newtry(function() c:close() end)
-- do everything reassured c will be closed
try(c:send("hello there?\r\n"))
local answer = try(c:receive())
...
try(c:send("good bye\r\n"))
c:close()
end)
</pre>
<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=protect>
socket.<b>protect(</b>func<b>)</b>
</p>
<p class=description>
Converts a function that throws exceptions into a safe function. This
function only catches exceptions thrown by the <a href=#try><tt>try</tt></a>
and <a href=#newtry><tt>newtry</tt></a> functions. It does not catch normal
Lua errors.
</p>
<p class=parameters>
<tt>Func</tt> is a function that calls
<a href=#try><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>)
to throw exceptions.
</p>
<p class=return>
Returns an equivalent function that instead of throwing exceptions,
returns <tt><b>nil</b></tt> followed by an error message.
</p>
<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>
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=select>
socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b>
</p>
<p class=description>
Waits for a number of sockets to change status.
</p>
<p class=parameters>
<tt>Recvt</tt> is an array with the sockets to test for characters
available for reading. Sockets in the <tt>sendt</tt> array are watched to
see if it is OK to immediately write on them. <tt>Timeout</tt> is the
maximum amount of time (in seconds) to wait for a change in status. A
<tt><b>nil</b></tt>, negative or omitted <tt>timeout</tt> value allows the
function to block indefinitely. <tt>Recvt</tt> and <tt>sendt</tt> can also
be empty tables or <tt><b>nil</b></tt>. Non-socket values (or values with
non-numeric indices) in the arrays will be silently ignored.
</p>
<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.
The error message is "<tt>timeout</tt>" if a timeout condition was met and
<tt><b>nil</b></tt> otherwise. The returned tables are
doubly keyed both by integers and also by the sockets
themselves, to simplify the test if a specific socket has
changed status.
</p>
<p class=note>
<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
writable even though the socket is <em>not</em> ready for sending.
</p>
<p class=note>
<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee
<a href=tcp.html#accept><tt>accept</tt></a> will return immediately.
Use the <a href=tcp.html#settimeout><tt>settimeout</tt></a>
method or <tt>accept</tt> might block forever.
</p>
<p class=note>
<b>Yet another note</b>: If you close a socket and pass
it to <tt>select</tt>, it will be ignored.
</p>
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink>
socket.<b>sink(</b>mode, socket<b>)</b>
</p>
<p class=description>
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink from a stream socket object.
</p>
<p class=parameters>
<tt>Mode</tt> defines the behavior of the sink. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: sends data through socket after applying the
<em>chunked transfer coding</em>, closing the socket when done;
<li> <tt>"close-when-done"</tt>: sends all received data through the
socket, closing the socket when done;
<li> <tt>"keep-open"</tt>: sends all received data through the
socket, leaving it open when done.
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to send the data.
</p>
<p class=return>
The function returns a sink with the appropriate behavior.
</p>
<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=skip>
socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Drops a number of arguments and returns the remaining.
</p>
<p class=parameters>
<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to
<tt>ret<sub>N</sub></tt> are the arguments.
</p>
<p class=return>
The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
</p>
<p class=note>
Note: This function is useful to avoid creation of dummy variables:
</p>
<pre class=example>
-- get the status code and separator from SMTP server reply
local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
</pre>
<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sleep>
socket.<b>sleep(</b>time<b>)</b>
</p>
<p class=description>
Freezes the program execution during a given amount of time.
</p>
<p class=parameters>
<tt>Time</tt> is the number of seconds to sleep for.
The function truncates <tt>time</tt> down to the nearest integer.
</p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=source>
socket.<b>source(</b>mode, socket [, length]<b>)</b>
</p>
<p class=description>
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source from a stream socket object.
</p>
<p class=parameters>
<tt>Mode</tt> defines the behavior of the source. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: receives data from socket and removes the
<em>chunked transfer coding</em> before returning the data;
<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the
socket. This mode requires the extra argument <tt>length</tt>;
<li> <tt>"until-closed"</tt>: receives data from a socket until the other
side closes the connection.
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to receive the data.
</p>
<p class=return>
The function returns a source with the appropriate behavior.
</p>
<!-- time ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
socket.<b>gettime()</b>
</p>
<p class=description>
Returns the time in seconds, relative to the origin of the
universe. 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>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try>
socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Throws an exception in case of error. The exception can only be caught
by the <a href=#protect><tt>protect</tt></a> function. It does not explode
into an error message.
</p>
<p class=parameters>
<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary
arguments, but are usually the return values of a function call
nested with <tt>try</tt>.
</p>
<p class=return>
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>.
</p>
<pre class=example>
-- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect("localhost", 80))
</pre>
<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=version>
socket.<b>_VERSION</b>
</p>
<p class=description>
This constant has a string describing the current LuaSocket version.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:54 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View File

@ -1,532 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The TCP/IP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<title>LuaSocket: TCP/IP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=accept>
server:<b>accept()</b>
</p>
<p class=description>
Waits for a remote connection on the server
object and returns a client object representing that connection.
</p>
<p class=return>
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>
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.
</p>
<p class=note>
Note: calling <a href=socket.html#select><tt>socket.select</tt></a>
with a server object in
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
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up.
</p>
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind>
master:<b>bind(</b>address, port<b>)</b>
</p>
<p class=description>
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host.
<p class=parameters>
<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).
If <tt>address</tt>
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
chooses an ephemeral port.
</p>
<p class=return>
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<p class=note>
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.
</p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=close>
master:<b>close()</b><br>
client:<b>close()</b><br>
server:<b>close()</b>
</p>
<p class=description>
Closes a TCP object. The internal socket used by the object is closed
and the local address to which the object was
bound is made available to other applications. No further operations
(except for further calls to the <tt>close</tt> method) are allowed on
a closed socket.
</p>
<p class=note>
Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor,
which are limited system resources. Garbage-collected objects are
automatically closed before destruction, though.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect>
master:<b>connect(</b>address, port<b>)</b>
</p>
<p class=description>
Attempts to connect a master object to a remote host, transforming it into a
client object.
Client objects support methods
<a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>,
<a href=#getpeername><tt>getpeername</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a>.
</p>
<p class=parameters>
<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).
</p>
<p class=return>
In case of error, the method returns <b><tt>nil</tt></b> followed by a string
describing the error. In case of success, the method returns 1.
</p>
<p class=note>
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.
</p>
<p class=note>
Note: Starting with LuaSocket 2.0,
the <a href=#settimeout><tt>settimeout</tt></a>
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
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
established.
</p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getpeername>
client:<b>getpeername()</b>
</p>
<p class=description>
Returns information about the remote side of a connected client object.
</p>
<p class=return>
Returns a string with the IP address of the peer, followed by the
port number that peer is using for the connection.
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class=note>
Note: It makes no sense to call this method on server objects.
</p>
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getsockname>
master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br>
server:<b>getsockname()</b>
</p>
<p class=description>
Returns the local address information associated to the object.
</p>
<p class=return>
The method returns a string with local IP address and a number with
the port. In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getstats>
master:<b>getstats()</b><br>
client:<b>getstats()</b><br>
server:<b>getstats()</b><br>
</p>
<p class=description>
Returns accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class=return>
The method returns the number of bytes received, the number of bytes sent,
and the age of the socket object in seconds.
</p>
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=listen>
master:<b>listen(</b>backlog<b>)</b>
</p>
<p class=description>
Specifies the socket is willing to receive connections, transforming the
object into a server object. Server objects support the
<a href=#accept><tt>accept</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>,
<a href=#setoption><tt>setoption</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a> methods.
</p>
<p class=parameters>
The parameter <tt>backlog</tt> specifies the number of client
connections that can
be queued waiting for service. If the queue is full and another client
attempts connection, the connection is refused.
</p>
<p class=return>
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=receive>
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p>
<p class=description>
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.
</p>
<p class=parameters>
<tt>Pattern</tt> can be any of the following:
</p>
<ul>
<li> '<tt>*a</tt>': reads from the socket until the connection is
closed. No end-of-line translation is performed;
<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
CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. This is the default pattern;
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket.
</ul>
<p class=parameters>
<tt>Prefix</tt> is an optional string to be concatenated to the beginning
of any received data before return.
</p>
<p class=return>
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
can be the string '<tt>closed</tt>' in case the connection was
closed before the transmission was completed or the string
'<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 class=note>
<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
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
functions should return <tt><b>nil</b></tt> on error. Thus it was changed
too.
</p>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send>
client:<b>send(</b>data [, i [, j]]<b>)</b>
</p>
<p class=description>
Sends <tt>data</tt> through client object.
</p>
<p class=parameters>
<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>string.sub</tt> Lua function to allow the selection of a
substring to be sent.
</p>
<p class=return>
If successful, the method returns the index of the last byte
within <tt>[i, j]</tt> that has been sent. Notice that, if
<tt>i</tt> is 1 or absent, this is effectively the total
number of bytes sent. In case of error, the method returns
<b><tt>nil</tt></b>, followed by an error message, followed
by the index of the last byte within <tt>[i, j]</tt> that
has been sent. You might want to try again from the byte
following that. The error message can be '<tt>closed</tt>'
in case the connection was closed before the transmission
was completed or the string '<tt>timeout</tt>' in case
there was a timeout during the operation.
</p>
<p class=note>
Note: Output is <em>not</em> buffered. For small strings,
it is always better to concatenate them in Lua
(with the '<tt>..</tt>' operator) and send the result in one call
instead of calling the method several times.
</p>
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setoption>
client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class=description>
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
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:
<ul>
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
the periodic transmission of messages on a connected socket. Should the
connected party fail to respond to these messages, the connection is
considered broken and processes using the socket are notified;
<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
boolean entry '<tt>on</tt>' and a numeric entry for the time interval
'<tt>timeout</tt>' in seconds. If the '<tt>on</tt>' field is set to
<tt>true</tt>, the system will block the process on the close attempt until
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
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
zero;
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
used in validating addresses supplied in a call to
<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>
disables the Nagle's algorithm for the connection.
</ul>
<p class=return>
The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setstats>
master:<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>
</p>
<p class=description>
Resets accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class=parameters>
<tt>Received</tt> is a number with the new number of bytes received.
<tt>Sent</tt> is a number with the new number of bytes sent.
<tt>Age</tt> is the new age in seconds.
</p>
<p class=return>
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=settimeout>
master:<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>
</p>
<p class=description>
Changes the timeout values for the object. By default,
all I/O operations are blocking. That is, any call to the methods
<a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, and
<a href=#accept><tt>accept</tt></a>
will block indefinitely, until the operation completes. The
<tt>settimeout</tt> method defines a limit on the amount of time the
I/O methods can block. When a timeout is set and the specified amount of
time has elapsed, the affected methods give up and fail with an error code.
</p>
<p class=parameters>
The amount of time to wait is specified as the
<tt>value</tt> parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning:
</p>
<ul>
<li> '<tt>b</tt>': <em>block</em> timeout. Specifies the upper limit on
the amount of time LuaSocket can be blocked by the operating system
while waiting for completion of any single I/O operation. This is the
default mode;</li>
<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
a call.</li>
</ul>
<p class=parameters>
The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block
indefinitely. Negative timeout values have the same effect.
</p>
<p class=note>
Note: although timeout values have millisecond precision in LuaSocket,
large blocks can cause I/O functions not to respect timeout values due
to the time the library takes to transfer blocks to and from the OS
and to and from the Lua interpreter. Also, function that accept host names
and perform automatic name resolution might be blocked by the resolver for
longer than the specified timeout value.
</p>
<p class=note>
Note: The old <tt>timeout</tt> method is deprecated. The name has been
changed for sake of uniformity, since all other method names already
contained verbs making their imperative nature obvious.
</p>
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=shutdown>
client:<b>shutdown(</b>mode<b>)</b><br>
</p>
<p class=description>
Shuts down part of a full-duplex connection.
</p>
<p class=parameters>
Mode tells which way of the connection should be shut down and can
take the value:
<ul>
<li>"<tt>both</tt>": disallow further sends and receives on the object.
This is the default mode;
<li>"<tt>send</tt>": disallow further sends on the object;
<li>"<tt>receive</tt>": disallow further receives on the object.
</ul>
<p class=return>
This function returns 1.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:57 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

183
docs/dns.html Normal file
View File

@ -0,0 +1,183 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: DNS support">
<meta name="keywords" content="Lua, LuaSocket, DNS, Network, Library, Support">
<title>LuaSocket: DNS support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="dns">DNS</h2>
<p>
IPv4 name resolution functions
<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>
<blockquote><tt>
resolved4 = {<br>
&nbsp;&nbsp;name = <i>canonic-name</i>,<br>
&nbsp;&nbsp;alias = <i>alias-list</i>,<br>
&nbsp;&nbsp;ip = <i>ip-address-list</i><br>
}
</tt> </blockquote>
<p>
Note that the <tt>alias</tt> list can be empty.
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="gethostname">
socket.dns.<b>gethostname()</b>
</p>
<p class="description">
Returns the standard host name for the machine as a string.
</p>
<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="tohostname">
socket.dns.<b>tohostname(</b>address<b>)</b>
</p>
<p class="description">
Converts from IPv4 address to host name.
</p>
<p class="parameters">
<tt>Address</tt> can be an IP address or host name.
</p>
<p class="return">
The function returns a string with the canonic host name of the given
<tt>address</tt>, followed by 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>
<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="toip">
socket.dns.<b>toip(</b>address<b>)</b>
</p>
<p class="description">
Converts from host name to IPv4 address.
</p>
<p class="parameters">
<tt>Address</tt> can be an IP address or host name.
</p>
<p class="return">
Returns a string with the first IP address found for <tt>address</tt>,
followed by 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>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="footer">
<hr>
<center>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:07 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
@ -13,22 +13,22 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -36,13 +36,13 @@
<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ftp>FTP</h2>
<h2 id="ftp">FTP</h2>
<p>
FTP (File Transfer Protocol) is a protocol used to transfer files
between hosts. The <tt>ftp</tt> namespace offers thorough support
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>
@ -50,28 +50,28 @@ High level functions are provided supporting the most common operations.
These high level functions are implemented on top of a lower level
interface. Using the low-level interface, users can easily create their
own functions to access <em>any</em> operation supported by the FTP
protocol. For that, check the implementation.
protocol. For that, check the implementation.
</p>
<p>
To really benefit from this module, a good understanding of
To really benefit from this module, a good understanding of
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
LTN012, Filters sources and sinks</a> is necessary.
LTN012, Filters sources and sinks</a> is necessary.
</p>
<p>
<p>
To obtain the <tt>ftp</tt> namespace, run:
</p>
<pre class=example>
<pre class="example">
-- loads the FTP module and any libraries it requires
local ftp = require("socket.ftp")
</pre>
<p>
URLs MUST conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
1738</a>, that is, an URL is a string in the form:
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
<blockquote>
@ -81,20 +81,19 @@ URLs MUST conform to
<p>
The following constants in the namespace can be set to control the default behavior of
the FTP module:
the FTP module:
</p>
<ul>
<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>USER</tt>: default anonymous user;
<li> <tt>PASSWORD</tt>: default anonymous password.</li>
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
<li> <tt>USER</tt>: default anonymous user;</li>
</ul>
<!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=get>
<p class="name" id="get">
ftp.<b>get(</b>url<b>)</b><br>
ftp.<b>get{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br>
@ -110,19 +109,19 @@ ftp.<b>get{</b><br>
<b>}</b>
</p>
<p class=description>
<p class="description">
The <tt>get</tt> function has two forms. The simple form has fixed
functionality: it downloads the contents of a URL and returns it as a
string. The generic form allows a <em>lot</em> more control, as explained
below.
</p>
<p class=parameters>
<p class="parameters">
If the argument of the <tt>get</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of
expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
precedence). <tt>Host</tt> is the server to connect to. <tt>Sink</tt> is
the <em>simple</em>
the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink that will receive the downloaded data. <tt>Argument</tt> or
<tt>path</tt> give the target path to the resource in the server. The
@ -130,28 +129,28 @@ optional arguments are the following:
</p>
<ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
<li><tt>command</tt>: The FTP command used to obtain data. Defaults to
"<tt>retr</tt>", but see example below;
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;
"<tt>retr</tt>", but see example below;</li>
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default;
<li><tt>step</tt>:
"<tt>a</tt>". Defaults to whatever is the server default;</li>
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
<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>
</ul>
<p class=return>
<p class="return">
If successful, the simple version returns the URL contents as a
string, and the generic function returns 1. In case of error, both
functions return <b><tt>nil</tt></b> and an error message describing the
error.
error.
</p>
<pre class=example>
<pre class="example">
-- load the ftp support
local ftp = require("socket.ftp")
@ -160,7 +159,7 @@ local ftp = require("socket.ftp")
f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
</pre>
<pre class=example>
<pre class="example">
-- load needed modules
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
@ -179,7 +178,7 @@ end
<!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=put>
<p class="name" id="put">
ftp.<b>put(</b>url, content<b>)</b><br>
ftp.<b>put{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br>
@ -195,57 +194,57 @@ ftp.<b>put{</b><br>
<b>}</b>
</p>
<p class=description>
<p class="description">
The <tt>put</tt> function has two forms. The simple form has fixed
functionality: it uploads a string of content into a URL. The generic form
allows a <em>lot</em> more control, as explained below.
allows a <em>lot</em> more control, as explained below.
</p>
<p class=parameters>
<p class="parameters">
If the argument of the <tt>put</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of
expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
precedence). <tt>Host</tt> is the server to connect to. <tt>Source</tt> is
the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that will provide the contents to be uploaded.
the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that will provide the contents to be uploaded.
<tt>Argument</tt> or
<tt>path</tt> give the target path to the resource in the server. The
optional arguments are the following:
</p>
<ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
<li><tt>command</tt>: The FTP command used to send data. Defaults to
"<tt>stor</tt>", but see example below;
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;
"<tt>stor</tt>", but see example below;</li>
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default;
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
"<tt>a</tt>". Defaults to whatever is the server default;</li>
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
<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>
</ul>
<p class=return>
<p class="return">
Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error
message describing the reason for failure.
</p>
<pre class=example>
<pre class="example">
-- load the ftp support
local ftp = require("socket.ftp")
-- Log as user "fulano" on server "ftp.example.com",
-- using password "silva", and store a file "README" with contents
-- using password "silva", and store a file "README" with contents
-- "wrong password, of course"
f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",
f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",
"wrong password, of course")
</pre>
<pre class=example>
<pre class="example">
-- load the ftp support
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
@ -254,7 +253,7 @@ local ltn12 = require("ltn12")
-- using password "silva", and append to the remote file "LOG", sending the
-- contents of the local file "LOCAL-LOG"
f, e = ftp.put{
host = "ftp.example.com",
host = "ftp.example.com",
user = "fulano",
password = "silva",
command = "appe",
@ -266,15 +265,15 @@ f, e = ftp.put{
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
<p>
<small>

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">
<html>
<head>
<meta name="description" content="LuaSocket: HTTP support">
<meta name="keywords" content="Lua, HTTP, Library, WWW, Browser, Network, Support">
<meta name="keywords" content="Lua, HTTP, Library, WWW, Browser, Network, Support">
<title>LuaSocket: HTTP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
@ -13,22 +13,22 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</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="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -36,45 +36,43 @@
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=http>HTTP</h2>
<h2 id="http">HTTP</h2>
<p>
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
information between web-browsers and servers. The <tt>http</tt>
namespace offers full support for the client side of the HTTP
namespace offers full support for the client side of the HTTP
protocol (i.e.,
the facilities that would be used by a web-browser implementation). The
implementation conforms to the HTTP/1.1 standard,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
2616</a>.
<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p>
The module exports functions that provide HTTP functionality in different
levels of abstraction. From the simple
levels of abstraction. From the simple
string oriented requests, through generic
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based, down to even lower-level if you bother to look through the source code.
</p>
<p>
<p>
To obtain the <tt>http</tt> namespace, run:
</p>
<pre class=example>
<pre class="example">
-- loads the HTTP module and any libraries it requires
local http = require("socket.http")
</pre>
<p>
URLs must conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
1738</a>,
that is, an URL is a string in the form:
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
<blockquote>
<pre>
[http://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;]
[http://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;]
</pre>
</blockquote>
@ -97,31 +95,36 @@ headers = {<br>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names.
Field names are case insensitive (as specified by the standard) and all
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.
</p>
<p class=note>
<p class="note">
Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table.
in representing them in a Lua table.
</p>
<p>
The following constants can be set to control the default behavior of
the HTTP module:
the HTTP module:
</p>
<ul>
<li> <tt>PORT</tt>: default port 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>USERAGENT</tt>: default user agent reported to server.
<li> <tt>PROXY</tt>: default proxy used for connections;</li>
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
<li> <tt>USERAGENT</tt>: default user agent reported to server.</li>
</ul>
<p class="note">
Note: These constants are global. Changing them will also
change the behavior other code that might be using LuaSocket.
</p>
<!-- 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><br>
&nbsp;&nbsp;url = <i>string</i>,<br>
@ -132,30 +135,31 @@ http.<b>request{</b><br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[proxy = <i>string</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>
</p>
<p class=description>
The request function has two forms. The simple form downloads
a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based
on strings. The generic form performs any HTTP method and is
<a href=http://lua-users.org/wiki/FiltersSourcesAndSinks>LTN12</a> based.
<p class="description">
The request function has two forms. The simple form downloads
a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based
on strings. The generic form performs any HTTP method and is
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based.
</p>
<p class=parameters>
<p class="parameters">
If the first argument of the <tt>request</tt> function is a string, it
should be an <tt>url</tt>. In that case, if a <tt>body</tt>
is provided as a string, the function will perform a <tt>POST</tt> method
in the <tt>url</tt>. Otherwise, it performs a <tt>GET</tt> in the
<tt>url</tt>
<tt>url</tt>
</p>
<p class=parameters>
If the first argument is instead a table, the most important fields are
<p class="parameters">
If the first argument is instead a table, the most important fields are
the <tt>url</tt> and the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>sink</tt> that will receive the downloaded content.
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>sink</tt> that will receive the downloaded content.
Any part of the <tt>url</tt> can be overridden by including
the appropriate field in the request table.
If authentication information is provided, the function
@ -165,49 +169,51 @@ function discards the downloaded data. The optional parameters are the
following:
</p>
<ul>
<li><tt>method</tt>: The HTTP request method. Defaults to "GET";
<li><tt>headers</tt>: Any additional HTTP headers to send with the request;
<li><tt>source</tt>: <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<li><tt>method</tt>: The HTTP request method. Defaults to "GET";</li>
<li><tt>headers</tt>: Any additional HTTP headers to send with the request;</li>
<li><tt>source</tt>: <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source to provide the request body. If there
is a body, you need to provide an appropriate "<tt>content-length</tt>"
request header field, or the function will attempt to send the body as
"<tt>chunked</tt>" (something few servers support). Defaults to the empty source;
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to move data.
Defaults to the LTN12 <tt>pump.step</tt> function.
<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;
<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
function from automatically following 301 or 302 server redirect messages;
"<tt>chunked</tt>" (something few servers support). Defaults to the empty source;</li>
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to move data.
Defaults to the LTN12 <tt>pump.step</tt> function.</li>
<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;</li>
<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
function from automatically following 301 or 302 server redirect messages;</li>
<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>
<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).</li>
</ul>
<p class=return>
<p class="return">
In case of failure, the function returns <tt><b>nil</b></tt> followed by an
error message. If successful, the simple form returns the response
error message. If successful, the simple form returns the response
body as a string, followed by the response status code, the response
headers and the response status line. The generic function returns the same
information, except the first return value is just the number 1 (the body
goes to the <tt>sink</tt>).
</p>
<p class=return>
Even when the server fails to provide the contents of the requested URL (URL not found, for example),
<p class="return">
Even when the server fails to provide the contents of the requested URL (URL not found, for example),
it usually returns a message body (a web page informing 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
a list of the possible values and their meanings, refer to <a
href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
2616</a>.
href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p class=description>
<p class="description">
Here are a few examples with the simple interface:
</p>
<pre class=example>
<pre class="example">
-- load the http module
local io = require("io")
local http = require("socket.http")
@ -215,15 +221,15 @@ local ltn12 = require("ltn12")
-- connect to server "www.cs.princeton.edu" and retrieves this manual
-- file from "~diego/professional/luasocket/http.html" and print it to stdout
http.request{
url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html",
http.request{
url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html",
sink = ltn12.sink.file(io.stdout)
}
-- connect to server "www.example.com" and tries to retrieve
-- "/private/index.html". Fails because authentication is needed.
b, c, h = http.request("http://www.example.com/private/index.html")
-- b returns some useless page telling about the denied access,
-- b returns some useless page telling about the denied access,
-- h returns authentication information
-- and c returns with value 401 (Authentication Required)
@ -233,11 +239,11 @@ r, e = http.request("http://wrong.host/")
-- r is nil, and e returns with value "host not found"
</pre>
<p class=description>
<p class="description">
And here is an example using the generic interface:
</p>
<pre class=example>
<pre class="example">
-- load the http module
http = require("socket.http")
@ -259,7 +265,7 @@ r, c, h = http.request {
-- }
</pre>
<p class=note id=post>
<p class="note" id="post">
Note: When sending a POST request, simple interface adds a
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
header to the request. This is the type used by
@ -267,21 +273,21 @@ HTML forms. If you need another type, use the generic
interface.
</p>
<p class=note id=authentication>
<p class="note" id="authentication">
Note: Some URLs are protected by their
servers from anonymous download. For those URLs, the server must receive
some sort of authentication along with the request or it will deny
download and return status "401&nbsp;Authentication Required".
download and return status "401&nbsp;Authentication Required".
</p>
<p class=note>
<p class="note">
The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both
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 class=note>The Basic Authentication Scheme sends
<p class="note">The Basic Authentication Scheme sends
<tt>&lt;user&gt;</tt> and
<tt>&lt;password&gt;</tt> unencrypted to the server and is therefore
considered unsafe. Unfortunately, by the time of this implementation,
@ -290,7 +296,7 @@ Therefore, this is the method used by the toolkit whenever
authentication is required.
</p>
<pre class=example>
<pre class="example">
-- load required modules
http = require("socket.http")
mime = require("mime")
@ -304,26 +310,26 @@ b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
-- the request directly.
r, c = http.request {
url = "http://www.example.com/private/index.html",
headers = { authentication = "Basic " .. (mime.b64("fulano:silva")) }
headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
}
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:26 EDT 2006
Last modified by Eric Westbrook on <br>
Sat Feb 23 19:09:42 UTC 2019
</small>
</p>
</center>

138
docs/index.html Normal file
View File

@ -0,0 +1,138 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="The LuaSocket Homepage">
<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
<title>LuaSocket: Network support for the Lua language </title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="whatis">What is LuaSocket?</h2>
<p>
LuaSocket is a <a href="http://www.lua.org">Lua</a> 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.
</p>
<p>
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
properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and UNIX platforms. </p>
<p>
Among the support modules, the most commonly used implement the
<a href="smtp.html">SMTP</a>
(sending e-mails),
<a href="http.html">HTTP</a>
(WWW access) and
<a href="ftp.html">FTP</a>
(uploading and downloading files) client
protocols. These provide a very natural and generic interface to the
functionality defined by each protocol.
In addition, you will find that the
<a href="mime.html">MIME</a> (common encodings),
<a href="url.html">URL</a>
(anything you could possible want to do with one) and
<a href="ltn12.html">LTN12</a>
(filters, sinks, sources and pumps) modules can be very handy.
</p>
<p>
The library is available under the same
<a href="http://www.lua.org/copyright.html">
terms and conditions</a> as the Lua language, the MIT license. The idea is
that if you can use Lua in a project, you should also be able to use
LuaSocket.
</p>
<p>
Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
Author: <a href="http://www.impa.br/~diego">Diego Nehab</a>
</p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="download">Download</h2>
<p>
LuaSocket version 3.1.0 is now available for download!
It is compatible with Lua&nbsp;5.1 through 5.4.
Chances are it works well on most UNIX distributions and Windows flavors.
</p>
<p>
The current version of the library can be found at
the <a href="https://github.com/lunarmodules/luasocket">LuaSocket
project page</a> on GitHub. Besides the full C and Lua source code
for the library, the distribution contains several examples,
this user's manual and basic test procedures.
</p>
<p> Take a look at the <a
href="installation.html">installation</a> section of the
manual to find out how to properly install the library.
</p>
<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="thanks">Special thanks</h2>
<p>
This marks the first release of LuaSocket that
wholeheartedly embraces the open-source development
philosophy. After a long hiatus, Matthew Wild finally
convinced me it was time for a release including IPv6 and
Lua 5.2 support. It was more work than we anticipated.
Special thanks to Sam Roberts, Florian Zeitz, and Paul
Aurich, Liam Devine, Alexey Melnichuk, and everybody else
that has helped bring this library back to life.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="footer">
<hr>
<center>
<p class="bar">
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
</div>
</body>
</html>

View File

@ -25,8 +25,8 @@ Installation">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -39,24 +39,10 @@ Installation">
<h2>Installation</h2>
<p> LuaSocket 2.0.2 uses the new package system for Lua 5.1.
All Lua library developers are encouraged to update their libraries so that
all libraries can coexist peacefully and users can benefit from the
standardization and flexibility of the standard.
</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>
<p> Here we 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>
@ -64,14 +50,19 @@ scheme will likely already have been answered. </p>
directories, one for system dependent files, and another for system
independent files. Let's call these directories <tt>&lt;CDIR&gt;</tt>
and <tt>&lt;LDIR&gt;</tt>, respectively.
For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.0</tt>' for
<tt>&lt;LDIR&gt;</tt>. On Windows, sometimes only one directory is used, say
'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket
For example, in my laptp, Lua&nbsp;5.1 is configured to
use '<tt>/usr/local/lib/lua/5.1</tt>' for
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.1</tt>' for
<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>
<pre class=example>
&lt;LDIR&gt;/compat-5.1.lua
&lt;LDIR&gt;/ltn12.lua
&lt;LDIR&gt;/socket.lua
&lt;CDIR&gt;/socket/core.dll
@ -88,33 +79,6 @@ distribution directory structure:</p>
would be replaced by <tt>core.so</tt>.
</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>
<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>
<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; print(socket._VERSION)
--&gt; LuaSocket 2.0.2
--&gt; LuaSocket 3.0.0
</pre>
<p> Each module loads their dependencies automatically, so you only need to
load the modules you directly depend upon: </p>
<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; 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
</pre>
@ -144,8 +108,8 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -153,7 +117,7 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:30 EDT 2006
Tue Jun 11 19:06:14 HKT 2013
</small>
</p>
</center>

View File

@ -25,8 +25,8 @@ Library, Support">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<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>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -1,4 +1,4 @@
<!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">
<html>
@ -14,22 +14,22 @@ Pump, Support, Library">
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -37,7 +37,7 @@ Pump, Support, Library">
<!-- ltn12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ltn12>LTN12</h2>
<h2 id="ltn12">LTN12</h2>
<p> The <tt>ltn12</tt> namespace implements the ideas described in
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
@ -46,11 +46,11 @@ functions. Please refer to the LTN for a deeper explanation of the
functionality provided by this module.
</p>
<p>
<p>
To obtain the <tt>ltn12</tt> namespace, run:
</p>
<pre class=example>
<pre class="example">
-- loads the LTN21 module
local ltn12 = require("ltn12")
</pre>
@ -61,32 +61,32 @@ local ltn12 = require("ltn12")
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="filter.chain">
ltn12.filter.<b>chain(</b>filter<sub>1</sub>, filter<sub>2</sub>
<p class="name" id="filter.chain">
ltn12.filter.<b>chain(</b>filter<sub>1</sub>, filter<sub>2</sub>
[, ... filter<sub>N</sub>]<b>)</b>
</p>
<p class=description>
<p class="description">
Returns a filter that passes all data it receives through each of a
series of given filters.
series of given filters.
</p>
<p class=parameters>
<p class="parameters">
<tt>Filter<sub>1</sub></tt> to <tt>filter<sub>N</sub></tt> are simple
filters.
filters.
</p>
<p class=return>
<p class="return">
The function returns the chained filter.
</p>
<p class=note>
<p class="note">
The nesting of filters can be arbitrary. For instance, the useless filter
below doesn't do anything but return the data that was passed to it,
unaltered.
</p>
<pre class=example>
<pre class="example">
-- load required modules
local ltn12 = require("ltn12")
local mime = require("mime")
@ -102,26 +102,26 @@ id = ltn12.filter.chain(
<!-- cycle ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="filter.cycle">
<p class="name" id="filter.cycle">
ltn12.filter.<b>cycle(</b>low [, ctx, extra]<b>)</b>
</p>
<p class=description>
<p class="description">
Returns a high-level filter that cycles though a low-level filter by
passing it each chunk and updating a context between calls.
passing it each chunk and updating a context between calls.
</p>
<p class=parameters>
<tt>Low</tt> is the low-level filter to be cycled,
<p class="parameters">
<tt>Low</tt> is the low-level filter to be cycled,
<tt>ctx</tt> is the initial context and <tt>extra</tt> is any extra
argument the low-level filter might take.
</p>
<p class=return>
The function returns the high-level filter.
<p class="return">
The function returns the high-level filter.
</p>
<pre class=example>
<pre class="example">
-- load the ltn12 module
local ltn12 = require("ltn12")
@ -137,15 +137,15 @@ end
<!-- all ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="pump.all">
<p class="name" id="pump.all">
ltn12.pump.<b>all(</b>source, sink<b>)</b>
</p>
<p class=description>
Pumps <em>all</em> data from a <tt>source</tt> to a <tt>sink</tt>.
<p class="description">
Pumps <em>all</em> data from a <tt>source</tt> to a <tt>sink</tt>.
</p>
<p class=return>
<p class="return">
If successful, the function returns a value that evaluates to
<b><tt>true</tt></b>. In case
of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
@ -153,15 +153,15 @@ of error, the function returns a <b><tt>false</tt></b> value, followed by an err
<!-- step +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="pump.step">
<p class="name" id="pump.step">
ltn12.pump.<b>step(</b>source, sink<b>)</b>
</p>
<p class=description>
Pumps <em>one</em> chunk of data from a <tt>source</tt> to a <tt>sink</tt>.
<p class="description">
Pumps <em>one</em> chunk of data from a <tt>source</tt> to a <tt>sink</tt>.
</p>
<p class=return>
<p class="return">
If successful, the function returns a value that evaluates to
<b><tt>true</tt></b>. In case
of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
@ -173,103 +173,103 @@ of error, the function returns a <b><tt>false</tt></b> value, followed by an err
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.chain">
<p class="name" id="sink.chain">
ltn12.sink.<b>chain(</b>filter, sink<b>)</b>
</p>
<p class=description>
Creates and returns a new sink that passes data through a <tt>filter</tt> before sending it to a given <tt>sink</tt>.
<p class="description">
Creates and returns a new sink that passes data through a <tt>filter</tt> before sending it to a given <tt>sink</tt>.
</p>
<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.error">
<p class="name" id="sink.error">
ltn12.sink.<b>error(</b>message<b>)</b>
</p>
<p class=description>
<p class="description">
Creates and returns a sink that aborts transmission with the error
<tt>message</tt>.
</p>
<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.file">
<p class="name" id="sink.file">
ltn12.sink.<b>file(</b>handle, message<b>)</b>
</p>
<p class=description>
Creates a sink that sends data to a file.
<p class="description">
Creates a sink that sends data to a file.
</p>
<p class=parameters>
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
<p class="parameters">
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
</p>
<p class=return>
<p class="return">
The function returns a sink that sends all data to the given <tt>handle</tt>
and closes the file when done, or a sink that aborts the transmission with
the error <tt>message</tt>
</p>
<p class=note>
In the following example, notice how the prototype is designed to
<p class="note">
In the following example, notice how the prototype is designed to
fit nicely with the <tt>io.open</tt> function.
</p>
<pre class=example>
<pre class="example">
-- load the ltn12 module
local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png")),
ltn12.sink.file(io.open("copy.png"))
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
<!-- null +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.null">
<p class="name" id="sink.null">
ltn12.sink.<b>null()</b>
</p>
<p class=description>
Returns a sink that ignores all data it receives.
<p class="description">
Returns a sink that ignores all data it receives.
</p>
<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.simplify">
<p class="name" id="sink.simplify">
ltn12.sink.<b>simplify(</b>sink<b>)</b>
</p>
<p class=description>
Creates and returns a simple sink given a fancy <tt>sink</tt>.
<p class="description">
Creates and returns a simple sink given a fancy <tt>sink</tt>.
</p>
<!-- table ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.table">
<p class="name" id="sink.table">
ltn12.sink.<b>table(</b>[table]<b>)</b>
</p>
<p class=description>
<p class="description">
Creates a sink that stores all chunks in a table. The chunks can later be
efficiently concatenated into a single string.
</p>
<p class=parameters>
<p class="parameters">
<tt>Table</tt> is used to hold the chunks. If
<tt><b>nil</b></tt>, the function creates its own table.
<tt><b>nil</b></tt>, the function creates its own table.
</p>
<p class=return>
The function returns the sink and the table used to store the chunks.
<p class="return">
The function returns the sink and the table used to store the chunks.
</p>
<pre class=example>
<pre class="example">
-- load needed modules
local http = require("socket.http")
local ltn12 = require("ltn12")
@ -291,128 +291,138 @@ end
<!-- cat ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.cat">
<p class="name" id="source.cat">
ltn12.source.<b>cat(</b>source<sub>1</sub> [, source<sub>2</sub>, ...,
source<sub>N</sub>]<b>)</b>
</p>
<p class=description>
<p class="description">
Creates a new source that produces the concatenation of the data produced
by a number of sources.
by a number of sources.
</p>
<p class=parameters>
<p class="parameters">
<tt>Source<sub>1</sub></tt> to <tt>source<sub>N</sub></tt> are the original
sources.
sources.
</p>
<p class=return>
<p class="return">
The function returns the new source.
</p>
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.chain">
<p class="name" id="source.chain">
ltn12.source.<b>chain(</b>source, filter<b>)</b>
</p>
<p class=description>
Creates a new <tt>source</tt> that passes data through a <tt>filter</tt>
before returning it.
<p class="description">
Creates a new <tt>source</tt> that passes data through a <tt>filter</tt>
before returning it.
</p>
<p class=return>
<p class="return">
The function returns the new source.
</p>
<!-- empty ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.empty">
<p class="name" id="source.empty">
ltn12.source.<b>empty()</b>
</p>
<p class=description>
Creates and returns an empty source.
<p class="description">
Creates and returns an empty source.
</p>
<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.error">
<p class="name" id="source.error">
ltn12.source.<b>error(</b>message<b>)</b>
</p>
<p class=description>
<p class="description">
Creates and returns a source that aborts transmission with the error
<tt>message</tt>.
</p>
<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.file">
<p class="name" id="source.file">
ltn12.source.<b>file(</b>handle, message<b>)</b>
</p>
<p class=description>
Creates a source that produces the contents of a file.
<p class="description">
Creates a source that produces the contents of a file.
</p>
<p class=parameters>
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
<p class="parameters">
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
</p>
<p class=return>
The function returns a source that reads chunks of data from
<p class="return">
The function returns a source that reads chunks of data from
given <tt>handle</tt> and returns it to the user,
closing the file when done, or a source that aborts the transmission with
the error <tt>message</tt>
</p>
<p class=note>
In the following example, notice how the prototype is designed to
<p class="note">
In the following example, notice how the prototype is designed to
fit nicely with the <tt>io.open</tt> function.
</p>
<pre class=example>
<pre class="example">
-- load the ltn12 module
local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png")),
ltn12.sink.file(io.open("copy.png"))
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.simplify">
<p class="name" id="source.simplify">
ltn12.source.<b>simplify(</b>source<b>)</b>
</p>
<p class=description>
Creates and returns a simple source given a fancy <tt>source</tt>.
<p class="description">
Creates and returns a simple source given a fancy <tt>source</tt>.
</p>
<!-- string +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.string">
<p class="name" id="source.string">
ltn12.source.<b>string(</b>string<b>)</b>
</p>
<p class=description>
<p class="description">
Creates and returns a source that produces the contents of a
<tt>string</tt>, chunk by chunk.
<tt>string</tt>, chunk by chunk.
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

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">
<html>
<head>
<meta name="description" content="LuaSocket: MIME support">
<meta name="keywords" content="Lua, LuaSocket, MIME, Library, Support">
<meta name="keywords" content="Lua, LuaSocket, MIME, Library, Support">
<title>LuaSocket: MIME module</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
@ -13,22 +13,22 @@
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -36,33 +36,33 @@
<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=mime>MIME</h2>
<h2 id="mime">MIME</h2>
<p>
The <tt>mime</tt> namespace offers filters that apply and remove common
content transfer encodings, such as Base64 and Quoted-Printable.
It also provides functions to break text into lines and change
the end-of-line convention.
MIME is described mainly in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2048.txt">2049</a>.
MIME is described mainly in
<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
</p>
<p>
All functionality provided by the MIME module
follows the ideas presented in
All functionality provided by the MIME module
follows the ideas presented in
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
LTN012, Filters sources and sinks</a>.
LTN012, Filters sources and sinks</a>.
</p>
<p>
<p>
To obtain the <tt>mime</tt> namespace, run:
</p>
<pre class=example>
<pre class="example">
-- loads the MIME module and everything it requires
local mime = require("mime")
</pre>
@ -70,88 +70,60 @@ local mime = require("mime")
<!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="decode">
<p class="name" id="decode">
mime.<b>decode(</b>"base64"<b>)</b><br>
mime.<b>decode(</b>"quoted-printable"<b>)</b>
</p>
<p class=description>
<p class="description">
Returns a filter that decodes data from a given transfer content
encoding.
</p>
<!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="encode">
<p class="name" id="encode">
mime.<b>encode(</b>"base64"<b>)</b><br>
mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b>
</p>
<p class=description>
<p class="description">
Returns a filter that encodes data according to a given transfer content
encoding.
</p>
<p class=parameters>
<p class="parameters">
In the Quoted-Printable case, the user can specify whether the data is
textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or
"<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>".
</p>
<p class=note>
<p class="note">
Although both transfer content encodings specify a limit for the line
length, the encoding filters do <em>not</em> break text into lines (for
added flexibility).
added flexibility).
Below is a filter that converts binary data to the Base64 transfer content
encoding and breaks it into lines of the correct size.
</p>
<pre class=example>
<pre class="example">
base64 = ltn12.filter.chain(
mime.encode("base64"),
mime.wrap("base64")
)
</pre>
<p class=note>
<p class="note">
Note: Text data <em>has</em> to be converted to canonic form
<em>before</em> being encoded.
</p>
<pre class=example>
<pre class="example">
base64 = ltn12.filter.chain(
mime.normalize(),
mime.encode("base64"),
@ -159,50 +131,79 @@ base64 = ltn12.filter.chain(
)
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="stuff">
<p class="name" id="stuff">
mime.<b>stuff()</b><br>
</p>
<p class=description>
<p class="description">
Creates and returns a filter that performs stuffing of SMTP messages.
</p>
<p class=note>
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function
<p class="note">
Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to chain it with your
source, or apply it to your message body.
source, or apply it to your message body.
</p>
<!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrap">
<p class="name" id="wrap">
mime.<b>wrap(</b>"text" [, length]<b>)</b><br>
mime.<b>wrap(</b>"base64"<b>)</b><br>
mime.<b>wrap(</b>"quoted-printable"<b>)</b>
</p>
<p class=description>
Returns a filter that breaks data into lines.
<p class="description">
Returns a filter that breaks data into lines.
</p>
<p class=parameters>
The "<tt>text</tt>" line-wrap filter simply breaks text into lines by
inserting CRLF end-of-line markers at appropriate positions.
<tt>Length</tt> defaults 76.
<p class="parameters">
The "<tt>text</tt>" line-wrap filter simply breaks text into lines by
inserting CRLF end-of-line markers at appropriate positions.
<tt>Length</tt> defaults 76.
The "<tt>base64</tt>" line-wrap filter works just like the default
"<tt>text</tt>" line-wrap filter with default length.
"<tt>text</tt>" line-wrap filter with default length.
The function can also wrap "<tt>quoted-printable</tt>" lines, taking care
not to break lines in the middle of an escaped character. In that case, the
line length is fixed at 76.
</p>
<p class=note>
<p class="note">
For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following:
</p>
<pre class=example>
<pre class="example">
qp = ltn12.filter.chain(
mime.normalize(),
mime.encode("quoted-printable"),
@ -210,155 +211,155 @@ qp = ltn12.filter.chain(
)
</pre>
<p class=note>
<p class="note">
Note: To break into lines with a different end-of-line convention, apply
a normalization filter after the line break filter.
a normalization filter after the line break filter.
</p>
<!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=low>Low-level filters</h3>
<h3 id="low">Low-level filters</h3>
<!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="b64">
<p class="name" id="b64">
A, B = mime.<b>b64(</b>C [, D]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Base64 encoding.
<p class="description">
Low-level filter to perform Base64 encoding.
</p>
<p class=description>
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
<p class="description">
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
</p>
<p class=note>
<p class="note">
Note: The simplest use of this function is to encode a string into it's
Base64 transfer content encoding. Notice the extra parenthesis around the
call to <tt>mime.b64</tt>, to discard the second return value.
</p>
<pre class=example>
<pre class="example">
print((mime.b64("diego:password")))
--&gt; ZGllZ286cGFzc3dvcmQ=
</pre>
<!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dot">
<p class="name" id="dot">
A, n = mime.<b>dot(</b>m [, B]<b>)</b>
</p>
<p class=description>
<p class="description">
Low-level filter to perform SMTP stuffing and enable transmission of
messages containing the sequence "CRLF.CRLF".
messages containing the sequence "CRLF.CRLF".
</p>
<p class=parameters>
<p class="parameters">
<tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the
number of characters from the sequence CRLF seen in the end of <tt>B</tt>.
'<tt>m</tt>' should tell the same, but for the previous chunk.
</p>
<p class=note>Note: The message body is defined to begin with
<p class="note">Note: The message body is defined to begin with
an implicit CRLF. Therefore, to stuff a message correctly, the
first <tt>m</tt> should have the value 2.
first <tt>m</tt> should have the value 2.
</p>
<pre class=example>
<pre class="example">
print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n")))
--&gt; ..\nStuffing the message.\n..\n..
</pre>
<p class=note>
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to
apply it again.
<p class="note">
Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to
apply it again.
</p>
<!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="eol">
<p class="name" id="eol">
A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b>
</p>
<p class=description>
Low-level filter to perform end-of-line marker translation.
<p class="description">
Low-level filter to perform end-of-line marker translation.
For each chunk, the function needs to know if the last character of the
previous chunk could be part of an end-of-line marker or not. This is the
context the function receives besides the chunk. An updated version of
the context is returned after each new chunk.
the context is returned after each new chunk.
</p>
<p class=parameters>
<p class="parameters">
<tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the
ASCII value of the last character of the previous chunk, if it was a
candidate for line break, or 0 otherwise.
candidate for line break, or 0 otherwise.
<tt>B</tt> is the same as <tt>C</tt>, but for the current
chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF.
</p>
<pre class=example>
<pre class="example">
-- translates the end-of-line marker to UNIX
unix = mime.eol(0, dos, "\n")
unix = mime.eol(0, dos, "\n")
</pre>
<!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qp">
<p class="name" id="qp">
A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Quoted-Printable encoding.
<p class="description">
Low-level filter to perform Quoted-Printable encoding.
</p>
<p class=parameters>
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
Throughout encoding, occurrences of CRLF are replaced by the
<p class="parameters">
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
Throughout encoding, occurrences of CRLF are replaced by the
<tt>marker</tt>, which itself defaults to CRLF.
</p>
<p class=note>
<p class="note">
Note: The simplest use of this function is to encode a string into it's
Quoted-Printable transfer content encoding.
Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value.
</p>
<pre class=example>
print((mime.qp("maçã")))
<pre class="example">
print((mime.qp("ma<EFBFBD><EFBFBD>")))
--&gt; ma=E7=E3=
</pre>
<!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qpwrp">
<p class="name" id="qpwrp">
A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b>
</p>
<p class=description>
Low-level filter to break Quoted-Printable text into lines.
<p class="description">
Low-level filter to break Quoted-Printable text into lines.
</p>
<p class=parameters>
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
<p class="parameters">
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
</p>
<p class=note>
<p class="note">
Note: Besides breaking text into lines, this function makes sure the line
breaks don't fall in the middle of an escaped character combination. Also,
this function only breaks lines that are bigger than <tt>length</tt> bytes.
@ -366,86 +367,86 @@ this function only breaks lines that are bigger than <tt>length</tt> bytes.
<!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unb64">
<p class="name" id="unb64">
A, B = mime.<b>unb64(</b>C [, D]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Base64 decoding.
<p class="description">
Low-level filter to perform Base64 decoding.
</p>
<p class=parameters>
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
<p class="parameters">
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is the empty string
and <tt>B</tt> returns whatever couldn't be decoded.
and <tt>B</tt> returns whatever couldn't be decoded.
</p>
<p class=note>
<p class="note">
Note: The simplest use of this function is to decode a string from it's
Base64 transfer content encoding.
Base64 transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p>
<pre class=example>
<pre class="example">
print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
--&gt; diego:password
</pre>
<!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unqp">
<p class="name" id="unqp">
A, B = mime.<b>unqp(</b>C [, D]<b>)</b>
</p>
<p class=description>
<p class="description">
Low-level filter to remove the Quoted-Printable transfer content encoding
from data.
from data.
</p>
<p class=parameters>
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with
the encoding of the remaining bytes of <tt>C</tt>.
<p class="parameters">
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with
the encoding of the remaining bytes of <tt>C</tt>.
</p>
<p class=note>
<p class="note">
Note: The simplest use of this function is to decode a string from it's
Quoted-Printable transfer content encoding.
Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p>
<pre class=example>
<pre class="example">
print((mime.qp("ma=E7=E3=")))
--&gt; maçã
--&gt; ma<EFBFBD><EFBFBD>
</pre>
<!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrp">
<p class="name" id="wrp">
A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b>
</p>
<p class=description>
Low-level filter to break text into lines with CRLF marker.
Text is assumed to be in the <a href=#normalize><tt>normalize</tt></a> form.
<p class="description">
Low-level filter to break text into lines with CRLF marker.
Text is assumed to be in the <a href="#normalize"><tt>normalize</tt></a> form.
</p>
<p class=parameters>
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
<p class="parameters">
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
</p>
<p class=note>
Note: This function only breaks lines that are bigger than
<p class="note">
Note: This function only breaks lines that are bigger than
<tt>length</tt> bytes. The resulting line length does not include the CRLF
marker.
</p>
@ -453,12 +454,12 @@ marker.
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -466,7 +467,7 @@ marker.
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:44 EDT 2006
Fri Mar 4 15:19:17 BRT 2016
</small>
</p>
</center>

View File

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

View File

@ -1,11 +1,11 @@
<!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">
<html>
<head>
<meta name="description" content="LuaSocket: Index to reference manual">
<meta name="keywords" content="Lua, LuaSocket, Index, Manual, Network, Library,
Support, Manual">
Support, Manual">
<title>LuaSocket: Index to reference manual</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
@ -14,22 +14,22 @@ Support, Manual">
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -42,9 +42,10 @@ Support, Manual">
<blockquote>
<a href="dns.html">DNS (in socket)</a>
<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#gethostname">gethostname</a>.
<a href="dns.html#toip">toip</a>.
</blockquote>
</blockquote>
@ -91,14 +92,15 @@ Support, Manual">
<a href="ltn12.html#sink.table">table</a>.
</blockquote>
<blockquote>
<a href="ltn12.html#source">source</a>:
<a href="ltn12.html#source">source</a>:
<a href="ltn12.html#source.cat">cat</a>,
<a href="ltn12.html#source.chain">chain</a>,
<a href="ltn12.html#source.empty">empty</a>,
<a href="ltn12.html#source.error">error</a>,
<a href="ltn12.html#source.file">file</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>
@ -108,9 +110,9 @@ Support, Manual">
<a href="mime.html">MIME</a>
<blockquote>
<a href="mime.html#high">high-level</a>:
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#decode">decode</a>,
<a href="mime.html#encode">encode</a>,
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#stuff">stuff</a>,
<a href="mime.html#wrap">wrap</a>.
</blockquote>
@ -120,10 +122,10 @@ Support, Manual">
<a href="mime.html#dot">dot</a>,
<a href="mime.html#eol">eol</a>,
<a href="mime.html#qp">qp</a>,
<a href="mime.html#wrp">wrp</a>,
<a href="mime.html#qpwrp">qpwrp</a>.
<a href="mime.html#qpwrp">qpwrp</a>,
<a href="mime.html#unb64">unb64</a>,
<a href="mime.html#unqp">unqp</a>,
<a href="mime.html#wrp">wrp</a>.
</blockquote>
</blockquote>
@ -142,19 +144,31 @@ Support, Manual">
<blockquote>
<a href="socket.html">Socket</a>
<blockquote>
<a href="socket.html#bind">bind</a>,
<a href="socket.html#connect">connect</a>,
<a href="socket.html#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="dns.html#dns">dns</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#protect">protect</a>,
<a href="socket.html#select">select</a>,
<a href="socket.html#sink">sink</a>,
<a href="socket.html#skip">skip</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="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="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>.
</blockquote>
</blockquote>
@ -168,11 +182,17 @@ Support, Manual">
<a href="tcp.html#bind">bind</a>,
<a href="tcp.html#close">close</a>,
<a href="tcp.html#connect">connect</a>,
<a href="tcp.html#dirty">dirty</a>,
<a href="tcp.html#getfd">getfd</a>,
<a href="tcp.html#getoption">getoption</a>,
<a href="tcp.html#getpeername">getpeername</a>,
<a href="tcp.html#getsockname">getsockname</a>,
<a href="tcp.html#getstats">getstats</a>,
<a href="tcp.html#gettimeout">gettimeout</a>,
<a href="tcp.html#listen">listen</a>,
<a href="tcp.html#receive">receive</a>,
<a href="tcp.html#send">send</a>,
<a href="tcp.html#setfd">setfd</a>,
<a href="tcp.html#setoption">setoption</a>,
<a href="tcp.html#setstats">setstats</a>,
<a href="tcp.html#settimeout">settimeout</a>,
@ -186,8 +206,10 @@ Support, Manual">
<a href="udp.html">UDP (in socket)</a>
<blockquote>
<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#getsockname">getsockname</a>,
<a href="udp.html#gettimeout">gettimeout</a>,
<a href="udp.html#receive">receive</a>,
<a href="udp.html#receivefrom">receivefrom</a>,
<a href="udp.html#send">send</a>,
@ -216,12 +238,12 @@ Support, Manual">
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -1,11 +1,11 @@
<!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">
<html>
<head>
<meta name="description" content="LuaSocket: SMTP support">
<meta name="keywords" content="Lua, LuaSocket, SMTP, E-Mail, MIME, Multipart,
Library, Support">
Library, Support">
<title>LuaSocket: SMTP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
@ -14,22 +14,22 @@ Library, Support">
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -37,37 +37,36 @@ Library, Support">
<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=smtp>SMTP</h2>
<h2 id="smtp">SMTP</h2>
<p> The <tt>smtp</tt> namespace provides functionality to send e-mail
messages. The high-level API consists of two functions: one to
messages. The high-level API consists of two functions: one to
define an e-mail message, and another to actually send the message.
Although almost all users will find that these functions provide more than
enough functionality, the underlying implementation allows for even more
control (if you bother to read the code).
control (if you bother to read the code).
</p>
<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
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.
Multipart messages (those that contain attachments) are part
of the MIME standard, but described mainly
in <a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">RFC
2046</a>
in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>.</p>
<p> In the description below, good understanding of <a
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
sources and sinks</a> and the <a href=mime.html>MIME</a> module is
assumed. In fact, the SMTP module was the main reason for their
sources and sinks</a> and the <a href="mime.html">MIME</a> module is
assumed. In fact, the SMTP module was the main reason for their
creation. </p>
<p>
<p>
To obtain the <tt>smtp</tt> namespace, run:
</p>
<pre class=example>
<pre class="example">
-- loads the SMTP module and everything it requires
local smtp = require("socket.smtp")
</pre>
@ -91,202 +90,42 @@ headers = {<br>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names.
Field names are case insensitive (as specified by the standard) and all
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.
</p>
<p class=note>
<p class="note">
Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table.
in representing them in a Lua table.
</p>
<p>
The following constants can be set to control the default behavior of
the SMTP module:
the SMTP module:
</p>
<ul>
<li> <tt>DOMAIN</tt>: domain used to greet the server;
<li> <tt>PORT</tt>: default port used for the connection;
<li> <tt>SERVER</tt>: default server used for the connection;
<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations;
<li> <tt>ZONE</tt>: default time zone.
<li> <tt>DOMAIN</tt>: domain used to greet the server;</li>
<li> <tt>PORT</tt>: default port used for the connection;</li>
<li> <tt>SERVER</tt>: default server used for the connection;</li>
<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations;</li>
<li> <tt>ZONE</tt>: default time zone.</li>
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=message>
<p class="name" id="message">
smtp.<b>message(</b>mesgt<b>)</b>
</p>
<p class=description>
<p class="description">
Returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
</p>
<p class=parameters>
<p class="parameters">
The only parameter of the function is a table describing the message.
<tt>Mesgt</tt> has the following form (notice the recursive structure):
</p>
@ -296,7 +135,7 @@ The only parameter of the function is a table describing the message.
<tr><td><tt>
mesgt = {<br>
&nbsp;&nbsp;headers = <i>header-table</i>,<br>
&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or
&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or
<i>multipart-mesgt</i><br>
}<br>
&nbsp;<br>
@ -312,36 +151,36 @@ multipart-mesgt = {<br>
</table>
</blockquote>
<p class=parameters>
<p class="parameters">
For a simple message, all that is needed is a set of <tt>headers</tt>
and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
or as a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
or as a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source. For multipart messages, the body is a table that
recursively defines each part as an independent message, plus an optional
<tt>preamble</tt> and <tt>epilogue</tt>.
</p>
<p class=return>
The function returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<p class="return">
The function returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that produces the
message contents as defined by <tt>mesgt</tt>, chunk by chunk.
message contents as defined by <tt>mesgt</tt>, chunk by chunk.
Hopefully, the following
example will make things clear. When in doubt, refer to the appropriate RFC
as listed in the introduction. </p>
<pre class=example>
<pre class="example">
-- load the smtp support and its friends
local smtp = require("socket.smtp")
local mime = require("mime")
local ltn12 = require("ltn12")
-- creates a source to send a message with two parts. The first part is
-- creates a source to send a message with two parts. The first part is
-- plain text, the second part is a PNG image, encoded as base64.
source = smtp.message{
headers = {
-- Remember that headers are *ignored* by smtp.send.
-- Remember that headers are *ignored* by smtp.send.
from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
to = "Fulano da Silva &lt;fulano@example.com&gt;",
subject = "Here is a message with attachments"
@ -352,20 +191,20 @@ source = smtp.message{
"Preamble will probably appear even in a MIME enabled client.",
-- first part: no headers means plain text, us-ascii.
-- The mime.eol low-level filter normalizes end-of-line markers.
[1] = {
[1] = {
body = mime.eol(0, [[
Lines in a message body should always end with CRLF.
The smtp module will *NOT* perform translation. However, the
Lines in a message body should always end with CRLF.
The smtp module will *NOT* perform translation. However, the
send function *DOES* perform SMTP stuffing, whereas the message
function does *NOT*.
]])
},
-- second part: headers describe content to be a png image,
-- second part: headers describe content to be a png image,
-- sent under the base64 transfer content encoding.
-- notice that nothing happens until the message is actually sent.
-- small chunks are loaded into memory right before transmission and
-- notice that nothing happens until the message is actually sent.
-- small chunks are loaded into memory right before transmission and
-- translation happens on the fly.
[2] = {
[2] = {
headers = {
["content-type"] = 'image/png; name="image.png"',
["content-disposition"] = 'attachment; filename="image.png"',
@ -392,14 +231,177 @@ r, e = smtp.send{
}
</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>
<li> <tt>server</tt>: Server to connect to. Defaults to "localhost";</li>
<li> <tt>port</tt>: Port to connect to. Defaults to 25;</li>
<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
local machine host name;</li>
<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>
<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.</li>
</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>
<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>
<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.</li>
</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>
<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>
<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>
<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>
<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!</li>
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

481
docs/socket.html Normal file
View File

@ -0,0 +1,481 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The core namespace">
<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support">
<title>LuaSocket: The socket namespace</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align="center"><a href="https://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="socket">The socket namespace</h2>
<p>
The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
</p>
<p>
To obtain the <tt>socket</tt> namespace, run:
</p>
<pre class="example">
-- loads the socket module
local socket = require("socket")
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="bind">
socket.<b>bind(</b>address, port [, backlog]<b>)</b>
</p>
<p class="description">
This function is a shortcut that creates and returns a TCP server object
bound to a local <tt>address</tt> and <tt>port</tt>, ready to
accept client connections. Optionally,
user can also specify the <tt>backlog</tt> argument to the
<a href="tcp.html#listen"><tt>listen</tt></a> method (defaults to 32).
</p>
<p class="note">
Note: The server object returned will have the option "<tt>reuseaddr</tt>"
set to <tt><b>true</b></tt>.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="connect">
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p>
<p class="description">
This function is a shortcut that creates and returns a TCP client object
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
(<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>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="debug">
socket.<b>_DEBUG</b>
</p>
<p class="description">
This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support.
</p>
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="datagramsize">
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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="newtry">
socket.<b>newtry(</b>finalizer<b>)</b>
</p>
<p class="description">
Creates and returns a <em>clean</em>
<a href="#try"><tt>try</tt></a>
function that allows for cleanup before the exception
is raised.
</p>
<p class="parameters">
<tt>Finalizer</tt> is a function that will be called before
<tt>try</tt> throws the exception.
</p>
<p class="return">
The function returns your customized <tt>try</tt> function.
</p>
<p class="note">
Note: This idea saved a <em>lot</em> of work with the
implementation of protocols in LuaSocket:
</p>
<pre class="example">
foo = socket.protect(function()
-- connect somewhere
local c = socket.try(socket.connect("somewhere", 42))
-- create a try function that closes 'c' on error
local try = socket.newtry(function() c:close() end)
-- do everything reassured c will be closed
try(c:send("hello there?\r\n"))
local answer = try(c:receive())
...
try(c:send("good bye\r\n"))
c:close()
end)
</pre>
<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="protect">
socket.<b>protect(</b>func<b>)</b>
</p>
<p class="description">
Converts a function that throws exceptions into a safe function. This
function only catches exceptions thrown by the <a href="#try"><tt>try</tt></a>
and <a href="#newtry"><tt>newtry</tt></a> functions. It does not catch normal
Lua errors.
</p>
<p class="parameters">
<tt>Func</tt> is a function that calls
<a href="#try"><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>)
to throw exceptions.
</p>
<p class="return">
Returns an equivalent function that instead of throwing exceptions in case of
a failed <a href="#try"><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
followed by an error message.
</p>
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="select">
socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b>
</p>
<p class="description">
Waits for a number of sockets to change status.
</p>
<p class="parameters">
<tt>Recvt</tt> is an array with the sockets to test for characters
available for reading. Sockets in the <tt>sendt</tt> array are watched to
see if it is OK to immediately write on them. <tt>Timeout</tt> is the
maximum amount of time (in seconds) to wait for a change in status. A
<tt><b>nil</b></tt>, negative or omitted <tt>timeout</tt> value allows the
function to block indefinitely. <tt>Recvt</tt> and <tt>sendt</tt> can also
be empty tables or <tt><b>nil</b></tt>. Non-socket values (or values with
non-numeric indices) in the arrays will be silently ignored.
</p>
<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.
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
doubly keyed both by integers and also by the sockets
themselves, to simplify the test if a specific socket has
changed status.
</p>
<p class="note">
<b>Note:</b> <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <a href="#setsize">
<tt>socket._SETSIZE</tt></a>. 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">
<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
writable even though the socket is <em>not</em> ready for sending.
</p>
<p class="note">
<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee
<a href="tcp.html#accept"><tt>accept</tt></a> will return immediately.
Use the <a href="tcp.html#settimeout"><tt>settimeout</tt></a>
method or <tt>accept</tt> might block forever.
</p>
<p class="note">
<b>Yet another note</b>: If you close a socket and pass
it to <tt>select</tt>, it will be ignored.
</p>
<p class="note">
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
</p>
<!-- 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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="sink">
socket.<b>sink(</b>mode, socket<b>)</b>
</p>
<p class="description">
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink from a stream socket object.
</p>
<p class="parameters">
<tt>Mode</tt> defines the behavior of the sink. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: sends data through socket after applying the
<em>chunked transfer coding</em>, closing the socket when done;</li>
<li> <tt>"close-when-done"</tt>: sends all received data through the
socket, closing the socket when done;</li>
<li> <tt>"keep-open"</tt>: sends all received data through the
socket, leaving it open when done.</li>
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to send the data.
</p>
<p class="return">
The function returns a sink with the appropriate behavior.
</p>
<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="skip">
socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class="description">
Drops a number of arguments and returns the remaining.
</p>
<p class="parameters">
<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to
<tt>ret<sub>N</sub></tt> are the arguments.
</p>
<p class="return">
The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
</p>
<p class="note">
Note: This function is useful to avoid creation of dummy variables:
</p>
<pre class="example">
-- get the status code and separator from SMTP server reply
local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
</pre>
<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="sleep">
socket.<b>sleep(</b>time<b>)</b>
</p>
<p class="description">
Freezes the program execution during a given amount of time.
</p>
<p class="parameters">
<tt>Time</tt> is the number of seconds to sleep for. If
<tt>time</tt> is negative, the function returns immediately.
</p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="source">
socket.<b>source(</b>mode, socket [, length]<b>)</b>
</p>
<p class="description">
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source from a stream socket object.
</p>
<p class="parameters">
<tt>Mode</tt> defines the behavior of the source. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: receives data from socket and removes the
<em>chunked transfer coding</em> before returning the data;</li>
<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the
socket. This mode requires the extra argument <tt>length</tt>;</li>
<li> <tt>"until-closed"</tt>: receives data from a socket until the other
side closes the connection.</li>
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to receive the data.
</p>
<p class="return">
The function returns a source with the appropriate behavior.
</p>
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socketinvalid">
socket.<b>_SOCKETINVALID</b>
</p>
<p class="description">
The OS value for an invalid socket. This can be used with <a href="tcp.html#getfd">
<tt>tcp:getfd</tt></a> and <a href="tcp.html#setfd"><tt>tcp:setfd</tt></a> methods.
</p>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="try">
socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class="description">
Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
by a <a href="#protect"><tt>protect</tt></a>ed function only.
</p>
<p class="parameters">
<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary
arguments, but are usually the return values of a function call
nested with <tt>try</tt>.
</p>
<p class="return">
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> 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>
<pre class="example">
-- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect("localhost", 80))
</pre>
<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="version">
socket.<b>_VERSION</b>
</p>
<p class="description">
This constant has a string describing the current LuaSocket version.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="footer">
<hr>
<center>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:54 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

738
docs/tcp.html Normal file
View File

@ -0,0 +1,738 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The TCP/IP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<title>LuaSocket: TCP/IP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="tcp">TCP</h2>
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="accept">
server:<b>accept()</b>
</p>
<p class="description">
Waits for a remote connection on the server
object and returns a client object representing that connection.
</p>
<p class="return">
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>
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.
</p>
<p class="note">
Note: calling <a href="socket.html#select"><tt>socket.select</tt></a>
with a server object in
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
href="#settimeout"><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up.
</p>
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="bind">
master:<b>bind(</b>address, port<b>)</b>
</p>
<p class="description">
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host.
</p>
<p class="parameters">
<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).
If <tt>address</tt>
is '<tt>*</tt>', the system binds to all local interfaces
using the <tt>INADDR_ANY</tt> constant or
<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port.
</p>
<p class="return">
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<p class="note">
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.
</p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="close">
master:<b>close()</b><br>
client:<b>close()</b><br>
server:<b>close()</b>
</p>
<p class="description">
Closes a TCP object. The internal socket used by the object is closed
and the local address to which the object was
bound is made available to other applications. No further operations
(except for further calls to the <tt>close</tt> method) are allowed on
a closed socket.
</p>
<p class="note">
Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor,
which are limited system resources. Garbage-collected objects are
automatically closed before destruction, though.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="connect">
master:<b>connect(</b>address, port<b>)</b>
</p>
<p class="description">
Attempts to connect a master object to a remote host, transforming it into a
client object.
Client objects support methods
<a href="#send"><tt>send</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#getpeername"><tt>getpeername</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
and <a href="#close"><tt>close</tt></a>.
</p>
<p class="parameters">
<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).
</p>
<p class="return">
In case of error, the method returns <b><tt>nil</tt></b> followed by a string
describing the error. In case of success, the method returns 1.
</p>
<p class="note">
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.
</p>
<p class="note">
Note: Starting with LuaSocket 2.0,
the <a href="#settimeout"><tt>settimeout</tt></a>
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
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
established.
</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 value
will be -1. For an invalid socket it will be <a href="socket.html#socketinvalid">
<tt>_SOCKETINVALID</tt></a>.
</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(option)</b><br>
server:<b>getoption(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.</p>
<ul>
<li> '<tt>keepalive</tt>'</li>
<li> '<tt>linger</tt>'</li>
<li> '<tt>reuseaddr</tt>'</li>
<li> '<tt>tcp-nodelay</tt>'</li>
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getpeername">
client:<b>getpeername()</b>
</p>
<p class="description">
Returns information about the remote side of a connected client object.
</p>
<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 class="note">
Note: It makes no sense to call this method on server objects.
</p>
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getsockname">
master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br>
server:<b>getsockname()</b>
</p>
<p class="description">
Returns the local address information associated to the object.
</p>
<p class="return">
The method returns a string with local IP address, a number with
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>
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getstats">
master:<b>getstats()</b><br>
client:<b>getstats()</b><br>
server:<b>getstats()</b><br>
</p>
<p class="description">
Returns accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class="return">
The method returns the number of bytes received, the number of bytes sent,
and the age of the socket object in seconds.
</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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="listen">
master:<b>listen(</b>backlog<b>)</b>
</p>
<p class="description">
Specifies the socket is willing to receive connections, transforming the
object into a server object. Server objects support the
<a href="#accept"><tt>accept</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
and <a href="#close"><tt>close</tt></a> methods.
</p>
<p class="parameters">
The parameter <tt>backlog</tt> specifies the number of client
connections that can
be queued waiting for service. If the queue is full and another client
attempts connection, the connection is refused.
</p>
<p class="return">
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p>
<p class="description">
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.
</p>
<p class="parameters">
<tt>Pattern</tt> can be any of the following:
</p>
<ul>
<li> '<tt>*a</tt>': reads from the socket until the connection is
closed. No end-of-line translation is performed;</li>
<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
CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. In fact, <em>all</em> CR characters are
ignored by the pattern. This is the default pattern;</li>
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket.</li>
</ul>
<p class="parameters">
<tt>Prefix</tt> is an optional string to be concatenated to the beginning
of any received data before return.
</p>
<p class="return">
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, 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
'<tt>timeout</tt>' in case there was a timeout during the operation.
</p>
<p class="note">
<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
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
functions should return <tt><b>nil</b></tt> on error. Thus it was changed
too.
</p>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b>
</p>
<p class="description">
Sends <tt>data</tt> through client object.
</p>
<p class="parameters">
<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>string.sub</tt> Lua function to allow the selection of a
substring to be sent.
</p>
<p class="return">
If successful, the method returns the index of the last byte
within <tt>[i, j]</tt> that has been sent. Notice that, if
<tt>i</tt> is 1 or absent, this is effectively the total
number of bytes sent. In case of error, the method returns
<b><tt>nil</tt></b>, followed by an error message, followed
by the index of the last byte within <tt>[i, j]</tt> that
has been sent. You might want to try again from the byte
following that. The error message can be '<tt>closed</tt>'
in case the connection was closed before the transmission
was completed or the string '<tt>timeout</tt>' in case
there was a timeout during the operation.
</p>
<p class="note">
Note: Output is <em>not</em> buffered. For small strings,
it is always better to concatenate them in Lua
(with the '<tt>..</tt>' operator) and send the result in one call
instead of calling the method several times.
</p>
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setoption">
client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class="description">
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
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>keepalive</tt>': Setting this option to <tt>true</tt> enables
the periodic transmission of messages on a connected socket. Should the
connected party fail to respond to these messages, the connection is
considered broken and processes using the socket are notified;</li>
<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
boolean entry '<tt>on</tt>' and a numeric entry for the time interval
'<tt>timeout</tt>' in seconds. If the '<tt>on</tt>' field is set to
<tt>true</tt>, the system will block the process on the close attempt until
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
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
zero;</li>
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
used in validating addresses supplied in a call to
<a href="#bind"><tt>bind</tt></a> should allow reuse of local addresses;</li>
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
disables the Nagle's algorithm for the connection;</li>
<li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!!</li>
<li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!!</li>
<li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!!</li>
<li> '<tt>tcp-defer-accept</tt>': value for <tt>TCP_DEFER_ACCEPT</tt> Linux only!!</li>
<li> '<tt>tcp-fastopen</tt>': value for <tt>TCP_FASTOPEN</tt> Linux only!!</li>
<li> '<tt>tcp-fastopen-connect</tt>': value for <tt>TCP_FASTOPEN_CONNECT</tt> Linux only!!</li>
<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.</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>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setstats">
master:<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>
</p>
<p class="description">
Resets accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class="parameters">
<tt>Received</tt> is a number with the new number of bytes received.
<tt>Sent</tt> is a number with the new number of bytes sent.
<tt>Age</tt> is the new age in seconds.
</p>
<p class="return">
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="settimeout">
master:<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>
</p>
<p class="description">
Changes the timeout values for the object. By default,
all I/O operations are blocking. That is, any call to the methods
<a href="#send"><tt>send</tt></a>,
<a href="#receive"><tt>receive</tt></a>, and
<a href="#accept"><tt>accept</tt></a>
will block indefinitely, until the operation completes. The
<tt>settimeout</tt> method defines a limit on the amount of time the
I/O methods can block. When a timeout is set and the specified amount of
time has elapsed, the affected methods give up and fail with an error code.
</p>
<p class="parameters">
The amount of time to wait is specified as the
<tt>value</tt> parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning:
</p>
<ul>
<li> '<tt>b</tt>': <em>block</em> timeout. Specifies the upper limit on
the amount of time LuaSocket can be blocked by the operating system
while waiting for completion of any single I/O operation. This is the
default mode;</li>
<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
a call.</li>
</ul>
<p class="parameters">
The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block
indefinitely. Negative timeout values have the same effect.
</p>
<p class="note">
Note: although timeout values have millisecond precision in LuaSocket,
large blocks can cause I/O functions not to respect timeout values due
to the time the library takes to transfer blocks to and from the OS
and to and from the Lua interpreter. Also, function that accept host names
and perform automatic name resolution might be blocked by the resolver for
longer than the specified timeout value.
</p>
<p class="note">
Note: The old <tt>timeout</tt> method is deprecated. The name has been
changed for sake of uniformity, since all other method names already
contained verbs making their imperative nature obvious.
</p>
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="shutdown">
client:<b>shutdown(</b>mode<b>)</b><br>
</p>
<p class="description">
Shuts down part of a full-duplex connection.
</p>
<p class="parameters">
Mode tells which way of the connection should be shut down and can
take the value:
<ul>
<li>"<tt>both</tt>": disallow further sends and receives on the object.
This is the default mode;</li>
<li>"<tt>send</tt>": disallow further sends on the object;</li>
<li>"<tt>receive</tt>": disallow further receives on the object.</li>
</ul>
</p>
<p class="return">
This function returns 1.
</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.
To set it as invalid use <a href="socket.html#socketinvalid"><tt>_SOCKETINVALID</tt></a>.
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class="footer">
<hr>
<center>
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:57 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View File

@ -4,7 +4,7 @@
<head>
<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>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
@ -13,22 +13,22 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<div class="header">
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
<tr><td align="center"><a href="http://www.lua.org">
<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
</center>
<hr>
@ -37,34 +37,7 @@
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<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>
<h2 id="udp">UDP</h2>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -89,6 +62,40 @@ Garbage-collected objects are automatically closed before
destruction, though.
</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>
<li> '<tt>broadcast</tt>'</li>
<li> '<tt>reuseaddr</tt>'</li>
<li> '<tt>reuseport</tt>'</li>
<li> '<tt>ip-multicast-loop</tt>'</li>
<li> '<tt>ipv6-v6only</tt>'</li>
<li> '<tt>ip-multicast-if</tt>'</li>
<li> '<tt>ip-multicast-ttl</tt>'</li>
<li> '<tt>ip-add-membership</tt>'</li>
<li> '<tt>ip-drop-membership</tt>'</li>
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getpeername">
@ -100,8 +107,12 @@ Retrieves information about the peer
associated with a connected UDP object.
</p>
<p class="return">
Returns the IP address and port number of the peer.
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 class="note">
@ -119,10 +130,12 @@ unconnected:<b>getsockname()</b>
Returns the local address information associated to the object.
</p>
<p class="return">
The method returns a string with local IP
address and a number with the port. In case of error, the method
returns <b><tt>nil</tt></b>.
The method returns a string with local IP address, a number with
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 class="note">
@ -133,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the
wild-card address).
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<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,
the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the
available bytes are returned. If <tt>size</tt> is omitted, the
maximum datagram size is used (which is currently limited by the
implementation to 8192 bytes).
available bytes are returned.
If <tt>size</tt> is omitted, the
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 class="return">
@ -171,7 +199,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
</p>
<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
address and port as extra return values (and is therefore slightly less
efficient).
@ -188,7 +216,7 @@ Sends a datagram to the UDP peer of a connected object.
</p>
<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.
However datagrams larger than the link layer packet size will be
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">
<tt>Datagram</tt> is a string with the
datagram contents.
datagram contents.
The maximum datagram size for UDP is 64K minus IP layer overhead.
However datagrams larger than the link layer packet size will be
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.
<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).
</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>
<li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket.
Receives a boolean value;</li>
<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>
<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>
<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>
<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>
<li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams
are sent.
Receives an IP address;</li>
<li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing
multicast datagrams.
Receives a number;</li>
<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>
<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.</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>
<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setpeername">
@ -257,9 +354,9 @@ object or vice versa.
For connected objects, outgoing datagrams
will be sent to the specified peer, and datagrams received from
other peers will be discarded by the OS. Connected UDP objects must
use the <a href="#send"><tt>send</tt></a> and
<a href="#receive"><tt>receive</tt></a> methods instead of
<a href="#sendto"><tt>sendto</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="#sendto"><tt>sendto</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>.
</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.
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setsockname">
@ -317,40 +423,6 @@ system or explicitly by <tt>setsockname</tt>, it cannot be
changed.
</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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="settimeout">
@ -359,14 +431,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
</p>
<p class="description">
Changes the timeout values for the object. By default, the
<a href="#receive"><tt>receive</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>
Changes the timeout values for the object. By default, the
<a href="#receive"><tt>receive</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>
operations are blocking. That is, any call to the methods will block
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
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 class="parameters">
@ -391,17 +463,125 @@ all other method names already contained verbs making their
imperative nature obvious.
</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.udp4">
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<p class="bar">
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
<a href="reference.html">reference</a>
</p>
<p>
<small>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -36,14 +36,13 @@
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=url>URL</h2>
<h2 id="url">URL</h2>
<p>
The <tt>url</tt> namespace provides functions to parse, protect,
and build URLs, as well as functions to compose absolute URLs
from base and relative URLs, according to
<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>.
</p>
<p>
@ -70,7 +69,7 @@ An URL is defined by the following grammar:
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=absolute>
<p class=name id="absolute">
url.<b>absolute(</b>base, relative<b>)</b>
</p>
@ -91,7 +90,7 @@ The function returns a string with the absolute URL.
<p class=note>
Note: The rules that
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.
</p>
@ -126,7 +125,7 @@ g;x?y#s = http://a/b/c/g;x?y#s
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build>
<p class=name id="build">
url.<b>build(</b>parsed_url<b>)</b>
</p>
@ -147,7 +146,7 @@ The function returns a string with the built URL.
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build_path>
<p class=name id="build_path">
url.<b>build_path(</b>segments, unsafe<b>)</b>
</p>
@ -201,7 +200,7 @@ code = url.escape("/#?;")
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse>
<p class=name id="parse">
url.<b>parse(</b>url, default<b>)</b>
</p>
@ -266,7 +265,7 @@ parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse_path>
<p class=name id="parse_path">
url.<b>parse_path(</b>path<b>)</b>
</p>
@ -310,8 +309,8 @@ The function returns the decoded string.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

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

View File

@ -3,7 +3,6 @@
-- non-blocking I/O via the dispatcher module.
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $$
-----------------------------------------------------------------------------
local url = require("socket.url")
local dispatch = require("dispatch")
@ -12,7 +11,7 @@ dispatch.TIMEOUT = 10
-- make sure the user knows how to invoke us
arg = arg or {}
if table.getn(arg) < 1 then
if #arg < 1 then
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
exit()
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
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -44,48 +43,48 @@ function metat.__index:check(ok)
end
function metat.__index:getdef()
local line = socket.try(self.tp:receive())
local def = {}
while line ~= "." do
table.insert(def, line)
line = socket.try(self.tp:receive())
end
return table.concat(def, "\n")
local line = socket.try(self.tp:receive())
local def = {}
while line ~= "." do
table.insert(def, line)
line = socket.try(self.tp:receive())
end
return table.concat(def, "\n")
end
function metat.__index:define(database, word)
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 defs = {}
for i = 1, count do
self:check(151)
table.insert(defs, self:getdef())
end
self:check(250)
local defs = {}
for i = 1, count do
self:check(151)
table.insert(defs, self:getdef())
end
self:check(250)
return defs
end
function metat.__index:match(database, strat, word)
database = database 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)
local mat = {}
local line = socket.try(self.tp:receive())
local mat = {}
local line = socket.try(self.tp:receive())
while line ~= '.' do
database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
if not mat[database] then mat[database] = {} end
table.insert(mat[database], word)
line = socket.try(self.tp:receive())
end
self:check(250)
line = socket.try(self.tp:receive())
end
self:check(250)
return mat
end
function metat.__index:quit()
self.tp:command("QUIT")
return self:check(221)
self.tp:command("QUIT")
return self:check(221)
end
function metat.__index:close()

View File

@ -2,10 +2,10 @@
-- A hacked dispatcher module
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $$
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local string = require("string")
local socket = require("socket")
local coroutine = require("coroutine")
module("dispatch")
@ -44,26 +44,32 @@ end
-----------------------------------------------------------------------------
-- 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
-- loading our hack
function socket.protect(f)
return function(...)
local co = coroutine.create(f)
while true do
local results = {coroutine.resume(co, base.unpack(arg))}
local status = table.remove(results, 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))}
if string.sub(base._VERSION, -3) == "5.1" then
local function _protect(co, status, ...)
if not status then
local msg = ...
if base.type(msg) == 'table' then
return nil, msg[1]
else
return base.unpack(results)
base.error(msg, 0)
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
@ -77,7 +83,7 @@ local function newset()
insert = function(set, value)
if not reverse[value] then
table.insert(set, value)
reverse[value] = table.getn(set)
reverse[value] = #set
end
end,
remove = function(set, value)
@ -105,8 +111,7 @@ local function cowrap(dispatcher, tcp, error)
-- don't override explicitly.
local metat = { __index = function(table, key)
table[key] = function(...)
arg[1] = tcp
return tcp[key](base.unpack(arg))
return tcp[key](tcp,select(2,...))
end
return table[key]
end}

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@
-- LuaSocket toolkit.
-- Author: David Burgess
-- Modified by Diego Nehab, but David is in charge
-- RCS ID: $Id$
-----------------------------------------------------------------------------
--[[
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 _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
ctlfn = string.sub(ctlfn or file,1,131)
local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost,
local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost,
class,
option.job or "LuaSocket",
option.job or "LuaSocket",
user,
fmt, lpfile,
lpfile,

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
local input = source.chain(
source.file(io.open("input.bin", "rb")),
source.file(io.open("input.bin", "rb")),
encode("base64"))
local output = sink.chain(
wrap(76),
wrap(76),
sink.file(io.open("output.b64", "w")))
pump.all(input, output)

View File

@ -7,7 +7,7 @@ local function chainpair(f1, f2)
end
function filter.chain(...)
local f = select(1, ...)
local f = select(1, ...)
for i = 2, select('#', ...) do
f = chainpair(f, select(i, ...))
end

View File

@ -1,4 +1,4 @@
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
wrap("quoted-printable"))
local input = source.chain(source.file(io.stdin), qp)
local output = sink.file(io.stdout)

View File

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

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
function filter.chain(...)
local arg = {...}
local f = arg[1]
for i = 2, table.getn(arg) do
for i = 2, #arg do
f = chain2(f, arg[i])
end
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.
{{{
function source.cat(...)
local arg = {...}
local co = coroutine.create(function()
local i = 1
while i <= table.getn(arg) do
while i <= #arg do
local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk)
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:
{{{
local function pack(ok, ...)
return ok, arg
return ok, {...}
end
function protect(f)
return function(...)
local ok, ret = pack(pcall(f, unpack(arg)))
local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret)
else return nil, ret[1] end
end
@ -157,7 +157,7 @@ function newtry(f)
if f then f() end
error(arg[2], 0)
else
return unpack(arg)
return ...
end
end
end

135
luasocket-scm-3.rockspec Normal file
View File

@ -0,0 +1,135 @@
package = "LuaSocket"
version = "scm-3"
source = {
url = "git+https://github.com/lunarmodules/luasocket.git",
branch = "master"
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library composed of two parts: a set of C
modules that provide support for the TCP and UDP transport layers, and a
set of Lua modules that provide functions commonly needed by applications
that deal with the Internet.
]],
homepage = "https://github.com/lunarmodules/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" }
modules["socket.core"].libdirs = {}
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 = {
"docs"
, "samples"
, "etc"
, "test" }
}

View File

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

90
makefile Normal file → Executable file
View File

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

View File

@ -1,10 +1,11 @@
#--------------------------------------------------------------------------
# Distribution makefile
#--------------------------------------------------------------------------
DIST = luasocket-2.0.2
DIST = luasocket-3.0.0
TEST = \
test/README \
test/hello.lua \
test/testclnt.lua \
test/testsrvr.lua \
test/testsupport.lua
@ -15,6 +16,8 @@ SAMPLES = \
samples/daytimeclnt.lua \
samples/echoclnt.lua \
samples/echosrvr.lua \
samples/mclisten.lua \
samples/mcsend.lua \
samples/listener.lua \
samples/lpr.lua \
samples/talker.lua \
@ -62,6 +65,7 @@ SRC = \
src/udp.c \
src/udp.h \
src/unix.c \
src/serial.c \
src/unix.h \
src/usocket.c \
src/usocket.h \
@ -73,39 +77,44 @@ SRC = \
src/mime.lua \
src/smtp.lua \
src/socket.lua \
src/headers.lua \
src/tp.lua \
src/url.lua
MAKE = \
makefile \
config \
luasocket.sln \
socket.vcproj \
mime.vcproj
luasocket-scm-0.rockspec \
Lua51.props \
Lua52.props \
socket.vcxproj.filters \
mime.vcxproj.filters \
socket.vcxproj \
mime.vcxproj
DOC = \
doc/dns.html \
doc/ftp.html \
doc/home.html \
doc/http.html \
doc/installation.html \
doc/introduction.html \
doc/ltn12.html \
doc/luasocket.png \
doc/mime.html \
doc/reference.css \
doc/reference.html \
doc/smtp.html \
doc/socket.html \
doc/tcp.html \
doc/udp.html \
doc/url.html
DOCS = \
docs/dns.html \
docs/ftp.html \
docs/index.html \
docs/http.html \
docs/installation.html \
docs/introduction.html \
docs/ltn12.html \
docs/luasocket.png \
docs/mime.html \
docs/reference.css \
docs/reference.html \
docs/smtp.html \
docs/socket.html \
docs/tcp.html \
docs/udp.html \
docs/url.html
dist:
mkdir -p $(DIST)
cp -vf NEW $(DIST)
cp -vf CHANGELOG.md $(DIST)
cp -vf LICENSE $(DIST)
cp -vf README $(DIST)
cp -vf README.md $(DIST)
cp -vf $(MAKE) $(DIST)
mkdir -p $(DIST)/etc
@ -114,8 +123,8 @@ dist:
mkdir -p $(DIST)/src
cp -vf $(SRC) $(DIST)/src
mkdir -p $(DIST)/doc
cp -vf $(DOC) $(DIST)/doc
mkdir -p $(DIST)/docs
cp -vf $(DOCS) $(DIST)/docs
mkdir -p $(DIST)/samples
cp -vf $(SAMPLES) $(DIST)/samples

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>

205
mime.vcxproj Executable file
View File

@ -0,0 +1,205 @@
<?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" />
<ClCompile Include="src\compat.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.0.0-1"
source = {
url = "git+https://github.com/lunarmodules/luasocket.git",
tag = "v3.0.0"
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library composed of two parts: a set of C
modules that provide support for the TCP and UDP transport layers, and a
set of Lua modules that provide functions commonly needed by applications
that deal with the Internet.
]],
homepage = "https://github.com/lunarmodules/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 = {
"docs"
, "samples"
, "etc"
, "test" }
}

View File

@ -0,0 +1,108 @@
package = "LuaSocket"
version = "3.0rc1-2"
source = {
url = "https://github.com/diegonehab/luasocket/archive/v3.0-rc1.zip",
dir = "luasocket-3.0-rc1",
}
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 = {
"LUA_COMPAT_APIINTCASTS",
"LUASOCKET_DEBUG",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
macosx = {
"LUA_COMPAT_APIINTCASTS",
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
win32 = {
"LUA_COMPAT_APIINTCASTS",
"LUASOCKET_DEBUG",
"NDEBUG",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
},
mingw32 = {
"LUA_COMPAT_APIINTCASTS",
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
}
}
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" },
defines = defines[plat],
incdir = "src"
},
["mime.core"] = {
sources = { "src/mime.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" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
modules["socket.unix"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c",
"src/usocket.c", "src/unix.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = { "src/buffer.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"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = { "doc", "samples", "etc", "test" }
}

View File

@ -0,0 +1,135 @@
package = "LuaSocket"
version = "3.1.0-1"
source = {
url = "git+https://github.com/lunarmodules/luasocket.git",
tag = "v3.1.0"
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library composed of two parts: a set of C
modules that provide support for the TCP and UDP transport layers, and a
set of Lua modules that provide functions commonly needed by applications
that deal with the Internet.
]],
homepage = "https://github.com/lunarmodules/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" }
modules["socket.core"].libdirs = {}
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 = {
"docs"
, "samples"
, "etc"
, "test" }
}

View File

@ -26,13 +26,13 @@ function parse(body)
data[key] = value
end
end
return data, code, message
return data, code, message
end
local host = socket.dns.gethostname()
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 body, headers, code = http.get(url)
local body, headers, code = http.request(url)
if code == 200 then
local data, code, error = parse(body)

View File

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

View File

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

View File

@ -2,7 +2,6 @@
-- UDP sample: echo protocol server
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
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
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "*"

View File

@ -28,8 +28,8 @@ end
do
local opt = {}
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)"
for i = 2, table.getn(arg), 1 do
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]?.?)"
for i = 2, #arg, 1 do
string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
end
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
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "localhost"

View File

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

216
socket.vcxproj Executable file
View File

@ -0,0 +1,216 @@
<?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\compat.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
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include <string.h>
#include <stdio.h>
#include "auxiliar.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes the module
\*-------------------------------------------------------------------------*/
@ -24,11 +19,11 @@ int auxiliar_open(lua_State *L) {
* Creates a new class with given methods
* 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 */
/* create __index table to place methods */
lua_pushstring(L, "__index"); /* mt,"__index" */
lua_newtable(L); /* mt,"__index",it */
lua_newtable(L); /* mt,"__index",it */
/* put class name into class metatable */
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
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) {
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 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
\*-------------------------------------------------------------------------*/
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
\*-------------------------------------------------------------------------*/
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
\*-------------------------------------------------------------------------*/
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
\*-------------------------------------------------------------------------*/
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
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
*
* 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
* 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
* of groups. This module provides the functionality to:
*
* - create new classes
* - add classes to groups
* - create new classes
* - add classes to groups
* - set the class of objects
* - check if an object belongs to a given class or group
* - get the userdata associated to objects
@ -26,23 +26,29 @@
* "class" with the class name.
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
*
* RCS ID: $Id$
* reverse mapping are done using lauxlib.
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
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_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_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);
int auxiliar_checkboolean(lua_State *L, int objidx);
int auxiliar_tostring(lua_State *L);
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* AUXILIAR_H */

View File

@ -1,12 +1,8 @@
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.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) {
buf->first = buf->last = 0;
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
buf->received = buf->sent = 0;
@ -53,8 +49,8 @@ void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, buf->received);
lua_pushnumber(L, buf->sent);
lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3;
}
@ -63,8 +59,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, buf->received);
buf->sent = (long) luaL_optnumber(L, 3, buf->sent);
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 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);
long start = (long) luaL_optnumber(L, 3, 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 (end < 0) end = (long) (size+end+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 */
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, sent+start-1);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, sent+start-1);
lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
/* 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
return lua_gettop(L) - top;
}
@ -107,12 +103,15 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
* object:receive() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_receive(lua_State *L, p_buffer buf) {
int err = IO_DONE, top = lua_gettop(L);
int err = IO_DONE, top;
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
p_timeout tm = timeout_markstart(buf->tm);
/* initialize buffer with optional extra prefix
timeout_markstart(buf->tm);
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
top = lua_gettop(L);
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
luaL_addlstring(&b, part, size);
@ -120,18 +119,24 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
if (!lua_isnumber(L, 2)) {
const char *p= luaL_optstring(L, 2, "*l");
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");
/* get a fixed number of bytes (minus what was already partially
* received) */
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
/* get a fixed number of bytes (minus what was already partially
* received) */
} 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 */
if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the
* contents of the buffer. this is the reason for the complication */
luaL_pushresult(&b);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2);
lua_pushnil(L);
lua_replace(L, -4);
} else {
@ -141,7 +146,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
}
#ifdef LUASOCKET_DEBUG
/* 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
return lua_gettop(L) - top;
}
@ -166,7 +171,7 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
size_t total = 0;
int 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;
err = io->send(io->ctx, data+total, step, &done, tm);
total += done;
@ -214,7 +219,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
\*-------------------------------------------------------------------------*/
static int recvline(p_buffer buf, luaL_Buffer *b) {
@ -225,7 +230,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
pos = 0;
while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */
if (data[pos] != '\r') luaL_putchar(b, data[pos]);
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++;
}
if (pos < count) { /* found '\n' */
@ -244,7 +249,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
static void buffer_skip(p_buffer buf, size_t count) {
buf->received += count;
buf->first += count;
if (buffer_isempty(buf))
if (buffer_isempty(buf))
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
* timeout management is done with the timeout.h interface.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "io.h"
#include "timeout.h"
@ -31,17 +28,25 @@ typedef struct t_buffer_ {
size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */
p_timeout tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */
size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */
} t_buffer;
typedef t_buffer *p_buffer;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int buffer_open(lua_State *L);
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_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);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#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
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "luasocket.h"
#include "except.h"
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#if LUA_VERSION_NUM < 502
#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.
@ -21,7 +25,7 @@ static int finalize(lua_State *L);
static int do_nothing(lua_State *L);
/* except functions */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"newtry", global_newtry},
{"protect", global_protect},
{NULL, NULL}
@ -31,18 +35,17 @@ static luaL_reg func[] = {
* Try factory
\*-------------------------------------------------------------------------*/
static void wrap(lua_State *L) {
lua_newtable(L);
lua_pushnumber(L, 1);
lua_pushvalue(L, -3);
lua_settable(L, -3);
lua_insert(L, -2);
lua_pop(L, 1);
lua_createtable(L, 1, 0);
lua_pushvalue(L, -2);
lua_rawseti(L, -2, 1);
lua_pushvalue(L, lua_upvalueindex(1));
lua_setmetatable(L, -2);
}
static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, 0);
lua_pushvalue(L, lua_upvalueindex(2));
lua_call(L, 0, 0);
lua_settop(L, 2);
wrap(L);
lua_error(L);
@ -50,15 +53,17 @@ static int finalize(lua_State *L) {
} else return lua_gettop(L);
}
static int do_nothing(lua_State *L) {
static int do_nothing(lua_State *L) {
(void) L;
return 0;
return 0;
}
static int global_newtry(lua_State *L) {
lua_settop(L, 1);
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;
}
@ -66,27 +71,49 @@ static int global_newtry(lua_State *L) {
* Protect factory
\*-------------------------------------------------------------------------*/
static int unwrap(lua_State *L) {
if (lua_istable(L, -1)) {
lua_pushnumber(L, 1);
lua_gettable(L, -2);
lua_pushnil(L);
lua_insert(L, -2);
return 1;
} else return 0;
if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
int r = lua_rawequal(L, -1, lua_upvalueindex(1));
lua_pop(L, 1);
if (r) {
lua_pushnil(L);
lua_rawgeti(L, -2, 1);
return 1;
}
}
return 0;
}
static int protected_(lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
(void)ctx;
if (status != 0 && status != LUA_YIELD) {
if (unwrap(L)) return 2;
else lua_error(L);
return 0;
else return lua_error(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) {
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;
}
@ -94,6 +121,9 @@ static int global_protect(lua_State *L) {
* Init module
\*-------------------------------------------------------------------------*/
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;
}

View File

@ -9,27 +9,38 @@
* error checking was taking a substantial amount of the coding. These
* function greatly simplify the task of checking errors.
*
* The main idea is that functions should return nil as its first return
* value when it finds an error, and return an error message (or value)
* The main idea is that functions should return nil as their first return
* 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,
* the other values don't matter.
*
* 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
* nil. Otherwise, it returns all values it received.
* checks the first value, and, if it's falsy, wraps the second value in a
* 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
* function it receives, but the new function doesn't throw exceptions: it
* returns nil followed by the error message instead.
* The "newtry" function is a factory for "try" functions that call a
* finalizer in protected mode before calling "error".
*
* With these two function, it's easy to write functions that throw
* exceptions on error, but that don't interrupt the user script.
* The "protect" function returns a new function that behaves exactly like
* 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);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif

View File

@ -2,7 +2,6 @@
-- FTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -16,27 +15,27 @@ local socket = require("socket")
local url = require("socket.url")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
module("socket.ftp")
socket.ftp = {}
local _M = socket.ftp
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout in seconds before the program gives up on a connection
TIMEOUT = 60
_M.TIMEOUT = 60
-- default port for ftp service
PORT = 21
local PORT = 21
-- this is the default anonymous password. used when no password is
-- provided in url. should be changed to your e-mail.
USER = "ftp"
PASSWORD = "anonymous@anonymous.org"
_M.USER = "ftp"
_M.PASSWORD = "anonymous@anonymous.org"
-----------------------------------------------------------------------------
-- Low level FTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
function _M.open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end)
@ -44,22 +43,22 @@ function open(server, port, create)
end
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.try(self.data:settimeout(TIMEOUT))
self.try(self.data:settimeout(_M.TIMEOUT))
end
function metat.__index:pasvconnect()
self.data = self.try(socket.tcp())
self.try(self.data:settimeout(TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
self.try(self.data:settimeout(_M.TIMEOUT))
self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
end
function metat.__index:login(user, password)
self.try(self.tp:command("user", user or USER))
local code, reply = self.try(self.tp:check{"2..", 331})
self.try(self.tp:command("user", user or _M.USER))
local code, _ = self.try(self.tp:check{"2..", 331})
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.."))
end
return 1
@ -67,37 +66,70 @@ end
function metat.__index:pasv()
self.try(self.tp:command("pasv"))
local code, reply = self.try(self.tp:check("2.."))
local _, reply = self.try(self.tp:check("2.."))
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
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.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
}
if self.server then
self.server:close()
self.server = nil
end
return self.pasvt.ip, self.pasvt.port
return self.pasvt.address, self.pasvt.port
end
function metat.__index:port(ip, port)
function metat.__index:epsv()
self.try(self.tp:command("epsv"))
local _, reply = self.try(self.tp:check("229"))
local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
local _, _, _, 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
if not ip then
ip, port = self.try(self.tp:getcontrol():getsockname())
self.server = self.try(socket.bind(ip, 0))
ip, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(TIMEOUT))
if not address then
address = 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 pl = math.mod(port, 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:check("2.."))
return 1
end
function metat.__index:eprt(family, address, port)
self.pasvt = nil
if not address then
address = 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)
self.try(self.pasvt or self.server, "need port or pasv first")
-- if there is a pasvt table, we already sent a PASV command
@ -110,13 +142,13 @@ function metat.__index:send(sendt)
local command = sendt.command or "stor"
-- send the transfer command and check the reply
self.try(self.tp:command(command, argument))
local code, reply = self.try(self.tp:check{"2..", "1.."})
-- if there is not a a pasvt table, then there is a server
local code, _ = self.try(self.tp:check{"2..", "1.."})
-- if there is not a pasvt table, then there is a server
-- and we already sent a PORT command
if not self.pasvt then self:portconnect() end
-- get the sink, source and step for the transfer
local step = sendt.step or ltn12.pump.step
local readt = {self.tp.c}
local readt = { self.tp }
local checkstep = function(src, snk)
-- check status in control connection while downloading
local readyt = socket.select(readt, nil, 0)
@ -143,7 +175,11 @@ function metat.__index:receive(recvt)
if argument == "" then argument = nil end
local command = recvt.command or "retr"
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
local source = socket.source("until-closed", self.data)
local step = recvt.step or ltn12.pump.step
@ -200,11 +236,11 @@ end
local function tput(putt)
putt = override(putt)
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:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end
f:pasv()
f:epsv()
local sent = f:send(putt)
f:quit()
f:close()
@ -212,11 +248,11 @@ local function tput(putt)
end
local default = {
path = "/",
scheme = "ftp"
path = "/",
scheme = "ftp"
}
local function parse(u)
local function genericform(u)
local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
socket.try(t.host, "missing hostname")
@ -229,13 +265,15 @@ local function parse(u)
return t
end
_M.genericform = genericform
local function sput(u, body)
local putt = parse(u)
local putt = genericform(u)
putt.source = ltn12.source.string(body)
return tput(putt)
end
put = socket.protect(function(putt, body)
_M.put = socket.protect(function(putt, body)
if base.type(putt) == "string" then return sput(putt, body)
else return tput(putt) end
end)
@ -243,39 +281,49 @@ end)
local function tget(gett)
gett = override(gett)
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:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end
f:pasv()
f:epsv()
f:receive(gett)
f:quit()
return f:close()
end
local function sget(u)
local gett = parse(u)
local gett = genericform(u)
local t = {}
gett.sink = ltn12.sink.table(t)
tget(gett)
return table.concat(t)
end
command = socket.protect(function(cmdt)
_M.command = socket.protect(function(cmdt)
cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname")
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:login(cmdt.user, cmdt.password)
f.try(f.tp:command(cmdt.command, cmdt.argument))
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
if type(cmdt.command) == "table" then
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()
return f:close()
end)
get = socket.protect(function(gett)
_M.get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) 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.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -13,19 +12,34 @@ local url = require("socket.url")
local ltn12 = require("ltn12")
local mime = require("mime")
local string = require("string")
local headers = require("socket.headers")
local base = _G
local table = require("table")
module("socket.http")
socket.http = {}
local _M = socket.http
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
PORT = 80
_M.TIMEOUT = 60
-- 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 }}
-----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed
@ -75,7 +89,7 @@ socket.sourcet["http-chunked"] = function(sock, headers)
-- was it the last chunk?
if size > 0 then
-- if not, get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size)
local chunk, err, _ = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
else
@ -105,15 +119,15 @@ end
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(host, port, create)
function _M.open(host, port, create)
-- 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)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(TIMEOUT))
h.try(c:connect(host, port or PORT))
h.try(c:settimeout(_M.TIMEOUT))
h.try(c:connect(host, port))
-- here everything worked
return h
end
@ -123,10 +137,11 @@ function metat.__index:sendrequestline(method, uri)
return self.try(self.c:send(reqline))
end
function metat.__index:sendheaders(headers)
function metat.__index:sendheaders(tosend)
local canonic = headers.canonic
local h = "\r\n"
for i, v in base.pairs(headers) do
h = i .. ": " .. v .. "\r\n" .. h
for f, v in base.pairs(tosend) do
h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
end
self.try(self.c:send(h))
return 1
@ -142,7 +157,17 @@ function metat.__index:sendbody(headers, source, step)
end
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)"))
return self.try(base.tonumber(code), status)
end
@ -163,6 +188,12 @@ function metat.__index:receivebody(headers, sink, step)
sink, step))
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()
return self.c:close()
end
@ -173,7 +204,7 @@ end
local function adjusturi(reqt)
local u = reqt
-- 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 = {
path = socket.try(reqt.path, "invalid path 'nil'"),
params = reqt.params,
@ -185,7 +216,7 @@ local function adjusturi(reqt)
end
local function adjustproxy(reqt)
local proxy = reqt.proxy or PROXY
local proxy = reqt.proxy or _M.PROXY
if proxy then
proxy = url.parse(proxy)
return proxy.host, proxy.port or 3128
@ -196,16 +227,30 @@ end
local function adjustheaders(reqt)
-- 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 = {
["user-agent"] = USERAGENT,
["host"] = reqt.host,
["user-agent"] = _M.USERAGENT,
["host"] = host,
["connection"] = "close, TE",
["te"] = "trailers"
}
-- if we have authentication information, pass it along
if reqt.user and reqt.password then
lower["authorization"] =
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
lower["authorization"] =
"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
-- override with user headers
for i,v in base.pairs(reqt.headers or lower) do
@ -216,10 +261,8 @@ end
-- default url parts
local default = {
host = "",
port = PORT,
path ="/",
scheme = "http"
path ="/"
, scheme = "http"
}
local function adjustrequest(reqt)
@ -227,25 +270,46 @@ local function adjustrequest(reqt)
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
-- explicit components override url
for i,v in base.pairs(reqt) do nreqt[i] = v end
if nreqt.port == "" then nreqt.port = 80 end
socket.try(nreqt.host and nreqt.host ~= "",
"invalid host '" .. base.tostring(nreqt.host) .. "'")
-- default to scheme particulars
local schemedefs, host, port, method
= 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
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
nreqt.headers = adjustheaders(nreqt)
if nreqt.source
and not nreqt.headers["content-length"]
and not nreqt.headers["transfer-encoding"]
then
nreqt.headers["transfer-encoding"] = "chunked"
end
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
return nreqt
end
local function shouldredirect(reqt, code, headers)
return headers.location and
string.gsub(headers.location, "%s", "") ~= "" and
(reqt.redirect ~= false) and
(code == 301 or code == 302) and
local location = headers.location
if not location then return false end
location = string.gsub(location, "%s", "")
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")
and (not reqt.nredirects or reqt.nredirects < 5)
and ((false == reqt.maxredirects)
or ((reqt.nredirects or 0)
< (reqt.maxredirects or 5)))
end
local function shouldreceivebody(reqt, code)
@ -258,44 +322,60 @@ end
-- forward declarations
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 {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
url = url.absolute(reqt.url, location),
url = newurl,
source = reqt.source,
sink = reqt.sink,
headers = reqt.headers,
proxy = reqt.proxy,
proxy = reqt.proxy,
maxredirects = reqt.maxredirects,
nredirects = (reqt.nredirects or 0) + 1,
create = reqt.create
}
}
-- pass location header back as a hint we redirected
headers = headers or {}
headers.location = headers.location or location
return result, code, headers, status
end
function trequest(reqt)
--[[local]] function trequest(reqt)
-- we loop until we get what we want, or
-- until we are sure there is no way to get it
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
h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers)
local code = 100
local headers, status
-- if there is a body, check for server status
-- if there is a body, send it
if nreqt.source then
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
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
while code == 100 do
while code == 100 do
h:receiveheaders()
code, status = h:receivestatusline()
headers = h:receiveheaders()
end
headers = h:receiveheaders()
-- 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
h:close()
return tredirect(reqt, headers.location)
@ -308,11 +388,13 @@ function trequest(reqt)
return 1, code, headers, status
end
local function srequest(u, b)
-- turns an url and a body into a generic request
local function genericform(u, b)
local t = {}
local reqt = {
url = u,
sink = ltn12.sink.table(t)
sink = ltn12.sink.table(t),
target = t
}
if b then
reqt.source = ltn12.source.string(b)
@ -322,11 +404,21 @@ local function srequest(u, b)
}
reqt.method = "POST"
end
local code, headers, status = socket.skip(1, trequest(reqt))
return table.concat(t), code, headers, status
return reqt
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)
else return trequest(reqt) end
end)
_M.schemes = SCHEMES
return _M

414
src/inet.c Normal file → Executable file
View File

@ -1,36 +1,34 @@
/*=========================================================================*\
* Internet domain functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "inet.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
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_getnameinfo(lua_State *L);
static void inet_pushresolved(lua_State *L, struct hostent *hp);
static int inet_global_gethostname(lua_State *L);
/* DNS functions */
static luaL_reg func[] = {
{ "toip", inet_global_toip },
{ "tohostname", inet_global_tohostname },
static luaL_Reg func[] = {
{ "toip", inet_global_toip},
{ "getaddrinfo", inet_global_getaddrinfo},
{ "tohostname", inet_global_tohostname},
{ "getnameinfo", inet_global_getnameinfo},
{ "gethostname", inet_global_gethostname},
{ NULL, NULL}
};
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
@ -38,7 +36,7 @@ int inet_open(lua_State *L)
{
lua_pushstring(L, "dns");
lua_newtable(L);
luaL_openlib(L, NULL, func, 0);
luaL_setfuncs(L, func, 0);
lua_settable(L, -3);
return 0;
}
@ -54,7 +52,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
struct in_addr addr;
if (inet_aton(address, &addr))
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
else
else
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) {
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
@ -76,6 +74,50 @@ static int inet_global_tohostname(lua_State *L) {
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
* or ip address
@ -83,7 +125,7 @@ static int inet_global_tohostname(lua_State *L) {
static int inet_global_toip(lua_State *L)
{
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
@ -95,6 +137,81 @@ static int inet_global_toip(lua_State *L)
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
@ -105,7 +222,7 @@ static int inet_global_gethostname(lua_State *L)
name[256] = '\0';
if (gethostname(name, 256) < 0) {
lua_pushnil(L);
lua_pushstring(L, "gethostname failed");
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
lua_pushstring(L, name);
@ -113,43 +230,74 @@ static int inet_global_gethostname(lua_State *L)
}
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* 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);
char name[INET6_ADDRSTRLEN];
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getpeername failed");
} else {
lua_pushstring(L, inet_ntoa(peer.sin_addr));
lua_pushnumber(L, ntohs(peer.sin_port));
lua_pushstring(L, socket_strerror(errno));
return 2;
}
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, LUA_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
\*-------------------------------------------------------------------------*/
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;
socklen_t local_len = sizeof(local);
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
int err;
struct sockaddr_storage peer;
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_pushstring(L, "getsockname failed");
} else {
lua_pushstring(L, inet_ntoa(local.sin_addr));
lua_pushnumber(L, ntohs(local.sin_port));
lua_pushstring(L, socket_strerror(errno));
return 2;
}
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, LUA_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
\*-------------------------------------------------------------------------*/
const char *inet_trycreate(p_socket ps, int type) {
return socket_strerror(socket_create(ps, AF_INET, type, 0));
const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
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)
\*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_socket ps, const char *address,
unsigned short port, p_timeout tm)
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints)
{
struct sockaddr_in remote;
int err;
memset(&remote, 0, sizeof(remote));
remote.sin_family = AF_INET;
remote.sin_port = htons(port);
if (strcmp(address, "*")) {
if (!inet_aton(address, &remote.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = socket_gethostbyname(address, &hp);
if (err != IO_DONE) return socket_hoststrerror(err);
addr = (struct in_addr **) hp->h_addr_list;
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
int current_family = *family;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
timeout_markstart(tm);
/* 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;
err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
return socket_strerror(err);
/* try connecting to remote address */
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
(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)
\*-------------------------------------------------------------------------*/
const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
{
struct sockaddr_in local;
int err;
memset(&local, 0, sizeof(local));
/* address is either wildcard or a valid ip address */
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
local.sin_family = AF_INET;
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = socket_gethostbyname(address, &hp);
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));
const char *inet_trybind(p_socket ps, int *family, const char *address,
const char *serv, struct addrinfo *bindhints) {
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
int current_family = *family;
/* translate luasocket special values to C */
if (strcmp(address, "*") == 0) address = NULL;
if (!serv) serv = "0";
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
if (err) {
if (resolved) freeaddrinfo(resolved);
return err;
}
err = socket_bind(ps, (SA *) &local, sizeof(local));
if (err != IO_DONE) socket_destroy(ps);
return socket_strerror(err);
/* iterate over resolved addresses until one is good */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
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
* marvelously fast, but it works just fine.
* Some systems do not provide these so that we provide our own.
\*-------------------------------------------------------------------------*/
#ifdef INET_ATON
#ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
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
#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
#define INET_H
#ifndef INET_H
#define INET_H
/*=========================================================================*\
* Internet domain functions
* LuaSocket toolkit
*
* This module implements the creation and connection of internet domain
* 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
* available. The module also implements the interface of the internet
* getpeername and getsockname functions as seen by Lua programs.
*
* The Lua functions toip and tohostname are also implemented here.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "socket.h"
#include "timeout.h"
#ifdef _WIN32
#define INET_ATON
#define LUASOCKET_INET_ATON
#endif
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int inet_open(lua_State *L);
const char *inet_trycreate(p_socket ps, int type);
const char *inet_tryconnect(p_socket ps, const char *address,
unsigned short port, p_timeout tm);
const char *inet_trybind(p_socket ps, const char *address,
unsigned short port);
int inet_optfamily(lua_State* L, int narg, const char* def);
int inet_optsocktype(lua_State* L, int narg, const char* def);
int inet_meth_getpeername(lua_State *L, p_socket ps);
int inet_meth_getsockname(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 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);
#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 */

View File

@ -1,14 +1,10 @@
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "luasocket.h"
#include "io.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
@ -27,6 +23,6 @@ const char *io_strerror(int err) {
case IO_DONE: return NULL;
case IO_CLOSED: return "closed";
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
* is very simple.
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
#include "lua.h"
#include "luasocket.h"
#include "timeout.h"
/* IO error codes */
@ -60,8 +56,15 @@ typedef struct t_io_ {
} t_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);
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.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -10,17 +9,24 @@
-----------------------------------------------------------------------------
local string = require("string")
local table = require("table")
local unpack = unpack or table.unpack
local base = _G
module("ltn12")
local select = select
filter = {}
source = {}
sink = {}
pump = {}
local _M = {}
if module then -- heuristic for exporting a global package table
ltn12 = _M -- luacheck: ignore
end
local filter,source,sink,pump = {},{},{},{}
_M.filter = filter
_M.source = source
_M.sink = sink
_M.pump = pump
-- 2048 seems to be better in windows...
BLOCKSIZE = 2048
_VERSION = "LTN12 1.0.1"
_M.BLOCKSIZE = 2048
_M._VERSION = "LTN12 1.0.3"
-----------------------------------------------------------------------------
-- Filter stuff
@ -38,7 +44,8 @@ end
-- chains a bunch of filters together
-- (thanks to Wim Couwenberg)
function filter.chain(...)
local n = table.getn(arg)
local arg = {...}
local n = select('#',...)
local top, index = 1, 1
local retry = ""
return function(chunk)
@ -89,7 +96,7 @@ end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(BLOCKSIZE)
local chunk = handle:read(_M.BLOCKSIZE)
if not chunk then handle:close() end
return chunk
end
@ -112,14 +119,24 @@ function source.string(s)
if s then
local i = 1
return function()
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
i = i + BLOCKSIZE
local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
i = i + _M.BLOCKSIZE
if chunk ~= "" then return chunk
else return nil end
end
else return source.empty() 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
function source.rewind(src)
base.assert(src)
@ -135,7 +152,9 @@ function source.rewind(src)
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)
local last_in, last_out = "", ""
local state = "feeding"
@ -186,6 +205,7 @@ end
-- other, as if they were concatenated
-- (thanks to Wim Couwenberg)
function source.cat(...)
local arg = {...}
local src = table.remove(arg, 1)
return function()
while src do
@ -249,8 +269,13 @@ function sink.error(err)
end
end
-- chains a sink with a filter
function sink.chain(f, snk)
-- chains a sink with one or several filter(s)
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)
return function(chunk, err)
if chunk ~= "" then
@ -290,3 +315,4 @@ function pump.all(src, snk, step)
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
* IO routines, however, follow the Lua style, being very similar to the
* 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 "auxiliar.h"
#include "except.h"
@ -47,7 +32,7 @@ static int base_open(lua_State *L);
/*-------------------------------------------------------------------------*\
* Modules and functions
\*-------------------------------------------------------------------------*/
static const luaL_reg mod[] = {
static const luaL_Reg mod[] = {
{"auxiliar", auxiliar_open},
{"except", except_open},
{"timeout", timeout_open},
@ -59,7 +44,7 @@ static const luaL_reg mod[] = {
{NULL, NULL}
};
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"skip", global_skip},
{"__unload", global_unload},
{NULL, NULL}
@ -69,7 +54,7 @@ static luaL_reg func[] = {
* Skip a few arguments
\*-------------------------------------------------------------------------*/
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;
return ret >= 0 ? ret : 0;
}
@ -89,7 +74,8 @@ static int global_unload(lua_State *L) {
static int base_open(lua_State *L) {
if (socket_open()) {
/* 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
lua_pushstring(L, "_DEBUG");
lua_pushboolean(L, 1);

View File

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

497
src/makefile Normal file → Executable file
View File

@ -1,90 +1,461 @@
#------
# Load configuration
# luasocket src/makefile
#
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 5.3 5.4
# 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_$(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.0
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
#
#$(COMPAT)/compat-5.1.o \
SOCKET_OBJS:= \
luasocket.o \
timeout.o \
buffer.o \
io.o \
auxiliar.o \
options.o \
inet.o \
tcp.o \
udp.o \
except.o \
select.o \
usocket.o
SOCKET_OBJS= \
luasocket.$(O) \
timeout.$(O) \
buffer.$(O) \
io.$(O) \
auxiliar.$(O) \
compat.$(O) \
options.$(O) \
inet.$(O) \
$(SOCKET) \
except.$(O) \
select.$(O) \
tcp.$(O) \
udp.$(O)
#------
# Modules belonging mime-core
#
#$(COMPAT)/compat-5.1.o \
MIME_OBJS:=\
mime.o
MIME_OBJS= \
mime.$(O) \
compat.$(O)
#------
# Modules belonging unix (local domain sockets)
#
UNIX_OBJS:=\
buffer.o \
auxiliar.o \
options.o \
timeout.o \
io.o \
usocket.o \
unix.o
UNIX_OBJS=\
buffer.$(O) \
auxiliar.$(O) \
options.$(O) \
timeout.$(O) \
io.$(O) \
usocket.$(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)
$(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS)
$(LD) $(SOCKET_OBJS) $(LDFLAGS)$@
$(MIME_SO): $(MIME_OBJS)
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
$(LD) $(MIME_OBJS) $(LDFLAGS)$@
all-unix: all $(UNIX_SO) $(SERIAL_SO)
$(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
#
auxiliar.o: auxiliar.c auxiliar.h
buffer.o: buffer.c buffer.h io.h timeout.h
except.o: except.c except.h
inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h
io.o: io.c io.h timeout.h
luasocket.o: luasocket.c luasocket.h auxiliar.h except.h timeout.h \
buffer.h io.h inet.h socket.h usocket.h tcp.h udp.h select.h
mime.o: mime.c mime.h
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
usocket.h inet.h
select.o: select.c socket.h io.h timeout.h usocket.h select.h
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h tcp.h buffer.h
timeout.o: timeout.c auxiliar.h timeout.h
udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h udp.h
unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h options.h \
unix.h buffer.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS)
rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS)
#------
# End of makefile configuration
#
compat.$(O): compat.c compat.h
auxiliar.$(O): auxiliar.c auxiliar.h
buffer.$(O): buffer.c buffer.h io.h timeout.h
except.$(O): except.c except.h
inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
io.$(O): io.c io.h timeout.h
luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
udp.h select.h
mime.$(O): mime.c mime.h
options.$(O): options.c auxiliar.h options.h socket.h io.h \
timeout.h usocket.h inet.h
select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
options.h unix.h buffer.h
tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h tcp.h buffer.h
timeout.$(O): timeout.c auxiliar.h timeout.h
udp.$(O): udp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h udp.h
unix.$(O): unix.c auxiliar.h socket.h io.h timeout.h usocket.h \
options.h unix.h buffer.h
usocket.$(O): usocket.c socket.h io.h timeout.h usocket.h
wsocket.$(O): wsocket.c socket.h io.h timeout.h usocket.h

View File

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

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

@ -1,19 +1,11 @@
/*=========================================================================*\
* MIME support functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
#include "luasocket.h"
#include "mime.h"
#include <string.h>
#include <ctype.h>
/*=========================================================================*\
* 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 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 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 void qpsetup(UC *qpclass, UC *qpunbase);
/*static void qpsetup(UC *class, UC *unbase);*/
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 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);
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
/* code support functions */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{ "dot", mime_global_dot },
{ "b64", mime_global_b64 },
{ "eol", mime_global_eol },
@ -63,17 +55,111 @@ static luaL_reg func[] = {
/*-------------------------------------------------------------------------*\
* 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};
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
\*-------------------------------------------------------------------------*/
static const UC b64base[] =
"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
@ -81,16 +167,17 @@ static UC b64unbase[256];
/*-------------------------------------------------------------------------*\
* 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 */
lua_pushstring(L, "_VERSION");
lua_pushstring(L, MIME_VERSION);
lua_rawset(L, -3);
/* initialize lookup tables */
qpsetup(qpclass, qpunbase);
b64setup(b64unbase);
/*qpsetup(qpclass, qpunbase);*/
/*b64setup(b64unbase);*/
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.
* A, n = wrp(l, B, length)
* 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.
* 'n' is the number of bytes left in the last line of A.
* 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.
* 'n' is the number of bytes left in the last line of A.
\*-------------------------------------------------------------------------*/
static int mime_global_wrp(lua_State *L)
{
size_t size = 0;
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;
int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer;
@ -120,7 +207,7 @@ static int mime_global_wrp(lua_State *L)
else lua_pushnil(L);
lua_pushnumber(L, length);
return 2;
}
}
luaL_buffinit(L, &buffer);
while (input < last) {
switch (*input) {
@ -135,7 +222,7 @@ static int mime_global_wrp(lua_State *L)
left = length;
luaL_addstring(&buffer, CRLF);
}
luaL_putchar(&buffer, *input);
luaL_addchar(&buffer, *input);
left--;
break;
}
@ -146,23 +233,31 @@ static int mime_global_wrp(lua_State *L)
return 2;
}
#if 0
/*-------------------------------------------------------------------------*\
* Fill base64 decode map.
* Fill base64 decode map.
\*-------------------------------------------------------------------------*/
static void b64setup(UC *b64unbase)
static void b64setup(UC *unbase)
{
int i;
for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i;
b64unbase['='] = 0;
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
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.
* 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)
{
input[size++] = c;
@ -171,7 +266,7 @@ static size_t b64encode(UC c, UC *input, size_t size,
unsigned long value = 0;
value += input[0]; value <<= 8;
value += input[1]; value <<= 8;
value += input[2];
value += input[2];
code[3] = b64base[value & 0x3f]; value >>= 6;
code[2] = 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.
* 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)
{
unsigned long value = 0;
@ -200,7 +295,7 @@ static size_t b64pad(const UC *input, size_t size,
luaL_addlstring(buffer, (char *) code, 4);
break;
case 2:
value = input[0]; value <<= 8;
value = input[0]; value <<= 8;
value |= input[1]; value <<= 2;
code[2] = 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.
* 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)
{
/* 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[0] = (UC) value;
/* 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);
return 0;
/* need more data */
@ -248,7 +343,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
* A, B = b64(C, D)
* 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.
* 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
* every chunk we received.
\*-------------------------------------------------------------------------*/
@ -256,7 +351,7 @@ static int mime_global_b64(lua_State *L)
{
UC atom[3];
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;
luaL_Buffer buffer;
/* end-of-input blackhole */
@ -265,22 +360,27 @@ static int mime_global_b64(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
while (input < last)
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 (!input) {
size_t osize = 0;
asize = b64pad(atom, asize, &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);
return 2;
}
/* otherwise process the second part */
last = input + isize;
while (input < last)
while (input < last)
asize = b64encode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize);
@ -297,7 +397,7 @@ static int mime_global_unb64(lua_State *L)
{
UC atom[4];
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;
luaL_Buffer buffer;
/* end-of-input blackhole */
@ -306,21 +406,26 @@ static int mime_global_unb64(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
while (input < last)
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 (!input) {
size_t osize = 0;
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);
return 2;
}
/* otherwise, process the rest of the input */
last = input + isize;
while (input < last)
while (input < last)
asize = b64decode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer);
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
* encoded lines must be no longer than 76 not counting 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
\*-------------------------------------------------------------------------*/
#if 0
/*-------------------------------------------------------------------------*\
* Split quoted-printable characters into classes
* Precompute reverse map for encoding
\*-------------------------------------------------------------------------*/
static void qpsetup(UC *qpclass, UC *qpunbase)
static void qpsetup(UC *cl, UC *unbase)
{
int i;
for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN;
qpclass['\t'] = QP_IF_LAST;
qpclass[' '] = QP_IF_LAST;
qpclass['\r'] = QP_CR;
for (i = 0; i < 256; i++) qpunbase[i] = 255;
qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2;
qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5;
qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8;
qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10;
qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12;
qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13;
qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15;
qpunbase['f'] = 15;
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
cl['\t'] = QP_IF_LAST;
cl[' '] = QP_IF_LAST;
cl['\r'] = QP_CR;
for (i = 0; i < 256; i++) unbase[i] = 255;
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
unbase['E'] = 14; unbase['e'] = 14; unbase['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
\*-------------------------------------------------------------------------*/
static void qpquote(UC c, luaL_Buffer *buffer)
{
luaL_putchar(buffer, '=');
luaL_putchar(buffer, qpbase[c >> 4]);
luaL_putchar(buffer, qpbase[c & 0x0F]);
luaL_addchar(buffer, '=');
luaL_addchar(buffer, qpbase[c >> 4]);
luaL_addchar(buffer, qpbase[c & 0x0F]);
}
/*-------------------------------------------------------------------------*\
* 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)
{
input[size++] = c;
@ -400,7 +537,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
qpquote(input[0], buffer);
luaL_addstring(buffer, marker);
return 0;
} else luaL_putchar(buffer, input[0]);
} else luaL_addchar(buffer, input[0]);
break;
/* might have to be quoted always */
case QP_QUOTED:
@ -408,7 +545,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
break;
/* might never have to be quoted */
default:
luaL_putchar(buffer, input[0]);
luaL_addchar(buffer, input[0]);
break;
}
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)
{
size_t 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);
}
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
* A, B = qp(C, D, marker)
* 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
* can be encoded without doubts.
* A is the encoded version of the largest prefix of C .. D that
* can be encoded without doubts.
* B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/
static int mime_global_qp(lua_State *L)
{
size_t asize = 0, isize = 0;
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 char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
@ -454,11 +590,13 @@ static int mime_global_qp(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
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 (!input) {
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.
* 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) {
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 */
switch (input[0]) {
/* if we have an escape character */
case '=':
if (size < 3) return size;
case '=':
if (size < 3) return size;
/* eliminate soft line break */
if (input[1] == '\r' && input[2] == '\n') return 0;
/* decode quoted representation */
c = qpunbase[input[1]]; d = qpunbase[input[2]];
/* if it is an invalid, do not decode */
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;
case '\r':
if (size < 2) return size;
if (size < 2) return size;
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
return 0;
default:
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
luaL_putchar(buffer, input[0]);
luaL_addchar(buffer, input[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
* A, B = qp(C, D)
* A is the decoded version of the largest prefix of C .. D that
* can be decoded without doubts.
* A is the decoded version of the largest prefix of C .. D that
* can be decoded without doubts.
* B has the remaining bytes of C .. D, *without* decoding.
\*-------------------------------------------------------------------------*/
static int mime_global_unqp(lua_State *L)
{
size_t asize = 0, isize = 0;
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;
luaL_Buffer buffer;
/* end-of-input blackhole */
@ -527,18 +665,20 @@ static int mime_global_unqp(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
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 (!input) {
luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
}
/* otherwise process rest of input */
last = input + isize;
while (input < last)
@ -551,9 +691,9 @@ static int mime_global_unqp(lua_State *L)
/*-------------------------------------------------------------------------*\
* Incrementally breaks a quoted-printed string into lines
* A, n = qpwrp(l, B, length)
* 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.
* 'n' is the number of bytes left in the last line of A.
* 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.
* '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
* 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;
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;
int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer;
@ -586,16 +726,16 @@ static int mime_global_qpwrp(lua_State *L)
if (left <= 3) {
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_putchar(&buffer, *input);
}
luaL_addchar(&buffer, *input);
left--;
break;
default:
default:
if (left <= 1) {
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_putchar(&buffer, *input);
luaL_addchar(&buffer, *input);
left--;
break;
}
@ -618,7 +758,7 @@ static int mime_global_qpwrp(lua_State *L)
* last is the previous character
\*-------------------------------------------------------------------------*/
#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)
{
if (eolcandidate(c)) {
@ -630,21 +770,21 @@ static int eolprocess(int c, int last, const char *marker,
return c;
}
} else {
luaL_putchar(buffer, c);
luaL_addchar(buffer, (char) c);
return 0;
}
}
/*-------------------------------------------------------------------------*\
* Converts a string to uniform EOL convention.
* Converts a string to uniform EOL convention.
* A, n = eol(o, B, marker)
* 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.
\*-------------------------------------------------------------------------*/
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;
const char *input = luaL_optlstring(L, 2, NULL, &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)
{
luaL_putchar(buffer, c);
luaL_addchar(buffer, (char) c);
switch (c) {
case '\r':
case '\r':
return 1;
case '\n':
return (state == 1)? 2: 0;
case '.':
if (state == 2)
luaL_putchar(buffer, '.');
case '\n':
return (state == 1)? 2: 0;
case '.':
if (state == 2)
luaL_addchar(buffer, '.');
/* Falls through. */
default:
return 0;
}
@ -702,10 +843,10 @@ static int mime_global_dot(lua_State *L)
}
/* process all input */
luaL_buffinit(L, &buffer);
while (input < last)
while (input < last)
state = dot(*input++, state, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, state);
lua_pushnumber(L, (lua_Number) state);
return 2;
}

View File

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

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