272 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
128 changed files with 5585 additions and 3653 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

1
.gitignore vendored
View File

@ -6,7 +6,6 @@
*.dll*
*.user
*.sdf
Lua.props
Debug
Release
*.manifest

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",
}

View File

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

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

View File

@ -1,5 +1,4 @@
LuaSocket 3.0 license
Copyright <20> 2004-2013 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>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.1\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.1\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.1\</LUAINC_PATH>
<LUALIB>lua51.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua51</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.2\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.2\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.2\</LUAINC_PATH>
<LUALIB>lua52.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua52</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

44
NEW
View File

@ -1,44 +0,0 @@
What's New
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).

11
README
View File

@ -1,11 +0,0 @@
This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
and Linux.
Please use the project page at GitHub
https://github.com/diegonehab/luasocket
to file bug reports or propose changes.
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.

View File

@ -1,215 +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="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.0-rc1 is now available for download!
It is compatible with Lua&nbsp;5.1 and 5.2, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
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/diegonehab/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>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=new>What's New</h2>
<p>
Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
and Lua&nbsp;5.2 compatibility.
</p>
<ul>
<li> Added: Compatible with Lua&nbsp;5.2
<ul>
<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
package tables will <em>not</em> be exported as globals!
</ul>
<li> Added: IPv6 support;
<ul>
<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
IPv6 addresses, and return the socket family as a third value;
<li> URL module updated to support IPv6 host names;
<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
<li> New <tt>socket.dns.getaddrinfo</tt> and
<tt>socket.dns.getnameinfo</tt> functions;
</ul>
<li> Added: <tt>getoption</tt> method;
<li> Fixed: <tt>url.unescape</tt> was returning additional values;
<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
<tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
mistaking their own stack slots for functions arguments;
<li> Fixed: Receiving zero-length datagram is now possible;
<li> Improved: Hidden all internal library symbols;
<li> Improved: Better error messages;
<li> Improved: Better documentation of socket options.
<li> Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
<li> Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
<li> Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
<li> Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
<li> Fixed: manual links to home.html changed to index.html
(Robert Hahn);
<li> Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
<li> Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
<li> Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
<li> Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
<li> Improved: Clarified tcp:receive() in the manual (MPB);
<li> Improved: Decent makefiles (LHF).
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
</ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=old>Old Versions</h2>
<p>
All previous versions of the LuaSocket library can be downloaded <a
href="http://www.impa.br/~diego/software/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="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>
<p>
<small>
Last modified by Diego Nehab on <br>
Tue Jun 11 18:50:23 HKT 2013
</small>
</p>
</center>
</div>
</body>
</html>

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>
@ -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>
<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,14 +36,14 @@
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=dns>DNS</h2>
<h2 id="dns">DNS</h2>
<p>
IPv4 name resolution functions
<a href=#toip><tt>dns.toip</tt></a>
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
<a href="#tohostname"><tt>dns.tohostname</tt></a>
return <em>all</em> information obtained from
the resolver in a table of the form:
</p>
@ -60,10 +60,10 @@ 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
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
returns <em>all</em> information obtained from
the resolver in a table of the form:
</p>
@ -88,82 +88,82 @@ addresses, and <tt>"inet6"</tt> for IPv6 addresses.
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=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 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 class="parameters">
<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
</p>
<p class=return>
<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.
followed by an error message.
</p>
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=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 class="description">
Returns the standard host name for the machine as a string.
</p>
<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=tohostname>
<p class="name" id="tohostname">
socket.dns.<b>tohostname(</b>address<b>)</b>
</p>
<p class=description>
<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 class="parameters">
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
<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.
followed by an error message.
</p>
<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=toip>
<p class="name" id="toip">
socket.dns.<b>toip(</b>address<b>)</b>
</p>
<p class=description>
<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 class="parameters">
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
<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.
message.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<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;

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>
<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,7 +36,7 @@
<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ftp>FTP</h2>
<h2 id="ftp">FTP</h2>
<p>
FTP (File Transfer Protocol) is a protocol used to transfer files
@ -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.ietf.org/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 @@ that is, an URL is a string in the form:
<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>
<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>
<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,12 +36,12 @@
<!-- 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,
@ -50,16 +50,16 @@ implementation conforms to the HTTP/1.1 standard,
<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>
@ -67,12 +67,12 @@ local http = require("socket.http")
<p>
URLs must conform to
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
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 +97,34 @@ headers = {<br>
<p>
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>).
<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,48 +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.ietf.org/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")
@ -214,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)
@ -232,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")
@ -258,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
@ -266,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.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,
@ -289,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")
@ -309,20 +316,20 @@ r, c = http.request {
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<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

@ -89,7 +89,7 @@ it should be easy to use LuaSocket. Just fire the interpreter and use the
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; socket = require("socket")
&gt; print(socket._VERSION)
--&gt; LuaSocket 3.0-rc1
--&gt; LuaSocket 3.0.0
</pre>
<p> Each module loads their dependencies automatically, so you only need to

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>
<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,52 +173,52 @@ 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")
@ -231,45 +231,45 @@ ltn12.pump.all(
<!-- 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,89 +291,89 @@ 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")
@ -386,31 +386,41 @@ ltn12.pump.all(
<!-- 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>
<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;

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>
<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,14 +36,14 @@
<!-- 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
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>,
@ -52,17 +52,17 @@ MIME is described mainly in
</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,10 +454,10 @@ marker.
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<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;
@ -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>
<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>
@ -92,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>
@ -147,6 +148,7 @@ Support, Manual">
<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>,
@ -158,11 +160,14 @@ Support, Manual">
<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#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#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>
@ -183,6 +188,7 @@ Support, Manual">
<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>,
@ -203,6 +209,7 @@ Support, Manual">
<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>,
@ -231,10 +238,10 @@ Support, Manual">
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<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;

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>
<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,14 +37,14 @@ 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,
@ -54,19 +54,19 @@ 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.ietf.org/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>
@ -92,201 +92,40 @@ headers = {<br>
<p>
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>).
<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.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper
use of these headers. Here is a summary of what it says:
</p>
<ul>
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
of the message;
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
making a copy on a typewriter using carbon paper) contains the
addresses of others who are to receive the message, though the
content of the message may not be directed at them;
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.
</ul>
<p class=note>
The LuaSocket <tt>send</tt> function does not care or interpret the
headers you send, but it gives you full control over what is sent and
to whom it is sent:
</p>
<ul>
<li> If someone is to receive the message, the e-mail address <em>has</em>
to be in the recipient list. This is the only parameter that controls who
gets a copy of the message;
<li> If there are multiple recipients, none of them will automatically
know that someone else got that message. That is, the default behavior is
similar to the <tt>Bcc</tt> field of popular e-mail clients;
<li> It is up to you to add the <tt>To</tt> header with the list of primary
recipients so that other recipients can see it;
<li> It is also up to you to add the <tt>Cc</tt> header with the
list of additional recipients so that everyone else sees it;
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
empty. Otherwise, everyone receiving the message will see it and that is
exactly what you <em>don't</em> want to happen!
</ul>
<p class=note>
I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
and
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
</p>
<pre class=example>
-- load the smtp support
local smtp = require("socket.smtp")
-- Connects to server "localhost" and sends a message to users
-- "fulano@example.com", "beltrano@example.com",
-- and "sicrano@example.com".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
from = "&lt;luasocket@example.com&gt;"
rcpt = {
"&lt;fulano@example.com&gt;",
"&lt;beltrano@example.com&gt;",
"&lt;sicrano@example.com&gt;"
}
mesgt = {
headers = {
to = "Fulano da Silva &lt;fulano@example.com&gt;",
cc = '"Beltrano F. Nunes" &lt;beltrano@example.com&gt;',
subject = "My first message"
},
body = "I hope this works. If it does, I can send you another 1000 copies."
}
r, e = smtp.send{
from = from,
rcpt = rcpt,
source = smtp.message(mesgt)
}
</pre>
<!-- 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,12 +231,175 @@ 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>
<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;

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: The core namespace">
<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support">
<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>
@ -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="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
<tr><td align="center" valign="top">Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<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,47 +36,71 @@
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=socket>The socket namespace</h2>
<h2 id="socket">The socket namespace</h2>
<p>
The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
</p>
<p>
<p>
To obtain the <tt>socket</tt> namespace, run:
</p>
<pre class=example>
-- loads the socket module
<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>
<p class="name" id="bind">
socket.<b>bind(</b>address, port [, backlog]<b>)</b>
</p>
<p class=description>
<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
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).
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>"
<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>
<p class="name" id="connect">
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p>
<p class=description>
<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
@ -90,91 +114,79 @@ of connect are defined as simple helper functions that restrict the
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
<p class="name" id="debug">
socket.<b>_DEBUG</b>
</p>
<p class=description>
<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>
<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 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>
<pre class="example">
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- socket.headers ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<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>
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry>
<p class="name" id="newtry">
socket.<b>newtry(</b>finalizer<b>)</b>
</p>
<p class=description>
Creates and returns a <em>clean</em>
<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.
function that allows for cleanup before the exception
is raised.
</p>
<p class=parameters>
<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.
<tt>try</tt> throws the exception.
</p>
<p class=return>
The function returns your customized <tt>try</tt> function.
<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 class="note">
Note: This idea saved a <em>lot</em> of work with the
implementation of protocols in LuaSocket:
</p>
<pre class=example>
<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
-- do everything reassured c will be closed
try(c:send("hello there?\r\n"))
local answer = try(c:receive())
...
@ -186,46 +198,40 @@ end)
<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=protect>
<p class="name" id="protect">
socket.<b>protect(</b>func<b>)</b>
</p>
<p class=description>
<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
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 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 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>
<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 class="description">
Waits for a number of sockets to change status.
</p>
<p class=parameters>
<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
@ -236,208 +242,226 @@ 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
<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
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.
changed status.
</p>
<p class=note>
<b>Note: </b>: <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
<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
<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>
<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.
<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>
<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>
<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>
<p class="name" id="sink">
socket.<b>sink(</b>mode, socket<b>)</b>
</p>
<p class=description>
Creates an
<p class="description">
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink from a stream socket object.
sink from a stream socket object.
</p>
<p class=parameters>
<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;
<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;
socket, closing the socket when done;</li>
<li> <tt>"keep-open"</tt>: sends all received data through the
socket, leaving it open when done.
socket, leaving it open when done.</li>
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to send the data.
<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 class="return">
The function returns a sink with the appropriate behavior.
</p>
<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=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>
<p class="description">
Drops a number of arguments and returns the remaining.
</p>
<p class=parameters>
<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>
<p class="return">
The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
</p>
<p class=note>
<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
<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>
<p class="name" id="sleep">
socket.<b>sleep(</b>time<b>)</b>
</p>
<p class=description>
<p class="description">
Freezes the program execution during a given amount of time.
</p>
<p class=parameters>
<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>
<p class="name" id="source">
socket.<b>source(</b>mode, socket [, length]<b>)</b>
</p>
<p class=description>
Creates an
<p class="description">
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source from a stream socket object.
source from a stream socket object.
</p>
<p class=parameters>
<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;
<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>;
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.
side closes the connection.</li>
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to receive the data.
<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 class="return">
The function returns a source with the appropriate behavior.
</p>
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setsize>
socket.<b>_SETSIZE</b>
<p class="name" id="socketinvalid">
socket.<b>_SOCKETINVALID</b>
</p>
<p class=description>
The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle.
<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>
<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 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>
<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>.
arguments, but are usually the return values of a function call
nested with <tt>try</tt>.
</p>
<p class=return>
<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>.
<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>
<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>
<p class="name" id="version">
socket.<b>_VERSION</b>
</p>
<p class=description>
This constant has a string describing the current LuaSocket version.
<p class="description">
This constant has a string describing the current LuaSocket version.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<div class="footer">
<hr>
<center>
<p class=bar>
<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;

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: The TCP/IP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<title>LuaSocket: TCP/IP support</title>
<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>
<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,305 +36,351 @@
<!-- 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 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>
<h2 id="tcp">TCP</h2>
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="accept">
<p class="name" id="accept">
server:<b>accept()</b>
</p>
<p class=description>
<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.
<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
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>
<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.
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">
<p class="name" id="bind">
master:<b>bind(</b>address, port<b>)</b>
</p>
<p class=description>
<p class="description">
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host.
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).
<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.
<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port.
chooses an ephemeral port.
</p>
<p class=return>
<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>
<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">
<p class="name" id="close">
master:<b>close()</b><br>
client:<b>close()</b><br>
server:<b>close()</b>
</p>
<p class=description>
<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.
a closed socket.
</p>
<p class=note>
<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.
automatically closed before destruction, though.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="connect">
<p class="name" id="connect">
master:<b>connect(</b>address, port<b>)</b>
</p>
<p class=description>
<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>.
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 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>
<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>
<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
<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
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>
<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> or <a
href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
the appropriate family are tried in succession until the
first success or until the last failure.
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">
<p class="name" id="getpeername">
client:<b>getpeername()</b>
</p>
<p class=description>
<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 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>
<p class="note">
Note: It makes no sense to call this method on server objects.
</p>
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="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 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>").
<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">
<p class="name" id="getstats">
master:<b>getstats()</b><br>
client:<b>getstats()</b><br>
server:<b>getstats()</b><br>
</p>
<p class=description>
<p class="description">
Returns accounting information on the socket, useful for throttling
of bandwidth.
of bandwidth.
</p>
<p class=return>
<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.
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">
<p class="name" id="listen">
master:<b>listen(</b>backlog<b>)</b>
</p>
<p class=description>
<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.
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
<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>
<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">
<p class="name" id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p>
<p class=description>
<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.
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 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;
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> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket.
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>
<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>
<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
@ -344,33 +390,33 @@ 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>
<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
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.
too.
</p>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="send">
<p class="name" id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b>
</p>
<p class=description>
<p class="description">
Sends <tt>data</tt> through client object.
</p>
<p class=parameters>
<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
<tt>string.sub</tt> Lua function to allow the selection of a
substring to be sent.
</p>
<p class=return>
<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
@ -384,36 +430,36 @@ 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 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">
<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>
<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.
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 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;
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
@ -424,104 +470,88 @@ 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;
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;
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> '<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.
sending and receiving only IPv6 packets.</li>
</ul>
<p class=return>
<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>
<p class="note">
Note: The descriptions above come from the man pages.
</p>
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getoption">
client:<b>getoption(</b>option)</b><br>
server:<b>getoption(</b>option)</b>
</p>
<p class=description>
Gets options for the TCP object.
See <a href=#setoption><tt>setoption</tt></a> for description of the
option names and values.
</p>
<p class=parameters>
<tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>keepalive</tt>'
<li> '<tt>linger</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>tcp-nodelay</tt>'
</ul>
<p class=return>
The method returns the option <tt>value</tt> in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="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>
<p class="description">
Resets accounting information on the socket, useful for throttling
of bandwidth.
of bandwidth.
</p>
<p class=parameters>
<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 class="return">
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="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>
<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>
<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>
<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:
both can be used together for fine tuning:
</p>
<ul>
@ -532,15 +562,15 @@ 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>
a call.</li>
</ul>
<p class=parameters>
<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>
<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
@ -549,7 +579,7 @@ and perform automatic name resolution might be blocked by the resolver for
longer than the specified timeout value.
</p>
<p class=note>
<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.
@ -557,94 +587,138 @@ contained verbs making their imperative nature obvious.
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="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 class="description">
Shuts down part of a full-duplex connection.
</p>
<p class=parameters>
<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.
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>
<p class="return">
This function returns 1.
</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, any use is unlikely to be portable.</b>
</p>
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getfd">
master:<b>getfd()</b><br>
client:<b>getfd()</b><br>
server:<b>getfd()</b>
</p>
<p class=description>
Returns the underling socket descriptor or handle associated to the object.
</p>
<p class=return>
The descriptor or handle. In case the object has been closed, the return will be -1.
</p>
<p class=note>
Note: <b>This is an internal method, any use is unlikely to be portable.</b>
</p>
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setfd">
<p class="name" id="setfd">
master:<b>setfd(</b>fd<b>)</b><br>
client:<b>setfd(</b>fd<b>)</b><br>
server:<b>setfd(</b>fd<b>)</b>
</p>
<p class=description>
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
<p 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>
<p class="return">
No return value.
</p>
<p class=note>
Note: <b>This is an internal method, any use is unlikely to be portable.</b>
<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>
<div class="footer">
<hr>
<center>
<p class=bar>
<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;

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>
<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,74 +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 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>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="udp">UDP</h2>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -129,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">
@ -141,11 +108,11 @@ associated with a connected UDP 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 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">
@ -164,10 +131,10 @@ 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>").
<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>
@ -179,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">
@ -199,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">
@ -217,46 +199,12 @@ 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).
</p>
<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getoption">
connected:<b>getoption()</b><br>
unconnected:<b>getoption()</b>
</p>
<p class="description">
Gets an option value from the UDP object.
See <a href=#setoption><tt>setoption</tt></a> for
description of the option names and values.
</p>
<p class="parameters"><tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>dontroute</tt>'
<li> '<tt>broadcast</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>reuseport</tt>'
<li> '<tt>ip-multicast-loop</tt>'
<li> '<tt>ipv6-v6only</tt>'
<li> '<tt>ip-multicast-if</tt>'
<li> '<tt>ip-multicast-ttl</tt>'
<li> '<tt>ip-add-membership</tt>'
<li> '<tt>ip-drop-membership</tt>'
</ul>
</p>
<p class=return>
The method returns the option <tt>value</tt> in case of
success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="send">
@ -268,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.
@ -298,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.
@ -320,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">
@ -337,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>
@ -364,11 +381,11 @@ is recommended when the same peer is used for several transmissions
and can result in up to 30% performance gains.
</p>
<p class=note>
<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
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>
@ -406,74 +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>': Indicates that outgoing
messages should bypass the standard routing facilities.
Receives a boolean value;
<li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket.
Receives a boolean value;
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
validating addresses supplied in a <tt>bind()</tt> call
should allow reuse of local addresses.
Receives a boolean value;
<li> '<tt>reuseport</tt>': Allows completely duplicate
bindings by multiple processes if they all set
'<tt>reuseport</tt>' before binding the port.
Receives a boolean value;
<li> '<tt>ip-multicast-loop</tt>':
Specifies whether or not a copy of an outgoing multicast
datagram is delivered to the sending host as long as it is a
member of the multicast group.
Receives a boolean value;
<li> '<tt>ipv6-v6only</tt>':
Specifies whether to restrict <tt>inet6</tt> sockets to
sending and receiving only IPv6 packets.
Receive a boolean value;
<li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams
are sent.
Receives an IP address;
<li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing
multicast datagrams.
Receives a number;
<li> '<tt>ip-add-membership</tt>':
Joins the multicast group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address;
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address.
</ul>
<p class="return">
The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="settimeout">
@ -482,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">
@ -514,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>
<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

@ -5,7 +5,7 @@ local ltn12 = require"ltn12"
local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
local function unquote(t, quoted)
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]
@ -14,19 +14,19 @@ end
local function parse_set_cookie(c, quoted, cookie_table)
c = c .. ";$last=last;"
local _, __, n, v, i = string.find(c, "(" .. token_class ..
local _, _, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=%s*(.-)%s*;%s*()")
local cookie = {
name = n,
value = unquote(v, quoted),
name = n,
value = unquote(v, quoted),
attributes = {}
}
while 1 do
_, __, n, v, i = string.find(c, "(" .. token_class ..
_, _, 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,
name = n,
value = unquote(v, quoted)
}
end
@ -46,8 +46,8 @@ local function split_set_cookie(s, cookie_table)
-- split into individual cookies
i = 1
while 1 do
local _, __, cookie, next_token
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
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)
@ -62,12 +62,12 @@ local function quote(s)
end
local _empty = {}
local function build_cookies(cookies)
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
if v.value and v.value ~= "" then
s = s .. '=' .. quote(v.value)
end
end
@ -83,6 +83,6 @@ local function build_cookies(cookies)
end
if i < #cookies then s = s .. ", " end
end
return s
return s
end

View File

@ -5,6 +5,7 @@
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local string = require("string")
local socket = require("socket")
local coroutine = require("coroutine")
module("dispatch")
@ -43,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, ...)}
local status = table.remove(results, 1)
if not status then
if base.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

View File

@ -71,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))

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

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

View File

@ -1,104 +0,0 @@
package = "LuaSocket"
version = "scm-0"
source = {
url = "https://github.com/diegonehab/luasocket/archive/master.zip",
dir = "luasocket-master",
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
},
mingw32 = {
"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" }
}

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 +1 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/diego/build/macosx/include LUAPREFIX_macosx=/Users/diego/build/macosx install-both
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/$USER/build/macosx/include LUAPREFIX_macosx=/Users/$USER/build/macosx install-both

26
makefile Normal file → Executable file
View File

@ -5,12 +5,12 @@
# Targets:
# install install system independent support
# install-unix also install unix-only support
# install-both install for both lua5.1 and lua5.2
# install-both-unix also install unix-only
# install-both install for lua51 lua52 lua53
# install-both-unix also install unix-only
# print print the build settings
PLAT?= linux
PLATS= macosx linux win32 mingw
PLATS= macosx linux win32 win64 mingw freebsd solaris
all: $(PLAT)
@ -24,20 +24,32 @@ test:
lua test/hello.lua
install-both:
$(MAKE) clean
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install LUAV=5.1
$(MAKE) clean
$(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
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install-unix LUAV=5.1
$(MAKE) clean
$(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

View File

@ -1,7 +1,7 @@
#--------------------------------------------------------------------------
# Distribution makefile
#--------------------------------------------------------------------------
DIST = luasocket-3.0-rc1
DIST = luasocket-3.0.0
TEST = \
test/README \
@ -92,29 +92,29 @@ MAKE = \
socket.vcxproj \
mime.vcxproj
DOC = \
doc/dns.html \
doc/ftp.html \
doc/index.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
@ -123,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,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -20,19 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\mime.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\mime.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
<ClCompile Include="src\compat.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>
@ -41,22 +29,22 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -87,7 +75,7 @@
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir>
<OutDir>$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
@ -95,23 +83,23 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir>
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir>
<OutDir>$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir>
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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>
@ -122,9 +110,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
@ -138,7 +126,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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>
@ -149,9 +137,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
@ -163,7 +151,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
@ -172,9 +160,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
@ -187,7 +175,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
@ -198,9 +186,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\mime.c" />
</ItemGroup>
<ItemGroup>
<Filter Include="cdir">
<UniqueIdentifier>{fad87a86-297c-4881-a114-73b967bb3c92}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\mime.lua">
<Filter>cdir</Filter>
</CustomBuild>
</ItemGroup>
</Project>

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,7 +26,7 @@ function parse(body)
data[key] = value
end
end
return data, code, message
return data, code, message
end
local host = socket.dns.gethostname()

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -21,6 +21,7 @@
<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" />
@ -32,98 +33,6 @@
<ClCompile Include="src\udp.c" />
<ClCompile Include="src\wsocket.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ltn12.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
<CustomBuild Include="src\socket.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ftp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\headers.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\http.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\smtp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\tp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\url.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
@ -131,22 +40,22 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -177,7 +86,7 @@
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir>
<OutDir>$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
@ -185,23 +94,23 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir>
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir>
<OutDir>$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir>
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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>
@ -212,9 +121,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
@ -228,7 +137,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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>
@ -239,9 +148,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
@ -253,7 +162,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
@ -262,9 +171,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
@ -277,7 +186,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
@ -288,9 +197,9 @@
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\auxiliar.c" />
<ClCompile Include="src\buffer.c" />
<ClCompile Include="src\except.c" />
<ClCompile Include="src\inet.c" />
<ClCompile Include="src\io.c" />
<ClCompile Include="src\luasocket.c" />
<ClCompile Include="src\options.c" />
<ClCompile Include="src\select.c" />
<ClCompile Include="src\tcp.c" />
<ClCompile Include="src\timeout.c" />
<ClCompile Include="src\udp.c" />
<ClCompile Include="src\wsocket.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ltn12.lua">
<Filter>cdir</Filter>
</CustomBuild>
<CustomBuild Include="src\socket.lua">
<Filter>cdir</Filter>
</CustomBuild>
<CustomBuild Include="src\ftp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\headers.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\http.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\smtp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\tp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\url.lua">
<Filter>ldir</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Filter Include="cdir">
<UniqueIdentifier>{b053460d-5439-4e3a-a2eb-c31a95b5691f}</UniqueIdentifier>
</Filter>
<Filter Include="ldir">
<UniqueIdentifier>{b301b82c-37cb-4e05-9333-194e92ed7a62}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -2,14 +2,11 @@
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include <string.h>
#include <stdio.h>
#include "auxiliar.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes the module
\*-------------------------------------------------------------------------*/
@ -26,7 +23,7 @@ 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 */
@ -84,7 +81,7 @@ int auxiliar_checkboolean(lua_State *L, int 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) {
@ -98,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) {
@ -121,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) {
@ -139,11 +136,11 @@ 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);
}
/*-------------------------------------------------------------------------*\
@ -151,8 +148,7 @@ void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
* 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,
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,22 +26,29 @@
* "class" with the class name.
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
* 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);
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

@ -2,9 +2,7 @@
* Input/Output interface for Lua programs
* LuaSocket toolkit
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "buffer.h"
/*=========================================================================*\
@ -37,7 +35,7 @@ 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;
@ -61,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, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) 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;
@ -78,9 +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);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
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,7 +85,7 @@ 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_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, (lua_Number) (sent+start-1));
@ -98,7 +94,7 @@ int buffer_meth_send(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;
}
@ -107,14 +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);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
/* 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);
@ -122,12 +119,12 @@ 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
/* get a fixed number of bytes (minus what was already partially
* received) */
} else {
double n = lua_tonumber(L, 2);
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)
@ -138,8 +135,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
/* 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 {
@ -149,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;
}
@ -222,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) {
@ -252,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

@ -15,8 +15,7 @@
* 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.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "io.h"
#include "timeout.h"
@ -34,12 +33,20 @@ typedef struct t_buffer_ {
} 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

@ -2,12 +2,18 @@
* Simple exception support
* LuaSocket toolkit
\*=========================================================================*/
#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.
@ -29,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);
@ -48,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;
}
@ -64,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;
}
@ -92,10 +121,9 @@ static int global_protect(lua_State *L) {
* Init module
\*-------------------------------------------------------------------------*/
int except_open(lua_State *L) {
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
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,25 +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.
*
* 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

@ -23,7 +23,7 @@ local _M = socket.ftp
-- timeout in seconds before the program gives up on a connection
_M.TIMEOUT = 60
-- default port for ftp service
_M.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.
_M.USER = "ftp"
@ -35,7 +35,7 @@ _M.PASSWORD = "anonymous@anonymous.org"
local metat = { __index = {} }
function _M.open(server, port, create)
local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, 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)
@ -51,12 +51,12 @@ end
function metat.__index:pasvconnect()
self.data = self.try(socket.tcp())
self.try(self.data:settimeout(_M.TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
end
function metat.__index:login(user, password)
self.try(self.tp:command("user", user or _M.USER))
local code, reply = self.try(self.tp:check{"2..", 331})
local code, _ = self.try(self.tp:check{"2..", 331})
if code == 331 then
self.try(self.tp:command("pass", password or _M.PASSWORD))
self.try(self.tp:check("2.."))
@ -66,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())
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
@ -109,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)
@ -207,7 +240,7 @@ local function tput(putt)
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()
@ -219,7 +252,7 @@ local default = {
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")
@ -232,8 +265,10 @@ 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
@ -250,14 +285,14 @@ local function tget(gett)
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)
@ -268,11 +303,20 @@ _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)
@ -282,4 +326,4 @@ _M.get = socket.protect(function(gett)
else return tget(gett) end
end)
return _M
return _M

View File

@ -22,12 +22,25 @@ local _M = socket.http
-- Program constants
-----------------------------------------------------------------------------
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
_M.PORT = 80
_M.TIMEOUT = 60
-- user agent field sent in request
_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
-----------------------------------------------------------------------------
@ -76,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
@ -108,13 +121,13 @@ local metat = { __index = {} }
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(_M.TIMEOUT))
h.try(c:connect(host, port or _M.PORT))
h.try(c:connect(host, port))
-- here everything worked
return h
end
@ -144,10 +157,15 @@ function metat.__index:sendbody(headers, source, step)
end
function metat.__index:receivestatusline()
local status = self.try(self.c:receive(5))
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 return nil, status end
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)"))
@ -186,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,
@ -198,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
@ -209,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"] = _M.USERAGENT,
["host"] = reqt.host,
["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
@ -229,10 +261,8 @@ end
-- default url parts
local default = {
host = "",
port = _M.PORT,
path ="/",
scheme = "http"
path ="/"
, scheme = "http"
}
local function adjustrequest(reqt)
@ -240,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
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)
@ -272,17 +323,24 @@ end
local trequest, tredirect
--[[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
@ -299,23 +357,25 @@ end
h:sendheaders(nreqt.headers)
-- 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
headers = h:receiveheaders()
while code == 100 do
h:receiveheaders()
code, status = h:receivestatusline()
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)
@ -328,11 +388,13 @@ end
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)
@ -342,8 +404,15 @@ 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
_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)
@ -351,4 +420,5 @@ _M.request = socket.protect(function(reqt, body)
else return trequest(reqt) end
end)
return _M
_M.schemes = SCHEMES
return _M

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

@ -2,15 +2,13 @@
* Internet domain functions
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "inet.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "inet.h"
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
@ -31,9 +29,6 @@ static luaL_Reg func[] = {
{ NULL, NULL}
};
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
@ -41,11 +36,7 @@ int inet_open(lua_State *L)
{
lua_pushstring(L, "dns");
lua_newtable(L);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
lua_settable(L, -3);
return 0;
}
@ -97,7 +88,7 @@ static int inet_global_getnameinfo(lua_State *L) {
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
hints.ai_family = AF_UNSPEC;
ret = getaddrinfo(host, serv, &hints, &resolved);
if (ret != 0) {
@ -108,8 +99,8 @@ static int inet_global_getnameinfo(lua_State *L) {
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,
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);
@ -149,7 +140,7 @@ static int inet_global_toip(lua_State *L)
int inet_optfamily(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
@ -170,7 +161,7 @@ static int inet_global_getaddrinfo(lua_State *L)
int i = 1, ret = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
hints.ai_family = AF_UNSPEC;
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
@ -180,9 +171,10 @@ static int inet_global_getaddrinfo(lua_State *L)
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,
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;
@ -200,6 +192,16 @@ static int inet_global_getaddrinfo(lua_State *L)
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);
@ -251,17 +253,16 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
lua_pushstring(L, LUA_GAI_STRERROR(err));
return 2;
}
lua_pushstring(L, name);
lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
if (family == PF_INET) {
lua_pushliteral(L, "inet");
} else if (family == PF_INET6) {
lua_pushliteral(L, "inet6");
} else {
lua_pushliteral(L, "uknown family");
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;
}
@ -281,21 +282,20 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
lua_pushstring(L, socket_strerror(errno));
return 2;
}
err=getnameinfo((struct sockaddr *)&peer, peer_len,
err=getnameinfo((struct sockaddr *)&peer, peer_len,
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
lua_pushstring(L, LUA_GAI_STRERROR(err));
return 2;
}
lua_pushstring(L, name);
lua_pushstring(L, port);
if (family == PF_INET) {
lua_pushliteral(L, "inet");
} else if (family == PF_INET6) {
lua_pushliteral(L, "inet6");
} else {
lua_pushliteral(L, "uknown family");
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;
}
@ -346,8 +346,13 @@ 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 family, int type) {
return socket_strerror(socket_create(ps, family, 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;
}
/*-------------------------------------------------------------------------*\
@ -356,21 +361,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) {
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
{
switch (family) {
case PF_INET: {
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,
return socket_strerror(socket_connect(ps, (SA *) &sin,
sizeof(sin), tm));
}
case PF_INET6: {
case AF_INET6: {
struct sockaddr_in6 sin6;
struct in6_addr addrany = IN6ADDR_ANY_INIT;
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,
return socket_strerror(socket_connect(ps, (SA *) &sin6,
sizeof(sin6), tm));
}
}
@ -385,6 +390,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
{
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
int current_family = *family;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv,
connecthints, &resolved));
@ -399,23 +405,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
* that shows up while iterating. if there was a
* bind, all families will be the same and we will
* not enter this branch. */
if (*family != iterator->ai_family) {
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
socket_destroy(ps);
err = socket_strerror(socket_create(ps, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol));
if (err != NULL) {
freeaddrinfo(resolved);
return err;
}
*family = iterator->ai_family;
/* all sockets initially non-blocking */
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);
}
/* try connecting to remote address */
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
/* 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 */
@ -425,29 +431,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
/*-------------------------------------------------------------------------*\
* Tries to accept a socket
\*-------------------------------------------------------------------------*/
const char *inet_tryaccept(p_socket server, int family, p_socket client,
p_timeout tm)
{
const char *inet_tryaccept(p_socket server, int family, p_socket client,
p_timeout tm) {
socklen_t len;
t_sockaddr_storage addr;
if (family == PF_INET6) {
len = sizeof(struct sockaddr_in6);
} else {
len = sizeof(struct sockaddr_in);
}
return socket_strerror(socket_accept(server, client, (SA *) &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, const char *serv,
struct addrinfo *bindhints)
{
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;
t_socket sock = *ps;
int current_family = *family;
/* translate luasocket special values to C */
if (strcmp(address, "*") == 0) address = NULL;
if (!serv) serv = "0";
@ -459,35 +463,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
}
/* iterate over resolved addresses until one is good */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
if(sock == SOCKET_INVALID) {
err = socket_strerror(socket_create(&sock, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol));
if(err)
continue;
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(&sock,
(SA *) iterator->ai_addr,
err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen));
/* keep trying unless bind succeeded */
if (err) {
if(sock != *ps)
socket_destroy(&sock);
} else {
/* remember what we connected to, particularly the family */
*bindhints = *iterator;
if (err == NULL) {
*family = current_family;
/* set to non-blocking after bind */
socket_setnonblocking(ps);
break;
}
}
/* cleanup and return error */
freeaddrinfo(resolved);
*ps = sock;
/* here, if err is set, we failed */
return err;
}
/*-------------------------------------------------------------------------*\
* Some systems do not provide these so that we provide our own.
* Some systems do not provide these so that we provide our own.
\*-------------------------------------------------------------------------*/
#ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
@ -512,7 +513,7 @@ 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)
int inet_pton(int af, const char *src, void *dst)
{
struct addrinfo hints, *res;
int ret = 1;
@ -529,7 +530,7 @@ int inet_pton(int af, const char *src, void *dst)
} else {
ret = -1;
}
freeaddrinfo(res);
freeaddrinfo(res);
return ret;
}

View File

@ -1,12 +1,12 @@
#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
@ -14,7 +14,7 @@
*
* The Lua functions toip and tohostname are also implemented here.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "socket.h"
#include "timeout.h"
@ -22,21 +22,23 @@
#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 family, int type);
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints);
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints);
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
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 family);
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
int inet_optfamily(lua_State* L, int narg, const char* def);
int inet_optsocktype(lua_State* L, int narg, const char* def);
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);
@ -47,4 +49,8 @@ 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

@ -2,11 +2,9 @@
* Input/Output abstraction
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "io.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
@ -25,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

@ -12,9 +12,7 @@
* The module socket.h implements this interface, and thus the module tcp.h
* is very simple.
\*=========================================================================*/
#include <stdio.h>
#include "lua.h"
#include "luasocket.h"
#include "timeout.h"
/* IO error codes */
@ -22,7 +20,7 @@ enum {
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_UNKNOWN = -3
IO_UNKNOWN = -3
};
/* interface to error message function */
@ -58,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

@ -9,10 +9,13 @@
-----------------------------------------------------------------------------
local string = require("string")
local table = require("table")
local unpack = unpack or table.unpack
local base = _G
local select = select
local _M = {}
if module then -- heuristic for exporting a global package table
ltn12 = _M
ltn12 = _M -- luacheck: ignore
end
local filter,source,sink,pump = {},{},{},{}
@ -124,6 +127,16 @@ function source.string(s)
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)
@ -139,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"
@ -254,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

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

@ -12,16 +12,6 @@
* standard Lua read and write functions.
\*=========================================================================*/
/*=========================================================================*\
* Standard include files
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
/*=========================================================================*\
* LuaSocket includes
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include "except.h"
@ -64,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;
}
@ -78,26 +68,14 @@ static int global_unload(lua_State *L) {
return 0;
}
#if LUA_VERSION_NUM > 501
int luaL_typerror (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);
}
#endif
/*-------------------------------------------------------------------------*\
* Setup basic stuff.
\*-------------------------------------------------------------------------*/
static int base_open(lua_State *L) {
if (socket_open()) {
/* export functions (and leave namespace table on top of stack) */
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_newtable(L);
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, "socket", func, 0);
#endif
#ifdef LUASOCKET_DEBUG
lua_pushstring(L, "_DEBUG");
lua_pushboolean(L, 1);

View File

@ -6,20 +6,27 @@
* Diego Nehab
* 9/11/1999
\*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\
/*-------------------------------------------------------------------------* \
* Current socket library version
\*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 3.0-rc1"
#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.

199
src/makefile Normal file → Executable file
View File

@ -12,51 +12,62 @@
#
# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
# PLAT: linux macosx win32 mingw
# PLAT: linux macosx win32 win64 mingw
# platform to build for
PLAT?=linux
# LUAV: 5.1 5.2
# 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
# COMPAT: COMPAT NOCOMPAT
# when compiling for 5.2, use LUA_COMPAT_MODULE
COMPAT?=NOCOMPAT
# 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?=$(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?=$(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:
# LUAINC_mingw:
# /opt/local/include
LUAINC_mingw_base?=/usr/include
LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV)
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
@ -67,13 +78,32 @@ LDIR_mingw?=lua/$(LUAV)/lua
# LUAINC_win32:
# LUALIB_win32:
# where lua headers and libraries are found for win32 builds
LUAINC_win32_base?=
LUAINC_win32?=$(LUAINC_win32_base)/lua/$(LUAV)
PLATFORM_win32?=Release
LUAPREFIX_win32?=
CDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)
LDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)/lua
LUALIB_win32?=$(LUAPREFIX_win32)/lua/$(LUAV)/$(PLATFORM_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
@ -84,7 +114,7 @@ LDIR?=$(LDIR_$(PLAT))
# DESTDIR: (no default)
# used by package managers to install into a temporary destination
DESTDIR=
DESTDIR?=
#------
# Definitions below can be overridden on the make command line, but
@ -117,11 +147,13 @@ print:
@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 mingw
PLATS= macosx linux win32 win64 mingw solaris
#------
# Compiler and linker settings
@ -129,14 +161,10 @@ PLATS= macosx linux win32 mingw
SO_macosx=so
O_macosx=o
CC_macosx=gcc
DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN -DLUA_$(COMPAT)_MODULE \
-DLUASOCKET_API='__attribute__((visibility("default")))' \
-DUNIX_API='__attribute__((visibility("default")))' \
-DMIME_API='__attribute__((visibility("default")))'
CFLAGS_macosx= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
-fvisibility=hidden
LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; 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
#------
@ -145,28 +173,49 @@ SOCKET_macosx=usocket.o
SO_linux=so
O_linux=o
CC_linux=gcc
DEF_linux=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
-DLUASOCKET_API='__attribute__((visibility("default")))' \
-DUNIX_API='__attribute__((visibility("default")))' \
-DMIME_API='__attribute__((visibility("default")))'
CFLAGS_linux= -I$(LUAINC) $(DEF) -pedantic -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
LDFLAGS_linux=-O -shared -fpic -o
DEF_linux=-DLUASOCKET_$(DEBUG)
CFLAGS_linux=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_linux=-O -shared -fpic -o
LD_linux=gcc
SOCKET_linux=usocket.o
#------
# Compiler and linker settings
# for FreeBSD
SO_freebsd=so
O_freebsd=o
CC_freebsd=gcc
DEF_freebsd=-DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
CFLAGS_freebsd=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_freebsd=-O -shared -fpic -o
LD_freebsd=gcc
SOCKET_freebsd=usocket.o
#------
# Compiler and linker settings
# for Solaris
SO_solaris=so
O_solaris=o
CC_solaris=gcc
DEF_solaris=-DLUASOCKET_$(DEBUG)
CFLAGS_solaris=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic
LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o
LD_solaris=gcc
SOCKET_solaris=usocket.o
#------
# Compiler and linker settings
# for MingW
SO_mingw=dll
O_mingw=o
CC_mingw=gcc
DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
-DWINVER=0x0501 -DLUASOCKET_API='__declspec(dllexport)' \
-DMIME_API='__declspec(dllexport)'
CFLAGS_mingw= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
-fvisibility=hidden
LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
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
@ -178,20 +227,41 @@ SO_win32=dll
O_win32=obj
CC_win32=cl
DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
//D "LUASOCKET_API=__declspec(dllexport)" //D "_CRT_SECURE_NO_WARNINGS" \
//D "_WINDLL" //D "LUA_$(COMPAT)_MODULE" \
//D "MIME_API=__declspec(dllexport)" \
//D "LUASOCKET_$(DEBUG)"
CFLAGS_win32=//I "$(LUAINC)" $(DEF) //O2 //Ot //MD //W3 //nologo
//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'" \
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
//MACHINE:X86 /LIBPATH:"$(shell cmd //c echo $(LUALIB))" \
lua$(subst .,,$(LUAV)).lib ws2_32.lib //OUT:
//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:
@ -202,10 +272,10 @@ SOCKET_win32=wsocket.obj
#
SO=$(SO_$(PLAT))
O=$(O_$(PLAT))
SOCKET_V=3.0-rc1
SOCKET_V=3.0.0
MIME_V=1.0.3
SOCKET_SO=socket.$(SO).$(SOCKET_V)
MIME_SO=mime.$(SO).$(MIME_V)
SOCKET_SO=socket-$(SOCKET_V).$(SO)
MIME_SO=mime-$(MIME_V).$(SO)
UNIX_SO=unix.$(SO)
SERIAL_SO=serial.$(SO)
SOCKET=$(SOCKET_$(PLAT))
@ -215,8 +285,8 @@ SOCKET=$(SOCKET_$(PLAT))
#
CC=$(CC_$(PLAT))
DEF=$(DEF_$(PLAT))
CFLAGS=$(CFLAGS_$(PLAT))
LDFLAGS=$(LDFLAGS_$(PLAT))
CFLAGS=$(MYCFLAGS) $(CFLAGS_$(PLAT))
LDFLAGS=$(MYLDFLAGS) $(LDFLAGS_$(PLAT))
LD=$(LD_$(PLAT))
LUAINC= $(LUAINC_$(PLAT))
LUALIB= $(LUALIB_$(PLAT))
@ -230,6 +300,7 @@ SOCKET_OBJS= \
buffer.$(O) \
io.$(O) \
auxiliar.$(O) \
compat.$(O) \
options.$(O) \
inet.$(O) \
$(SOCKET) \
@ -242,7 +313,8 @@ SOCKET_OBJS= \
# Modules belonging mime-core
#
MIME_OBJS= \
mime.$(O)
mime.$(O) \
compat.$(O)
#------
# Modules belonging unix (local domain sockets)
@ -254,13 +326,17 @@ UNIX_OBJS=\
timeout.$(O) \
io.$(O) \
usocket.$(O) \
unixstream.$(O) \
unixdgram.$(O) \
compat.$(O) \
unix.$(O)
#------
# Modules belonging to serial (device streams)
#
SERIAL_OBJS:=\
SERIAL_OBJS=\
buffer.$(O) \
compat.$(O) \
auxiliar.$(O) \
options.$(O) \
timeout.$(O) \
@ -289,18 +365,28 @@ TO_TOP_LDIR= \
#
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"
@ -323,7 +409,7 @@ $(UNIX_SO): $(UNIX_OBJS)
$(SERIAL_SO): $(SERIAL_OBJS)
$(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
install:
install:
$(INSTALL_DIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
@ -349,6 +435,7 @@ clean:
#------
# List of dependencies
#
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

View File

@ -1,8 +1,8 @@
local _M = {}
if module then
mbox = _M
end
mbox = _M -- luacheck: ignore
end
function _M.split_message(message_s)
local message = {}
@ -29,7 +29,7 @@ end
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
@ -49,9 +49,9 @@ function _M.parse_headers(headers_s)
end
function _M.parse_from(from)
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
local _, _, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
if not address then
_, __, address = string.find(from, "%s*(.+)%s*")
_, _, address = string.find(from, "%s*(.+)%s*")
end
name = name or ""
address = address or ""
@ -61,9 +61,10 @@ function _M.parse_from(from)
end
function _M.split_mbox(mbox_s)
mbox = {}
local mbox = {}
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
local nj, i, j = 1, 1, 1
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

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

@ -2,16 +2,10 @@
* MIME support functions
* LuaSocket toolkit
\*=========================================================================*/
#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
@ -33,15 +27,15 @@ 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 *base);
/*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 *class, UC *unbase);
/*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);
@ -61,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
@ -79,21 +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)
{
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_newtable(L);
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, "mime", func, 0);
#endif
/* 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;
}
@ -103,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;
@ -123,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) {
@ -149,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 *unbase)
static void b64setup(UC *unbase)
{
int i;
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;
@ -174,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;
@ -186,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;
@ -203,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;
@ -217,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 */
@ -239,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 */
@ -251,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.
\*-------------------------------------------------------------------------*/
@ -259,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 */
@ -272,9 +364,9 @@ static int mime_global_b64(lua_State *L)
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;
@ -288,7 +380,7 @@ static int mime_global_b64(lua_State *L)
}
/* 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);
@ -305,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 */
@ -318,9 +410,9 @@ static int mime_global_unb64(lua_State *L)
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;
@ -333,7 +425,7 @@ static int mime_global_unb64(lua_State *L)
}
/* 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);
@ -349,20 +441,22 @@ 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 *cl, UC *unbase)
{
int i;
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['\t'] = QP_IF_LAST;
cl[' '] = QP_IF_LAST;
cl['\r'] = QP_CR;
for (i = 0; i < 256; i++) unbase[i] = 255;
@ -374,7 +468,37 @@ static void qpsetup(UC *cl, UC *unbase)
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
@ -388,9 +512,9 @@ static void qpquote(UC c, luaL_Buffer *buffer)
/*-------------------------------------------------------------------------*\
* 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;
@ -431,7 +555,7 @@ 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)
{
@ -448,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;
@ -473,7 +596,7 @@ static int mime_global_qp(lua_State *L)
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);
@ -493,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;
@ -501,8 +624,8 @@ 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 */
@ -512,7 +635,7 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
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:
@ -525,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 */
@ -548,14 +671,14 @@ static int mime_global_unqp(lua_State *L)
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)
@ -568,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
\*-------------------------------------------------------------------------*/
@ -578,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;
@ -603,11 +726,11 @@ static int mime_global_qpwrp(lua_State *L)
if (left <= 3) {
left = length;
luaL_addstring(&buffer, EQCRLF);
}
}
luaL_addchar(&buffer, *input);
left--;
break;
default:
default:
if (left <= 1) {
left = length;
luaL_addstring(&buffer, EQCRLF);
@ -635,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)) {
@ -653,15 +776,15 @@ static int eolprocess(int c, int last, const char *marker,
}
/*-------------------------------------------------------------------------*\
* 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;
@ -683,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_addchar(buffer, (char) c);
switch (c) {
case '\r':
case '\r':
return 1;
case '\n':
return (state == 1)? 2: 0;
case '.':
if (state == 2)
case '\n':
return (state == 1)? 2: 0;
case '.':
if (state == 2)
luaL_addchar(buffer, '.');
/* Falls through. */
default:
return 0;
}
@ -719,7 +843,7 @@ 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, (lua_Number) state);

View File

@ -8,7 +8,7 @@
* and formatting conforming to RFC 2045. It is used by mime.lua, which
* provide a higher level interface to this functionality.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
/*-------------------------------------------------------------------------*\
* Current MIME library version
@ -17,13 +17,6 @@
#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 */

View File

@ -10,8 +10,6 @@
local base = _G
local ltn12 = require("ltn12")
local mime = require("mime.core")
local io = require("io")
local string = require("string")
local _M = mime
-- encode, decode and wrap algorithm tables
@ -19,7 +17,7 @@ local encodet, decodet, wrapt = {},{},{}
_M.encodet = encodet
_M.decodet = decodet
_M.wrapt = wrapt
_M.wrapt = wrapt
-- creates a function that chooses a filter by name from a given table
local function choose(table)
@ -28,7 +26,7 @@ local function choose(table)
name, opt1, opt2 = "default", name, opt1
end
local f = table[name or "nil"]
if not f then
if not f then
base.error("unknown key (" .. base.tostring(name) .. ")", 3)
else return f(opt1, opt2) end
end
@ -53,13 +51,6 @@ decodet['quoted-printable'] = function()
return ltn12.filter.cycle(_M.unqp, "")
end
local function format(chunk)
if chunk then
if chunk == "" then return "''"
else return string.len(chunk) end
else return "nil" end
end
-- define the line-wrap filters
wrapt['text'] = function(length)
length = length or 76
@ -87,4 +78,4 @@ function _M.stuff()
return ltn12.filter.cycle(_M.dot, 2)
end
return _M
return _M

View File

@ -1,15 +1,12 @@
/*=========================================================================*\
* Common option interface
* Common option interface
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lauxlib.h"
#include "luasocket.h"
#include "auxiliar.h"
#include "options.h"
#include "inet.h"
#include <string.h>
/*=========================================================================*\
* Internal functions prototypes
@ -20,9 +17,9 @@ static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_setint(lua_State *L, p_socket ps, int level, int name);
static int opt_getint(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name,
static int opt_set(lua_State *L, p_socket ps, int level, int name,
void *val, int len);
static int opt_get(lua_State *L, p_socket ps, int level, int name,
static int opt_get(lua_State *L, p_socket ps, int level, int name,
void *val, int* len);
/*=========================================================================*\
@ -37,7 +34,7 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
char msg[57];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
@ -50,39 +47,42 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
char msg[57];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
return opt->func(L, ps);
}
/*------------------------------------------------------*/
/* enables reuse of local address */
int opt_set_reuseaddr(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
int opt_get_reuseaddr(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
/*------------------------------------------------------*/
/* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
int opt_get_reuseport(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
/* disables the Naggle algorithm */
/*------------------------------------------------------*/
/* disables the Nagle algorithm */
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
@ -90,26 +90,132 @@ int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
/*------------------------------------------------------*/
#ifdef TCP_KEEPIDLE
int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
}
int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
}
#endif
/*------------------------------------------------------*/
#ifdef TCP_KEEPCNT
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
}
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
}
#endif
/*------------------------------------------------------*/
#ifdef TCP_KEEPINTVL
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
}
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
}
#endif
/*------------------------------------------------------*/
int opt_set_keepalive(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_get_keepalive(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
/*------------------------------------------------------*/
int opt_set_dontroute(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
}
int opt_get_dontroute(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
}
/*------------------------------------------------------*/
int opt_set_broadcast(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
}
int opt_get_broadcast(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
}
/*------------------------------------------------------*/
int opt_set_recv_buf_size(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
}
int opt_get_recv_buf_size(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
}
/*------------------------------------------------------*/
int opt_get_send_buf_size(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
}
int opt_set_send_buf_size(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
}
// /*------------------------------------------------------*/
#ifdef TCP_FASTOPEN
int opt_set_tcp_fastopen(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN);
}
#endif
#ifdef TCP_FASTOPEN_CONNECT
int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT);
}
#endif
/*------------------------------------------------------*/
#ifdef TCP_DEFER_ACCEPT
int opt_set_tcp_defer_accept(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT);
}
#endif
/*------------------------------------------------------*/
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
@ -120,6 +226,7 @@ int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
}
/*------------------------------------------------------*/
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
@ -130,6 +237,7 @@ int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
}
/*------------------------------------------------------*/
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
@ -140,6 +248,7 @@ int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
/*------------------------------------------------------*/
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
@ -150,18 +259,19 @@ int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
}
/*------------------------------------------------------*/
int opt_set_linger(lua_State *L, p_socket ps)
{
struct linger li; /* obj, name, table */
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "on");
lua_gettable(L, 3);
if (!lua_isboolean(L, -1))
if (!lua_isboolean(L, -1))
luaL_argerror(L, 3, "boolean 'on' field expected");
li.l_onoff = (u_short) lua_toboolean(L, -1);
lua_pushstring(L, "timeout");
lua_gettable(L, 3);
if (!lua_isnumber(L, -1))
if (!lua_isnumber(L, -1))
luaL_argerror(L, 3, "number 'timeout' field expected");
li.l_linger = (u_short) lua_tonumber(L, -1);
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
@ -182,11 +292,13 @@ int opt_get_linger(lua_State *L, p_socket ps)
return 1;
}
/*------------------------------------------------------*/
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
}
/*------------------------------------------------------*/
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
{
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
@ -194,7 +306,7 @@ int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
val.s_addr = htonl(INADDR_ANY);
if (strcmp(address, "*") && !inet_aton(address, &val))
luaL_argerror(L, 3, "ip expected");
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &val, sizeof(val));
}
@ -211,6 +323,7 @@ int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
return 1;
}
/*------------------------------------------------------*/
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
{
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
@ -221,6 +334,7 @@ int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
}
/*------------------------------------------------------*/
int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
{
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
@ -231,6 +345,7 @@ int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
}
/*------------------------------------------------------*/
int opt_get_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
@ -241,6 +356,20 @@ int opt_set_ip6_v6only(lua_State *L, p_socket ps)
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
/*------------------------------------------------------*/
int opt_get_error(lua_State *L, p_socket ps)
{
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, socket_strerror(val));
return 1;
}
/*=========================================================================*\
* Auxiliar functions
\*=========================================================================*/
@ -250,17 +379,17 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'interface' field expected");
val.imr_interface.s_addr = htonl(INADDR_ANY);
if (strcmp(lua_tostring(L, -1), "*") &&
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
luaL_argerror(L, 3, "invalid 'interface' ip address");
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
@ -272,14 +401,14 @@ static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 3);
/* By default we listen to interface on default route
* (sigh). However, interface= can override it. We should
* (sigh). However, interface= can override it. We should
* support either number, or name for it. Waiting for
* windows port of if_nametoindex */
if (!lua_isnil(L, -1)) {
@ -291,7 +420,7 @@ static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static
static
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
{
socklen_t socklen = *len;
@ -304,7 +433,7 @@ int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
return 0;
}
static
static
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
{
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
@ -327,19 +456,6 @@ static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
return 1;
}
int opt_get_error(lua_State *L, p_socket ps)
{
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, socket_strerror(val));
return 1;
}
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */

View File

@ -8,7 +8,7 @@
* modules UDP and TCP.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "socket.h"
/* option registry */
@ -18,43 +18,96 @@ typedef struct t_opt {
} t_opt;
typedef t_opt *p_opt;
/* supported options for setoption */
int opt_set_dontroute(lua_State *L, p_socket ps);
int opt_set_broadcast(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
int opt_set_keepalive(lua_State *L, p_socket ps);
int opt_set_linger(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_reuseport(lua_State *L, p_socket ps);
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
/* supported options for getoption */
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
int opt_get_keepalive(lua_State *L, p_socket ps);
int opt_get_linger(lua_State *L, p_socket ps);
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
int opt_get_error(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_v6only(lua_State *L, p_socket ps);
/* invokes the appropriate option handler */
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_set_reuseport(lua_State *L, p_socket ps);
int opt_get_reuseport(lua_State *L, p_socket ps);
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
#ifdef TCP_KEEPIDLE
int opt_set_tcp_keepidle(lua_State *L, p_socket ps);
int opt_get_tcp_keepidle(lua_State *L, p_socket ps);
#endif
#ifdef TCP_KEEPCNT
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps);
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps);
#endif
#ifdef TCP_KEEPINTVL
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps);
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps);
#endif
#ifdef TCP_DEFER_ACCEPT
int opt_set_tcp_defer_accept(lua_State *L, p_socket ps);
#endif
int opt_set_keepalive(lua_State *L, p_socket ps);
int opt_get_keepalive(lua_State *L, p_socket ps);
int opt_set_dontroute(lua_State *L, p_socket ps);
int opt_get_dontroute(lua_State *L, p_socket ps);
int opt_set_broadcast(lua_State *L, p_socket ps);
int opt_get_broadcast(lua_State *L, p_socket ps);
int opt_set_recv_buf_size(lua_State *L, p_socket ps);
int opt_get_recv_buf_size(lua_State *L, p_socket ps);
int opt_set_send_buf_size(lua_State *L, p_socket ps);
int opt_get_send_buf_size(lua_State *L, p_socket ps);
#ifdef TCP_FASTOPEN
int opt_set_tcp_fastopen(lua_State *L, p_socket ps);
#endif
#ifdef TCP_FASTOPEN_CONNECT
int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps);
#endif
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_set_linger(lua_State *L, p_socket ps);
int opt_get_linger(lua_State *L, p_socket ps);
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
int opt_get_ip6_v6only(lua_State *L, p_socket ps);
int opt_get_error(lua_State *L, p_socket ps);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif

28
src/pierror.h Normal file
View File

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

View File

@ -2,24 +2,23 @@
* Select implementation
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "socket.h"
#include "timeout.h"
#include "select.h"
#include <string.h>
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static t_socket getfd(lua_State *L);
static int dirty(lua_State *L);
static void collect_fd(lua_State *L, int tab, int itab,
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd);
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start);
static void make_assoc(lua_State *L, int tab);
static int global_select(lua_State *L);
@ -30,21 +29,17 @@ static luaL_Reg func[] = {
{NULL, NULL}
};
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int select_open(lua_State *L) {
lua_pushstring(L, "_SETSIZE");
lua_pushnumber(L, FD_SETSIZE);
lua_pushinteger(L, FD_SETSIZE);
lua_rawset(L, -3);
lua_pushstring(L, "_SOCKETINVALID");
lua_pushinteger(L, SOCKET_INVALID);
lua_rawset(L, -3);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -98,10 +93,10 @@ static t_socket getfd(lua_State *L) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
if (lua_isnumber(L, -1)) {
double numfd = lua_tonumber(L, -1);
double numfd = lua_tonumber(L, -1);
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
}
}
}
lua_pop(L, 1);
return fd;
}
@ -114,12 +109,12 @@ static int dirty(lua_State *L) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
is = lua_toboolean(L, -1);
}
}
lua_pop(L, 1);
return is;
}
static void collect_fd(lua_State *L, int tab, int itab,
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd) {
int i = 1, n = 0;
/* nil is the same as an empty table */
@ -139,16 +134,16 @@ static void collect_fd(lua_State *L, int tab, int itab,
if (fd != SOCKET_INVALID) {
/* make sure we don't overflow the fd_set */
#ifdef _WIN32
if (n >= FD_SETSIZE)
if (n >= FD_SETSIZE)
luaL_argerror(L, tab, "too many sockets");
#else
if (fd >= FD_SETSIZE)
if (fd >= FD_SETSIZE)
luaL_argerror(L, tab, "descriptor too large for set size");
#endif
FD_SET(fd, set);
n++;
/* keep track of the largest descriptor so far */
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
*max_fd = fd;
/* make sure we can map back from descriptor to the object */
lua_pushnumber(L, (lua_Number) fd);
@ -162,9 +157,9 @@ static void collect_fd(lua_State *L, int tab, int itab,
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
int ndirty = 0, i = 1;
if (lua_isnil(L, tab))
if (lua_isnil(L, tab))
return 0;
for ( ;; ) {
for ( ;; ) {
t_socket fd;
lua_pushnumber(L, i);
lua_gettable(L, tab);
@ -185,7 +180,7 @@ static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
return ndirty;
}
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start) {
t_socket fd;
for (fd = 0; fd < max_fd; fd++) {
@ -217,4 +212,3 @@ static void make_assoc(lua_State *L, int tab) {
i = i+1;
}
}

View File

@ -10,6 +10,14 @@
* true if there is data ready for reading (required for buffered input).
\*=========================================================================*/
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int select_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* SELECT_H */

View File

@ -2,16 +2,15 @@
* Serial stream
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <sys/un.h>
#include <string.h>
#include <sys/un.h>
/*
Reuses userdata definition from unix.h, since it is useful for all
@ -54,15 +53,6 @@ static luaL_Reg serial_methods[] = {
{NULL, NULL}
};
/* our socket creation function */
/* this is an ad-hoc module that returns a single function
* as such, do not include other functions in this array. */
static luaL_Reg func[] = {
{"serial", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
@ -71,14 +61,7 @@ LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
auxiliar_newclass(L, "serial{client}", serial_methods);
/* create class groups */
auxiliar_add2group(L, "serial{client}", "serial{any}");
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_pushcfunction(L, global_create);
(void) func;
#else
/* set function into socket namespace */
luaL_openlib(L, "socket", func, 0);
lua_pushcfunction(L, global_create);
#endif
return 1;
}
@ -120,7 +103,7 @@ static int meth_getfd(lua_State *L) {
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
@ -131,7 +114,7 @@ static int meth_dirty(lua_State *L) {
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
@ -156,7 +139,7 @@ static int meth_settimeout(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Creates a serial object
* Creates a serial object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
const char* path = luaL_checkstring(L, 1);
@ -180,7 +163,7 @@ static int global_create(lua_State *L) {
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);

57
src/socket.h Normal file → Executable file
View File

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

View File

@ -32,23 +32,23 @@ function _M.bind(host, port, backlog)
err = "no info on address"
for i, alt in base.ipairs(addrinfo) do
if alt.family == "inet" then
sock, err = socket.tcp()
sock, err = socket.tcp4()
else
sock, err = socket.tcp6()
end
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
res, err = sock:bind(alt.addr, port)
if not res then
if not res then
sock:close()
else
else
res, err = sock:listen(backlog)
if not res then
if not res then
sock:close()
else
return sock
end
end
end
end
return nil, err
end

175
src/tcp.c
View File

@ -2,10 +2,7 @@
* TCP object
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
@ -13,10 +10,13 @@
#include "options.h"
#include "tcp.h"
#include <string.h>
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create4(lua_State *L);
static int global_create6(lua_State *L);
static int global_connect(lua_State *L);
static int meth_connect(lua_State *L);
@ -34,6 +34,7 @@ static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_gettimeout(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
@ -63,6 +64,7 @@ static luaL_Reg tcp_methods[] = {
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"settimeout", meth_settimeout},
{"gettimeout", meth_gettimeout},
{"shutdown", meth_shutdown},
{NULL, NULL}
};
@ -71,24 +73,58 @@ static luaL_Reg tcp_methods[] = {
static t_opt optget[] = {
{"keepalive", opt_get_keepalive},
{"reuseaddr", opt_get_reuseaddr},
{"reuseport", opt_get_reuseport},
{"tcp-nodelay", opt_get_tcp_nodelay},
#ifdef TCP_KEEPIDLE
{"tcp-keepidle", opt_get_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
{"tcp-keepcnt", opt_get_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
{"tcp-keepintvl", opt_get_tcp_keepintvl},
#endif
{"linger", opt_get_linger},
{"error", opt_get_error},
{"recv-buffer-size", opt_get_recv_buf_size},
{"send-buffer-size", opt_get_send_buf_size},
{NULL, NULL}
};
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"reuseport", opt_set_reuseport},
{"tcp-nodelay", opt_set_tcp_nodelay},
#ifdef TCP_KEEPIDLE
{"tcp-keepidle", opt_set_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
{"tcp-keepcnt", opt_set_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
{"tcp-keepintvl", opt_set_tcp_keepintvl},
#endif
{"ipv6-v6only", opt_set_ip6_v6only},
{"linger", opt_set_linger},
{"recv-buffer-size", opt_set_recv_buf_size},
{"send-buffer-size", opt_set_send_buf_size},
#ifdef TCP_DEFER_ACCEPT
{"tcp-defer-accept", opt_set_tcp_defer_accept},
#endif
#ifdef TCP_FASTOPEN
{"tcp-fastopen", opt_set_tcp_fastopen},
#endif
#ifdef TCP_FASTOPEN_CONNECT
{"tcp-fastopen-connect", opt_set_tcp_fastopen_connect},
#endif
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"tcp", global_create},
{"tcp4", global_create4},
{"tcp6", global_create6},
{"connect", global_connect},
{NULL, NULL}
@ -108,11 +144,7 @@ int tcp_open(lua_State *L)
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -216,8 +248,7 @@ static int meth_accept(lua_State *L)
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L)
{
static int meth_bind(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
@ -227,7 +258,7 @@ static int meth_bind(lua_State *L)
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = tcp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&tcp->sock, address, port, &bindhints);
err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
@ -240,8 +271,7 @@ static int meth_bind(lua_State *L)
/*-------------------------------------------------------------------------*\
* Turns a master tcp object into a client object.
\*-------------------------------------------------------------------------*/
static int meth_connect(lua_State *L)
{
static int meth_connect(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
@ -252,7 +282,7 @@ static int meth_connect(lua_State *L)
/* make sure we try to connect only to the same family */
connecthints.ai_family = tcp->family;
timeout_markstart(&tcp->tm);
err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
&tcp->tm, &connecthints);
/* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1);
@ -282,9 +312,12 @@ static int meth_close(lua_State *L)
static int meth_getfamily(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
if (tcp->family == PF_INET6) {
if (tcp->family == AF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else if (tcp->family == AF_INET) {
lua_pushliteral(L, "inet4");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
@ -348,6 +381,12 @@ static int meth_settimeout(lua_State *L)
return timeout_meth_settimeout(L, &tcp->tm);
}
static int meth_gettimeout(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return timeout_meth_gettimeout(L, &tcp->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
@ -355,37 +394,36 @@ static int meth_settimeout(lua_State *L)
* Creates a master tcp object
\*-------------------------------------------------------------------------*/
static int tcp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
/* try to allocate a system socket */
if (!err) {
/* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
/* if family is AF_UNSPEC, we leave the socket invalid and
* store AF_UNSPEC into family. This will allow it to later be
* replaced with an AF_INET6 or AF_INET socket upon first use. */
tcp->sock = SOCKET_INVALID;
tcp->family = family;
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
if (family != AF_UNSPEC) {
const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
if (err != NULL) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
tcp->sock = sock;
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->family = family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
socket_setnonblocking(&tcp->sock);
}
return 1;
}
static int global_create(lua_State *L) {
return tcp_create(L, AF_UNSPEC);
}
static int global_create4(lua_State *L) {
return tcp_create(L, AF_INET);
}
@ -393,53 +431,6 @@ static int global_create6(lua_State *L) {
return tcp_create(L, AF_INET6);
}
#if 0
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
struct addrinfo *connecthints, p_tcp tcp) {
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
/* iterate over all returned addresses trying to connect */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
p_timeout tm = timeout_markstart(&tcp->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 (tcp->family != iterator->ai_family) {
socket_destroy(&tcp->sock);
err = socket_strerror(socket_create(&tcp->sock,
iterator->ai_family, iterator->ai_socktype,
iterator->ai_protocol));
if (err != NULL) {
freeaddrinfo(resolved);
return err;
}
tcp->family = iterator->ai_family;
/* all sockets initially non-blocking */
socket_setnonblocking(&tcp->sock);
}
/* finally try connecting to remote address */
err = socket_strerror(socket_connect(&tcp->sock,
(SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
#endif
static int global_connect(lua_State *L) {
const char *remoteaddr = luaL_checkstring(L, 1);
const char *remoteserv = luaL_checkstring(L, 2);
@ -456,26 +447,26 @@ static int global_connect(lua_State *L) {
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->sock = SOCKET_INVALID;
tcp->family = PF_UNSPEC;
tcp->family = AF_UNSPEC;
/* allow user to pick local address and port */
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = family;
bindhints.ai_flags = AI_PASSIVE;
if (localaddr) {
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
localserv, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
tcp->family = bindhints.ai_family;
}
/* try to connect to remote address and port */
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = bindhints.ai_family;
connecthints.ai_family = tcp->family;
err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
&tcp->tm, &connecthints);
if (err) {

View File

@ -14,7 +14,7 @@
* tcp objects either connected to some address or returned by the accept
* method of a server object.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "buffer.h"
#include "timeout.h"
@ -30,6 +30,14 @@ typedef struct t_tcp_ {
typedef t_tcp *p_tcp;
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int tcp_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* TCP_H */

View File

@ -2,16 +2,15 @@
* Timeout management functions
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "auxiliar.h"
#include "timeout.h"
#include <stdio.h>
#include <limits.h>
#include <float.h>
#ifdef _WIN32
#include <windows.h>
#else
@ -52,7 +51,7 @@ void timeout_init(p_timeout tm, double block, double total) {
/*-------------------------------------------------------------------------*\
* Determines how much time we have left for the next system call,
* if the previous call was successful
* if the previous call was successful
* Input
* tm: timeout control structure
* Returns
@ -107,7 +106,7 @@ double timeout_getretry(p_timeout tm) {
}
/*-------------------------------------------------------------------------*\
* Marks the operation start time in structure
* Marks the operation start time in structure
* Input
* tm: timeout control structure
\*-------------------------------------------------------------------------*/
@ -117,7 +116,7 @@ p_timeout timeout_markstart(p_timeout tm) {
}
/*-------------------------------------------------------------------------*\
* Gets time in s, relative to January 1, 1970 (UTC)
* Gets time in s, relative to January 1, 1970 (UTC)
* Returns
* time in s.
\*-------------------------------------------------------------------------*/
@ -144,11 +143,7 @@ double timeout_gettime(void) {
* Initializes module
\*-------------------------------------------------------------------------*/
int timeout_open(lua_State *L) {
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -163,7 +158,7 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
const char *mode = luaL_optstring(L, 3, "b");
switch (*mode) {
case 'b':
tm->block = t;
tm->block = t;
break;
case 'r': case 't':
tm->total = t;
@ -176,6 +171,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
return 1;
}
/*-------------------------------------------------------------------------*\
* Gets timeout values for IO operations
* Lua Output: block, total
\*-------------------------------------------------------------------------*/
int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
lua_pushnumber(L, tm->block);
lua_pushnumber(L, tm->total);
return 2;
}
/*=========================================================================*\
* Test support functions
\*=========================================================================*/

View File

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

View File

@ -46,6 +46,14 @@ end
-- metatable for sock object
local metat = { __index = {} }
function metat.__index:getpeername()
return self.c:getpeername()
end
function metat.__index:getsockname()
return self.c:getpeername()
end
function metat.__index:check(ok)
local code, reply = get_reply(self.c)
if not code then return nil, reply end
@ -74,7 +82,7 @@ function metat.__index:command(cmd, arg)
end
function metat.__index:sink(snk, pat)
local chunk, err = c:receive(pat)
local chunk, err = self.c:receive(pat)
return snk(chunk, err)
end
@ -123,4 +131,4 @@ function _M.connect(host, port, timeout, create)
return base.setmetatable({c = c}, metat)
end
return _M
return _M

185
src/udp.c Normal file → Executable file
View File

@ -2,11 +2,7 @@
* UDP object
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
@ -14,6 +10,9 @@
#include "options.h"
#include "udp.h"
#include <string.h>
#include <stdlib.h>
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
@ -26,6 +25,7 @@
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create4(lua_State *L);
static int global_create6(lua_State *L);
static int meth_send(lua_State *L);
static int meth_sendto(lua_State *L);
@ -34,6 +34,7 @@ static int meth_receivefrom(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L);
static int meth_gettimeout(lua_State *L);
static int meth_setsockname(lua_State *L);
static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L);
@ -64,6 +65,7 @@ static luaL_Reg udp_methods[] = {
{"setpeername", meth_setpeername},
{"setsockname", meth_setsockname},
{"settimeout", meth_settimeout},
{"gettimeout", meth_gettimeout},
{NULL, NULL}
};
@ -84,11 +86,17 @@ static t_opt optset[] = {
{"ipv6-add-membership", opt_set_ip6_add_membership},
{"ipv6-drop-membership", opt_set_ip6_drop_membersip},
{"ipv6-v6only", opt_set_ip6_v6only},
{"recv-buffer-size", opt_set_recv_buf_size},
{"send-buffer-size", opt_set_send_buf_size},
{NULL, NULL}
};
/* socket options for getoption */
static t_opt optget[] = {
{"dontroute", opt_get_dontroute},
{"broadcast", opt_get_broadcast},
{"reuseaddr", opt_get_reuseaddr},
{"reuseport", opt_get_reuseport},
{"ip-multicast-if", opt_get_ip_multicast_if},
{"ip-multicast-loop", opt_get_ip_multicast_loop},
{"error", opt_get_error},
@ -96,12 +104,15 @@ static t_opt optget[] = {
{"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
{"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
{"ipv6-v6only", opt_get_ip6_v6only},
{"recv-buffer-size", opt_get_recv_buf_size},
{"send-buffer-size", opt_get_send_buf_size},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"udp", global_create},
{"udp4", global_create4},
{"udp6", global_create6},
{NULL, NULL}
};
@ -109,8 +120,7 @@ static luaL_Reg func[] = {
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int udp_open(lua_State *L)
{
int udp_open(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "udp{connected}", udp_methods);
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
@ -120,18 +130,18 @@ int udp_open(lua_State *L)
auxiliar_add2group(L, "udp{connected}", "select{able}");
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
/* export default UDP size */
lua_pushliteral(L, "_DATAGRAMSIZE");
lua_pushinteger(L, UDP_DATAGRAMSIZE);
lua_rawset(L, -3);
return 0;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
const char *udp_strerror(int err) {
static const char *udp_strerror(int err) {
/* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */
if (err == IO_CLOSED) return "refused";
@ -174,15 +184,39 @@ static int meth_sendto(lua_State *L) {
memset(&aihint, 0, sizeof(aihint));
aihint.ai_family = udp->family;
aihint.ai_socktype = SOCK_DGRAM;
aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
aihint.ai_flags = AI_NUMERICHOST;
#ifdef AI_NUMERICSERV
aihint.ai_flags |= AI_NUMERICSERV;
#endif
err = getaddrinfo(ip, port, &aihint, &ai);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
lua_pushstring(L, LUA_GAI_STRERROR(err));
return 2;
}
/* create socket if on first sendto if AF_UNSPEC was set */
if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) {
struct addrinfo *ap;
const char *errstr = NULL;
for (ap = ai; ap != NULL; ap = ap->ai_next) {
errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0);
if (errstr == NULL) {
socket_setnonblocking(&udp->sock);
udp->family = ap->ai_family;
break;
}
}
if (errstr != NULL) {
lua_pushnil(L);
lua_pushstring(L, errstr);
freeaddrinfo(ai);
return 2;
}
}
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
(socklen_t) ai->ai_addrlen, tm);
freeaddrinfo(ai);
if (err != IO_DONE) {
@ -199,71 +233,80 @@ static int meth_sendto(lua_State *L) {
\*-------------------------------------------------------------------------*/
static int meth_receive(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
char buf[UDP_DATAGRAMSIZE];
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
int err;
p_timeout tm = &udp->tm;
count = MIN(count, sizeof(buffer));
timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err != IO_DONE) {
if (!dgram) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
lua_pushliteral(L, "out of memory");
return 2;
}
lua_pushlstring(L, buffer, got);
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
if (wanted > sizeof(buf)) free(dgram);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data and sender from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L)
{
static int meth_receivefrom(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
int err;
p_timeout tm = &udp->tm;
char buf[UDP_DATAGRAMSIZE];
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
char addrstr[INET6_ADDRSTRLEN];
char portstr[6];
int err;
p_timeout tm = &udp->tm;
timeout_markstart(tm);
count = MIN(count, sizeof(buffer));
err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr,
&addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err != IO_DONE) {
if (!dgram) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
lua_pushliteral(L, "out of memory");
return 2;
}
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
&addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
lua_pushstring(L, LUA_GAI_STRERROR(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, buffer, got);
lua_pushlstring(L, dgram, got);
lua_pushstring(L, addrstr);
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
if (wanted > sizeof(buf)) free(dgram);
return 3;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
static int meth_getfamily(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
if (udp->family == PF_INET6) {
if (udp->family == AF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
@ -332,6 +375,11 @@ static int meth_settimeout(lua_State *L) {
return timeout_meth_settimeout(L, &udp->tm);
}
static int meth_gettimeout(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return timeout_meth_gettimeout(L, &udp->tm);
}
/*-------------------------------------------------------------------------*\
* Turns a master udp object into a client object.
\*-------------------------------------------------------------------------*/
@ -348,7 +396,7 @@ static int meth_setpeername(lua_State *L) {
/* make sure we try to connect only to the same family */
connecthints.ai_family = udp->family;
if (connecting) {
err = inet_tryconnect(&udp->sock, &udp->family, address,
err = inet_tryconnect(&udp->sock, &udp->family, address,
port, tm, &connecthints);
if (err) {
lua_pushnil(L);
@ -362,7 +410,6 @@ static int meth_setpeername(lua_State *L) {
inet_trydisconnect(&udp->sock, udp->family, tm);
auxiliar_setclass(L, "udp{unconnected}", 1);
}
/* change class to connected or unconnected depending on address */
lua_pushnumber(L, 1);
return 1;
}
@ -390,7 +437,7 @@ static int meth_setsockname(lua_State *L) {
bindhints.ai_socktype = SOCK_DGRAM;
bindhints.ai_family = udp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&udp->sock, address, port, &bindhints);
err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
@ -407,32 +454,32 @@ static int meth_setsockname(lua_State *L) {
* Creates a master udp object
\*-------------------------------------------------------------------------*/
static int udp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
/* try to allocate a system socket */
if (!err) {
/* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
/* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1);
/* if family is AF_UNSPEC, we leave the socket invalid and
* store AF_UNSPEC into family. This will allow it to later be
* replaced with an AF_INET6 or AF_INET socket upon first use. */
udp->sock = SOCKET_INVALID;
timeout_init(&udp->tm, -1, -1);
udp->family = family;
if (family != AF_UNSPEC) {
const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
if (err != NULL) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
udp->sock = sock;
timeout_init(&udp->tm, -1, -1);
udp->family = family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
socket_setnonblocking(&udp->sock);
}
return 1;
}
static int global_create(lua_State *L) {
return udp_create(L, AF_UNSPEC);
}
static int global_create4(lua_State *L) {
return udp_create(L, AF_INET);
}

View File

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

View File

@ -1,346 +1,69 @@
/*=========================================================================*\
* Unix domain socket
* Unix domain socket
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "luasocket.h"
#include "lua.h"
#include "lauxlib.h"
#include "unixstream.h"
#include "unixdgram.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <sys/un.h>
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
static const char *unix_tryconnect(p_unix un, const char *path);
static const char *unix_trybind(p_unix un, const char *path);
/* unix object methods */
static luaL_Reg unix_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"listen", meth_listen},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"settimeout", meth_settimeout},
{"shutdown", meth_shutdown},
{NULL, NULL}
/*-------------------------------------------------------------------------*\
* Modules and functions
\*-------------------------------------------------------------------------*/
static const luaL_Reg mod[] = {
{"stream", unixstream_open},
{"dgram", unixdgram_open},
{NULL, NULL}
};
/* socket option handlers */
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"linger", opt_set_linger},
{NULL, NULL}
};
static void add_alias(lua_State *L, int index, const char *name, const char *target)
{
lua_getfield(L, index, target);
lua_setfield(L, index, name);
}
/* our socket creation function */
/* this is an ad-hoc module that returns a single function
* as such, do not include other functions in this array. */
static luaL_Reg func[] = {
{"unix", global_create},
{NULL, NULL}
};
static int compat_socket_unix_call(lua_State *L)
{
/* Look up socket.unix.stream in the socket.unix table (which is the first
* argument). */
lua_getfield(L, 1, "stream");
/* Replace the stack entry for the socket.unix table with the
* socket.unix.stream function. */
lua_replace(L, 1);
/* Call socket.unix.stream, passing along any arguments. */
int n = lua_gettop(L);
lua_call(L, n-1, LUA_MULTRET);
/* Pass along the return values from socket.unix.stream. */
n = lua_gettop(L);
return n;
}
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int luaopen_socket_unix(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "unix{master}", unix_methods);
auxiliar_newclass(L, "unix{client}", unix_methods);
auxiliar_newclass(L, "unix{server}", unix_methods);
/* create class groups */
auxiliar_add2group(L, "unix{master}", "unix{any}");
auxiliar_add2group(L, "unix{client}", "unix{any}");
auxiliar_add2group(L, "unix{server}", "unix{any}");
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_pushcfunction(L, global_create);
(void) func;
#else
/* set function into socket namespace */
luaL_openlib(L, "socket", func, 0);
lua_pushcfunction(L, global_create);
#endif
/* return the function instead of the 'socket' table */
return 1;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
return opt_meth_setoption(L, optset, &un->sock);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L) {
p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
/* if successful, push client socket */
if (err == IO_DONE) {
p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
auxiliar_setclass(L, "unix{client}", -1);
/* initialize structure fields */
socket_setnonblocking(&sock);
clnt->sock = sock;
io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static const char *unix_trybind(p_unix un, const char *path) {
struct sockaddr_un local;
size_t len = strlen(path);
int err;
if (len >= sizeof(local.sun_path)) return "path too long";
memset(&local, 0, sizeof(local));
strcpy(local.sun_path, path);
local.sun_family = AF_UNIX;
#ifdef UNIX_HAS_SUN_LEN
local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
+ len + 1;
err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
#else
err = socket_bind(&un->sock, (SA *) &local,
sizeof(local.sun_family) + len);
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_bind(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unix_trybind(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master unix object into a client object.
\*-------------------------------------------------------------------------*/
static const char *unix_tryconnect(p_unix un, const char *path)
LUASOCKET_API int luaopen_socket_unix(lua_State *L)
{
struct sockaddr_un remote;
int err;
size_t len = strlen(path);
if (len >= sizeof(remote.sun_path)) return "path too long";
memset(&remote, 0, sizeof(remote));
strcpy(remote.sun_path, path);
remote.sun_family = AF_UNIX;
timeout_markstart(&un->tm);
#ifdef UNIX_HAS_SUN_LEN
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
+ len + 1;
err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
#else
err = socket_connect(&un->sock, (SA *) &remote,
sizeof(remote.sun_family) + len, &un->tm);
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
int i;
lua_newtable(L);
int socket_unix_table = lua_gettop(L);
for (i = 0; mod[i].name; i++)
mod[i].func(L);
/* Add backwards compatibility aliases "tcp" and "udp" for the "stream" and
* "dgram" functions. */
add_alias(L, socket_unix_table, "tcp", "stream");
add_alias(L, socket_unix_table, "udp", "dgram");
/* Add a backwards compatibility function and a metatable setup to call it
* for the old socket.unix() interface. */
lua_pushcfunction(L, compat_socket_unix_call);
lua_setfield(L, socket_unix_table, "__call");
lua_pushvalue(L, socket_unix_table);
lua_setmetatable(L, socket_unix_table);
static int meth_connect(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unix_tryconnect(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
/* turn master object into a client object */
auxiliar_setclass(L, "unix{client}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
int backlog = (int) luaL_optnumber(L, 2, 32);
int err = socket_listen(&un->sock, backlog);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
/* turn master object into a server object */
auxiliar_setclass(L, "unix{server}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Shuts the connection down partially
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master unix object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
t_socket sock;
int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
/* try to allocate a system socket */
if (err == IO_DONE) {
/* allocate unix object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* set its type as master object */
auxiliar_setclass(L, "unix{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}

View File

@ -7,16 +7,12 @@
* This module is just an example of how to extend LuaSocket with a new
* domain.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "buffer.h"
#include "timeout.h"
#include "socket.h"
#ifndef UNIX_API
#define UNIX_API extern
#endif
typedef struct t_unix_ {
t_socket sock;
t_io io;
@ -25,6 +21,6 @@ typedef struct t_unix_ {
} t_unix;
typedef t_unix *p_unix;
UNIX_API int luaopen_socket_unix(lua_State *L);
LUASOCKET_API int luaopen_socket_unix(lua_State *L);
#endif /* UNIX_H */

405
src/unixdgram.c Normal file
View File

@ -0,0 +1,405 @@
/*=========================================================================*\
* Unix domain socket dgram submodule
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <string.h>
#include <stdlib.h>
#include <sys/un.h>
#define UNIXDGRAM_DATAGRAMSIZE 8192
/* provide a SUN_LEN macro if sys/un.h doesn't (e.g. Android) */
#ifndef SUN_LEN
#define SUN_LEN(ptr) \
((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_gettimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_receivefrom(lua_State *L);
static int meth_sendto(lua_State *L);
static int meth_getsockname(lua_State *L);
static const char *unixdgram_tryconnect(p_unix un, const char *path);
static const char *unixdgram_trybind(p_unix un, const char *path);
/* unixdgram object methods */
static luaL_Reg unixdgram_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"send", meth_send},
{"sendto", meth_sendto},
{"receive", meth_receive},
{"receivefrom", meth_receivefrom},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"getsockname", meth_getsockname},
{"settimeout", meth_settimeout},
{"gettimeout", meth_gettimeout},
{NULL, NULL}
};
/* socket option handlers */
static t_opt optset[] = {
{"reuseaddr", opt_set_reuseaddr},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"dgram", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int unixdgram_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "unixdgram{connected}", unixdgram_methods);
auxiliar_newclass(L, "unixdgram{unconnected}", unixdgram_methods);
/* create class groups */
auxiliar_add2group(L, "unixdgram{connected}", "unixdgram{any}");
auxiliar_add2group(L, "unixdgram{unconnected}", "unixdgram{any}");
auxiliar_add2group(L, "unixdgram{connected}", "select{able}");
auxiliar_add2group(L, "unixdgram{unconnected}", "select{able}");
luaL_setfuncs(L, func, 0);
return 0;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
static const char *unixdgram_strerror(int err)
{
/* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */
if (err == IO_CLOSED) return "refused";
else return socket_strerror(err);
}
static int meth_send(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{connected}", 1);
p_timeout tm = &un->tm;
size_t count, sent = 0;
int err;
const char *data = luaL_checklstring(L, 2, &count);
timeout_markstart(tm);
err = socket_send(&un->sock, data, count, &sent, tm);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, unixdgram_strerror(err));
return 2;
}
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
/*-------------------------------------------------------------------------*\
* Send data through unconnected unixdgram socket
\*-------------------------------------------------------------------------*/
static int meth_sendto(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
size_t count, sent = 0;
const char *data = luaL_checklstring(L, 2, &count);
const char *path = luaL_checkstring(L, 3);
p_timeout tm = &un->tm;
int err;
struct sockaddr_un remote;
size_t len = strlen(path);
if (len >= sizeof(remote.sun_path)) {
lua_pushnil(L);
lua_pushstring(L, "path too long");
return 2;
}
memset(&remote, 0, sizeof(remote));
strcpy(remote.sun_path, path);
remote.sun_family = AF_UNIX;
timeout_markstart(tm);
#ifdef UNIX_HAS_SUN_LEN
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
+ len + 1;
err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm);
#else
err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote,
sizeof(remote.sun_family) + len, tm);
#endif
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, unixdgram_strerror(err));
return 2;
}
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
char buf[UNIXDGRAM_DATAGRAMSIZE];
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
int err;
p_timeout tm = &un->tm;
timeout_markstart(tm);
if (!dgram) {
lua_pushnil(L);
lua_pushliteral(L, "out of memory");
return 2;
}
err = socket_recv(&un->sock, dgram, wanted, &got, tm);
/* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, unixdgram_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
if (wanted > sizeof(buf)) free(dgram);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data and sender from a DGRAM socket
\*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
char buf[UNIXDGRAM_DATAGRAMSIZE];
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
struct sockaddr_un addr;
socklen_t addr_len = sizeof(addr);
int err;
p_timeout tm = &un->tm;
timeout_markstart(tm);
if (!dgram) {
lua_pushnil(L);
lua_pushliteral(L, "out of memory");
return 2;
}
addr.sun_path[0] = '\0';
err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr,
&addr_len, tm);
/* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, unixdgram_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
/* the path may be empty, when client send without bind */
lua_pushstring(L, addr.sun_path);
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
return opt_meth_setoption(L, optset, &un->sock);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
(void) un;
lua_pushboolean(L, 0);
return 1;
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static const char *unixdgram_trybind(p_unix un, const char *path) {
struct sockaddr_un local;
size_t len = strlen(path);
if (len >= sizeof(local.sun_path)) return "path too long";
memset(&local, 0, sizeof(local));
strcpy(local.sun_path, path);
local.sun_family = AF_UNIX;
size_t addrlen = SUN_LEN(&local);
#ifdef UNIX_HAS_SUN_LEN
local.sun_len = addrlen + 1;
#endif
int err = socket_bind(&un->sock, (SA *) &local, addrlen);
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_bind(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unixdgram_trybind(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
static int meth_getsockname(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
struct sockaddr_un peer = {0};
socklen_t peer_len = sizeof(peer);
if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
}
lua_pushstring(L, peer.sun_path);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master unixdgram object into a client object.
\*-------------------------------------------------------------------------*/
static const char *unixdgram_tryconnect(p_unix un, const char *path)
{
struct sockaddr_un remote;
size_t len = strlen(path);
if (len >= sizeof(remote.sun_path)) return "path too long";
memset(&remote, 0, sizeof(remote));
strcpy(remote.sun_path, path);
remote.sun_family = AF_UNIX;
timeout_markstart(&un->tm);
size_t addrlen = SUN_LEN(&remote);
#ifdef UNIX_HAS_SUN_LEN
remote.sun_len = addrlen + 1;
#endif
int err = socket_connect(&un->sock, (SA *) &remote, addrlen, &un->tm);
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_connect(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unixdgram_tryconnect(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
/* turn unconnected object into a connected object */
auxiliar_setclass(L, "unixdgram{connected}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
static int meth_gettimeout(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
return timeout_meth_gettimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master unixdgram object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L)
{
t_socket sock;
int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0);
/* try to allocate a system socket */
if (err == IO_DONE) {
/* allocate unixdgram object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* set its type as master object */
auxiliar_setclass(L, "unixdgram{unconnected}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}

28
src/unixdgram.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef UNIXDGRAM_H
#define UNIXDGRAM_H
/*=========================================================================*\
* DGRAM object
* LuaSocket toolkit
*
* The dgram.h module provides LuaSocket with support for DGRAM protocol
* (AF_INET, SOCK_DGRAM).
*
* Two classes are defined: connected and unconnected. DGRAM objects are
* originally unconnected. They can be "connected" to a given address
* with a call to the setpeername function. The same function can be used to
* break the connection.
\*=========================================================================*/
#include "unix.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int unixdgram_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* UNIXDGRAM_H */

355
src/unixstream.c Normal file
View File

@ -0,0 +1,355 @@
/*=========================================================================*\
* Unix domain socket stream sub module
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unixstream.h"
#include <string.h>
#include <sys/un.h>
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
static int meth_getsockname(lua_State *L);
static const char *unixstream_tryconnect(p_unix un, const char *path);
static const char *unixstream_trybind(p_unix un, const char *path);
/* unixstream object methods */
static luaL_Reg unixstream_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"listen", meth_listen},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"getsockname", meth_getsockname},
{"settimeout", meth_settimeout},
{"shutdown", meth_shutdown},
{NULL, NULL}
};
/* socket option handlers */
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"linger", opt_set_linger},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"stream", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int unixstream_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "unixstream{master}", unixstream_methods);
auxiliar_newclass(L, "unixstream{client}", unixstream_methods);
auxiliar_newclass(L, "unixstream{server}", unixstream_methods);
/* create class groups */
auxiliar_add2group(L, "unixstream{master}", "unixstream{any}");
auxiliar_add2group(L, "unixstream{client}", "unixstream{any}");
auxiliar_add2group(L, "unixstream{server}", "unixstream{any}");
luaL_setfuncs(L, func, 0);
return 0;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
return opt_meth_setoption(L, optset, &un->sock);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L) {
p_unix server = (p_unix) auxiliar_checkclass(L, "unixstream{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
/* if successful, push client socket */
if (err == IO_DONE) {
p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
auxiliar_setclass(L, "unixstream{client}", -1);
/* initialize structure fields */
socket_setnonblocking(&sock);
clnt->sock = sock;
io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static const char *unixstream_trybind(p_unix un, const char *path) {
struct sockaddr_un local;
size_t len = strlen(path);
int err;
if (len >= sizeof(local.sun_path)) return "path too long";
memset(&local, 0, sizeof(local));
strcpy(local.sun_path, path);
local.sun_family = AF_UNIX;
#ifdef UNIX_HAS_SUN_LEN
local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
+ len + 1;
err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
#else
err = socket_bind(&un->sock, (SA *) &local,
sizeof(local.sun_family) + len);
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_bind(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unixstream_trybind(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
static int meth_getsockname(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
struct sockaddr_un peer = {0};
socklen_t peer_len = sizeof(peer);
if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
}
lua_pushstring(L, peer.sun_path);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master unixstream object into a client object.
\*-------------------------------------------------------------------------*/
static const char *unixstream_tryconnect(p_unix un, const char *path)
{
struct sockaddr_un remote;
int err;
size_t len = strlen(path);
if (len >= sizeof(remote.sun_path)) return "path too long";
memset(&remote, 0, sizeof(remote));
strcpy(remote.sun_path, path);
remote.sun_family = AF_UNIX;
timeout_markstart(&un->tm);
#ifdef UNIX_HAS_SUN_LEN
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
+ len + 1;
err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
#else
err = socket_connect(&un->sock, (SA *) &remote,
sizeof(remote.sun_family) + len, &un->tm);
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_connect(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unixstream_tryconnect(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
/* turn master object into a client object */
auxiliar_setclass(L, "unixstream{client}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
int backlog = (int) luaL_optnumber(L, 2, 32);
int err = socket_listen(&un->sock, backlog);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
/* turn master object into a server object */
auxiliar_setclass(L, "unixstream{server}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Shuts the connection down partially
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_unix stream = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&stream->sock, how);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master unixstream object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
t_socket sock;
int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
/* try to allocate a system socket */
if (err == IO_DONE) {
/* allocate unixstream object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* set its type as master object */
auxiliar_setclass(L, "unixstream{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}

29
src/unixstream.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef UNIXSTREAM_H
#define UNIXSTREAM_H
/*=========================================================================*\
* UNIX STREAM object
* LuaSocket toolkit
*
* The unixstream.h module is basicly a glue that puts together modules buffer.h,
* timeout.h socket.h and inet.h to provide the LuaSocket UNIX STREAM (AF_UNIX,
* SOCK_STREAM) support.
*
* Three classes are defined: master, client and server. The master class is
* a newly created unixstream object, that has not been bound or connected. Server
* objects are unixstream objects bound to some local address. Client objects are
* unixstream objects either connected to some address or returned by the accept
* method of a server object.
\*=========================================================================*/
#include "unix.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int unixstream_open(lua_State *L);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* UNIXSTREAM_H */

View File

@ -49,7 +49,7 @@ local function make_set(t)
return s
end
-- these are allowed withing a path segment, along with alphanum
-- these are allowed within a path segment, along with alphanum
-- other characters must be escaped
local segment_set = make_set {
"-", "_", ".", "!", "~", "*", "'", "(",
@ -59,16 +59,16 @@ local segment_set = make_set {
local function protect_segment(s)
return string.gsub(s, "([^A-Za-z0-9_])", function (c)
if segment_set[c] then return c
else return string.format("%%%02x", string.byte(c)) end
else return string.format("%%%02X", string.byte(c)) end
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Unencodes a escaped hexadecimal string into its binary representation
-- Input
-- s: binary string to be encoded
-- s: escaped hexadecimal string to be unencoded
-- Returns
-- escaped representation of string binary
-- unescaped binary representation of escaped hexadecimal binary
-----------------------------------------------------------------------------
function _M.unescape(s)
return (string.gsub(s, "%%(%x%x)", function(hex)
@ -76,6 +76,34 @@ function _M.unescape(s)
end))
end
-----------------------------------------------------------------------------
-- Removes '..' and '.' components appropriately from a path.
-- Input
-- path
-- Returns
-- dot-normalized path
local function remove_dot_components(path)
local marker = string.char(1)
repeat
local was = path
path = path:gsub('//', '/'..marker..'/', 1)
until path == was
repeat
local was = path
path = path:gsub('/%./', '/', 1)
until path == was
repeat
local was = path
path = path:gsub('[^/]+/%.%./([^/]+)', '%1', 1)
until path == was
path = path:gsub('[^/]+/%.%./*$', '')
path = path:gsub('/%.%.$', '/')
path = path:gsub('/%.$', '/')
path = path:gsub('^/%.%./', '/')
path = path:gsub(marker, '')
return path
end
-----------------------------------------------------------------------------
-- Builds a path from a base path and a relative path
-- Input
@ -85,23 +113,12 @@ end
-- corresponding absolute path
-----------------------------------------------------------------------------
local function absolute_path(base_path, relative_path)
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
local path = string.gsub(base_path, "[^/]*$", "")
path = path .. relative_path
path = string.gsub(path, "([^/]*%./)", function (s)
if s ~= "./" then return s else return "" end
end)
path = string.gsub(path, "/%.$", "/")
local reduced
while reduced ~= path do
reduced = path
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
if s ~= "../../" then return "" else return s end
end)
end
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
if s ~= "../.." then return "" else return s end
end)
if string.sub(relative_path, 1, 1) == "/" then
return remove_dot_components(relative_path) end
base_path = base_path:gsub("[^/]*$", "")
if not base_path:find'/$' then base_path = base_path .. '/' end
local path = base_path .. relative_path
path = remove_dot_components(path)
return path
end
@ -131,11 +148,6 @@ function _M.parse(url, default)
if not url or url == "" then return nil, "invalid url" end
-- remove whitespace
-- url = string.gsub(url, "%s", "")
-- get fragment
url = string.gsub(url, "#(.*)$", function(f)
parsed.fragment = f
return ""
end)
-- get scheme
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
function(s) parsed.scheme = s; return "" end)
@ -144,6 +156,11 @@ function _M.parse(url, default)
parsed.authority = n
return ""
end)
-- get fragment
url = string.gsub(url, "#(.*)$", function(f)
parsed.fragment = f
return ""
end)
-- get query string
url = string.gsub(url, "%?(.*)", function(q)
parsed.query = q
@ -162,9 +179,9 @@ function _M.parse(url, default)
function(u) parsed.userinfo = u; return "" end)
authority = string.gsub(authority, ":([^:%]]*)$",
function(p) parsed.port = p; return "" end)
if authority ~= "" then
if authority ~= "" then
-- IPv6?
parsed.host = string.match(authority, "^%[(.+)%]$") or authority
parsed.host = string.match(authority, "^%[(.+)%]$") or authority
end
local userinfo = parsed.userinfo
if not userinfo then return parsed end
@ -183,8 +200,9 @@ end
-- a stringing with the corresponding URL
-----------------------------------------------------------------------------
function _M.build(parsed)
local ppath = _M.parse_path(parsed.path or "")
local url = _M.build_path(ppath)
--local ppath = _M.parse_path(parsed.path or "")
--local url = _M.build_path(ppath)
local url = parsed.path or ""
if parsed.params then url = url .. ";" .. parsed.params end
if parsed.query then url = url .. "?" .. parsed.query end
local authority = parsed.authority
@ -193,7 +211,7 @@ function _M.build(parsed)
if string.find(authority, ":") then -- IPv6?
authority = "[" .. authority .. "]"
end
if parsed.port then authority = authority .. ":" .. parsed.port end
if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end
local userinfo = parsed.userinfo
if parsed.user then
userinfo = parsed.user
@ -219,16 +237,21 @@ end
-- corresponding absolute url
-----------------------------------------------------------------------------
function _M.absolute(base_url, relative_url)
local base_parsed
if base.type(base_url) == "table" then
base_parsed = base_url
base_url = _M.build(base_parsed)
else
base_parsed = _M.parse(base_url)
end
local result
local relative_parsed = _M.parse(relative_url)
if not base_parsed then return relative_url
elseif not relative_parsed then return base_url
elseif relative_parsed.scheme then return relative_url
if not base_parsed then
result = relative_url
elseif not relative_parsed then
result = base_url
elseif relative_parsed.scheme then
result = relative_url
else
relative_parsed.scheme = base_parsed.scheme
if not relative_parsed.authority then
@ -241,13 +264,14 @@ function _M.absolute(base_url, relative_url)
relative_parsed.query = base_parsed.query
end
end
else
else
relative_parsed.path = absolute_path(base_parsed.path or "",
relative_parsed.path)
end
end
return _M.build(relative_parsed)
result = _M.build(relative_parsed)
end
return remove_dot_components(result)
end
-----------------------------------------------------------------------------

View File

@ -4,12 +4,15 @@
*
* The code is now interrupt-safe.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
* the I/O call fail in the first place.
\*=========================================================================*/
#include <string.h>
#include <signal.h>
#include "luasocket.h"
#include "socket.h"
#include "pierror.h"
#include <string.h>
#include <signal.h>
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
@ -72,16 +75,16 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
/*-------------------------------------------------------------------------*\
* Initializes module
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
/* instals a handler to ignore sigpipe or it will crash us */
/* installs a handler to ignore sigpipe or it will crash us */
signal(SIGPIPE, SIG_IGN);
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
return 1;
@ -92,7 +95,6 @@ int socket_close(void) {
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps);
close(*ps);
*ps = SOCKET_INVALID;
}
@ -101,7 +103,7 @@ void socket_destroy(p_socket ps) {
/*-------------------------------------------------------------------------*\
* Select with timeout control
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
int ret;
do {
@ -120,8 +122,8 @@ int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
\*-------------------------------------------------------------------------*/
int socket_create(p_socket ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCKET_INVALID) return IO_DONE;
else return errno;
if (*ps != SOCKET_INVALID) return IO_DONE;
else return errno;
}
/*-------------------------------------------------------------------------*\
@ -130,29 +132,25 @@ int socket_create(p_socket ps, int domain, int type, int protocol) {
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
int err = IO_DONE;
socket_setblocking(ps);
if (bind(*ps, addr, len) < 0) err = errno;
if (bind(*ps, addr, len) < 0) err = errno;
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
socket_setblocking(ps);
if (listen(*ps, backlog)) err = errno;
socket_setnonblocking(ps);
int err = IO_DONE;
if (listen(*ps, backlog)) err = errno;
return err;
}
/*-------------------------------------------------------------------------*\
*
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
shutdown(*ps, how);
socket_setnonblocking(ps);
}
/*-------------------------------------------------------------------------*\
@ -166,7 +164,7 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
do if (connect(*ps, addr, len) == 0) return IO_DONE;
while ((err = errno) == EINTR);
/* if connection failed immediately, return error code */
if (err != EINPROGRESS && err != EAGAIN) return err;
if (err != EINPROGRESS && err != EAGAIN) return err;
/* zero timeout case optimization */
if (timeout_iszero(tm)) return IO_TIMEOUT;
/* wait until we have the result of the connection attempt or timeout */
@ -181,7 +179,7 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int err;
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
@ -197,7 +195,7 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
@ -215,6 +213,8 @@ int socket_send(p_socket ps, const char *data, size_t count,
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
if (err == EPROTOTYPE) continue;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
@ -229,20 +229,21 @@ int socket_send(p_socket ps, const char *data, size_t count,
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
*sent = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long put = (long) sendto(*ps, data, count, 0, addr, len);
long put = (long) sendto(*ps, data, count, 0, addr, len);
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
if (err == EPIPE) return IO_CLOSED;
if (err == EPROTOTYPE) continue;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
@ -266,8 +267,8 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
@ -275,7 +276,7 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm) {
int err;
*got = 0;
@ -289,8 +290,8 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
@ -303,7 +304,7 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
* with send/recv replaced with write/read. We can't just use write/read
* in the socket version, because behaviour when size is zero is different.
\*-------------------------------------------------------------------------*/
int socket_write(p_socket ps, const char *data, size_t count,
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
@ -321,6 +322,8 @@ int socket_write(p_socket ps, const char *data, size_t count,
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
if (err == EPROTOTYPE) continue;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
@ -349,8 +352,8 @@ int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
@ -374,7 +377,7 @@ void socket_setnonblocking(p_socket ps) {
}
/*-------------------------------------------------------------------------*\
* DNS helpers
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
@ -399,7 +402,7 @@ int socket_gethostbyname(const char *addr, struct hostent **hp) {
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case HOST_NOT_FOUND: return "host not found";
case HOST_NOT_FOUND: return PIE_HOST_NOT_FOUND;
default: return hstrerror(err);
}
}
@ -407,43 +410,45 @@ const char *socket_hoststrerror(int err) {
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case EADDRINUSE: return "address already in use";
case EISCONN: return "already connected";
case EACCES: return "permission denied";
case ECONNREFUSED: return "connection refused";
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case ETIMEDOUT: return "timeout";
default: return strerror(err);
case EADDRINUSE: return PIE_ADDRINUSE;
case EISCONN: return PIE_ISCONN;
case EACCES: return PIE_ACCESS;
case ECONNREFUSED: return PIE_CONNREFUSED;
case ECONNABORTED: return PIE_CONNABORTED;
case ECONNRESET: return PIE_CONNRESET;
case ETIMEDOUT: return PIE_TIMEDOUT;
default: {
return strerror(err);
}
}
}
const char *socket_ioerror(p_socket ps, int err) {
(void) ps;
return socket_strerror(err);
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
case EAI_OVERFLOW: return "argument buffer overflow";
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
case EAI_SYSTEM: return strerror(errno);
default: return gai_strerror(err);
}
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return PIE_AGAIN;
case EAI_BADFLAGS: return PIE_BADFLAGS;
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return PIE_BADHINTS;
#endif
case EAI_FAIL: return PIE_FAIL;
case EAI_FAMILY: return PIE_FAMILY;
case EAI_MEMORY: return PIE_MEMORY;
case EAI_NONAME: return PIE_NONAME;
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW: return PIE_OVERFLOW;
#endif
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return PIE_PROTOCOL;
#endif
case EAI_SERVICE: return PIE_SERVICE;
case EAI_SOCKTYPE: return PIE_SOCKTYPE;
case EAI_SYSTEM: return strerror(errno);
default: return LUA_GAI_STRERROR(err);
}
}

146
src/wsocket.c Normal file → Executable file
View File

@ -3,33 +3,36 @@
* LuaSocket toolkit
*
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
* the I/O call fail in the first place.
\*=========================================================================*/
#include "luasocket.h"
#include <string.h>
#include "socket.h"
#include "pierror.h"
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err);
/*-------------------------------------------------------------------------*\
* Initializes module
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
WORD wVersionRequested = MAKEWORD(2, 0);
int err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) return 0;
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
WSACleanup();
return 0;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
WSACleanup();
@ -50,10 +53,10 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
struct timeval tv, *tp = NULL;
double t;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
if (sw & WAITFD_R) {
FD_ZERO(&rfds);
if (sw & WAITFD_R) {
FD_ZERO(&rfds);
FD_SET(*ps, &rfds);
rp = &rfds;
rp = &rfds;
}
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
@ -72,9 +75,9 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
struct timeval tv;
struct timeval tv;
double t = timeout_get(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
@ -96,7 +99,7 @@ void socket_destroy(p_socket ps) {
}
/*-------------------------------------------------------------------------*\
*
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
@ -130,14 +133,14 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
/* we wait until something happens */
err = socket_waitfd(ps, WAITFD_C, tm);
if (err == IO_CLOSED) {
int len = sizeof(err);
int elen = sizeof(err);
/* give windows time to set the error (yes, disgusting) */
Sleep(10);
/* find out why we failed */
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &elen);
/* we KNOW there was an error. if 'why' is 0, we will return
* "unknown error", but it's not really our fault */
return err > 0? err: IO_UNKNOWN;
return err > 0? err: IO_UNKNOWN;
} else return err;
}
@ -154,7 +157,7 @@ int socket_bind(p_socket ps, SA *addr, socklen_t len) {
}
/*-------------------------------------------------------------------------*\
*
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
@ -167,7 +170,7 @@ int socket_listen(p_socket ps, int backlog) {
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
@ -175,21 +178,21 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
/* try to get client socket */
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
/* find out why we failed */
err = WSAGetLastError();
err = WSAGetLastError();
/* if we failed because there was no connectoin, keep trying */
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
/* call select to avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
}
/*-------------------------------------------------------------------------*\
* Send with timeout
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
* this can take an awful lot of time and we will end up blocked.
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
* this can take an awful lot of time and we will end up blocked.
* Therefore, whoever calls this function should not pass a huge buffer.
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
@ -206,18 +209,18 @@ int socket_send(p_socket ps, const char *data, size_t count,
return IO_DONE;
}
/* deal with failure */
err = WSAGetLastError();
err = WSAGetLastError();
/* we can only proceed if there was no serious error */
if (err != WSAEWOULDBLOCK) return err;
/* avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
@ -229,17 +232,17 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
*sent = put;
return IO_DONE;
}
err = WSAGetLastError();
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
p_timeout tm)
int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
p_timeout tm)
{
int err, prev = IO_DONE;
*got = 0;
@ -252,9 +255,9 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
* On TCP, it means our socket is now useless, so the error passes.
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
* On TCP, it means our socket is now useless, so the error passes.
* (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK) {
if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
@ -267,8 +270,8 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm)
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm)
{
int err, prev = IO_DONE;
*got = 0;
@ -281,8 +284,8 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
/* On UDP, a connreset simply means the previous send failed.
* So we try again.
* On TCP, it means our socket is now useless, so the error passes.
* (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK) {
@ -310,7 +313,7 @@ void socket_setnonblocking(p_socket ps) {
}
/*-------------------------------------------------------------------------*\
* DNS helpers
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
@ -330,21 +333,21 @@ int socket_gethostbyname(const char *addr, struct hostent **hp) {
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAHOST_NOT_FOUND: return "host not found";
default: return wstrerror(err);
case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND;
default: return wstrerror(err);
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAEADDRINUSE: return "address already in use";
case WSAECONNREFUSED: return "connection refused";
case WSAEISCONN: return "already connected";
case WSAEACCES: return "permission denied";
case WSAECONNABORTED: return "closed";
case WSAECONNRESET: return "closed";
case WSAETIMEDOUT: return "timeout";
case WSAEADDRINUSE: return PIE_ADDRINUSE;
case WSAECONNREFUSED : return PIE_CONNREFUSED;
case WSAEISCONN: return PIE_ISCONN;
case WSAEACCES: return PIE_ACCESS;
case WSAECONNABORTED: return PIE_CONNABORTED;
case WSAECONNRESET: return PIE_CONNRESET;
case WSAETIMEDOUT: return PIE_TIMEDOUT;
default: return wstrerror(err);
}
}
@ -357,7 +360,7 @@ const char *socket_ioerror(p_socket ps, int err) {
static const char *wstrerror(int err) {
switch (err) {
case WSAEINTR: return "Interrupted function call";
case WSAEACCES: return "Permission denied";
case WSAEACCES: return PIE_ACCESS; /* "Permission denied"; */
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open files";
@ -370,65 +373,62 @@ static const char *wstrerror(int err) {
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; /* "Socket type not supported"; */
case WSAEOPNOTSUPP: return "Operation not supported";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE: return "Address already in use";
case WSAEAFNOSUPPORT: return PIE_FAMILY; /* "Address family not supported by protocol family"; */
case WSAEADDRINUSE: return PIE_ADDRINUSE; /* "Address already in use"; */
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Network dropped connection on reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAECONNRESET: return PIE_CONNRESET; /* "Connection reset by peer"; */
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAEISCONN: return PIE_ISCONN; /* "Socket is already connected"; */
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAETIMEDOUT: return PIE_TIMEDOUT; /* "Connection timed out"; */
case WSAECONNREFUSED: return PIE_CONNREFUSED; /* "Connection refused"; */
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAEPROCLIM: return "Too many processes";
case WSASYSNOTREADY: return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
case WSANOTINITIALISED:
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; /* "Host not found"; */
case WSATRY_AGAIN: return "Nonauthoritative host not found";
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
case WSANO_RECOVERY: return PIE_FAIL; /* "Nonrecoverable name lookup error"; */
case WSANO_DATA: return "Valid name, no data record of requested type";
default: return "Unknown error";
}
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
case EAI_AGAIN: return PIE_AGAIN;
case EAI_BADFLAGS: return PIE_BADFLAGS;
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
case EAI_BADHINTS: return PIE_BADHINTS;
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
case EAI_FAIL: return PIE_FAIL;
case EAI_FAMILY: return PIE_FAMILY;
case EAI_MEMORY: return PIE_MEMORY;
case EAI_NONAME: return PIE_NONAME;
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW: return "argument buffer overflow";
case EAI_OVERFLOW: return PIE_OVERFLOW;
#endif
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
case EAI_PROTOCOL: return PIE_PROTOCOL;
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
case EAI_SERVICE: return PIE_SERVICE;
case EAI_SOCKTYPE: return PIE_SOCKTYPE;
#ifdef EAI_SYSTEM
case EAI_SYSTEM: return strerror(errno);
case EAI_SYSTEM: return strerror(errno);
#endif
default: return gai_strerror(err);
default: return LUA_GAI_STRERROR(err);
}
}

4
test/auth/.htaccess Normal file
View File

@ -0,0 +1,4 @@
AuthName "test-auth"
AuthType Basic
AuthUserFile /home/diego/impa/luasocket/test/auth/.htpasswd
Require valid-user

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