mirror of
https://github.com/lunarmodules/luasocket.git
synced 2025-12-24 22:19:13 +01:00
Compare commits
368 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a66baed15 | ||
|
|
790a58112f | ||
|
|
d341493bbf | ||
|
|
0901c486ff | ||
|
|
68aeb39dc2 | ||
|
|
733af884f1 | ||
|
|
ab3b0ef5c9 | ||
|
|
9acb6dc81a | ||
|
|
c89a931cc3 | ||
|
|
21514304be | ||
|
|
3a37ab8890 | ||
|
|
33883e78c8 | ||
|
|
c8d0fdda54 | ||
|
|
8b2dcdcf7d | ||
|
|
4e363330a3 | ||
|
|
d27b1a7945 | ||
|
|
5d07d9b227 | ||
|
|
d71e6bc459 | ||
|
|
42a1a732b7 | ||
|
|
86e1b3f45f | ||
|
|
1fa10673f7 | ||
|
|
c8b9b40eda | ||
|
|
c2245f35c5 | ||
|
|
ce6a08d57d | ||
|
|
83648f8df2 | ||
|
|
2015290cb4 | ||
|
|
ee30e4643d | ||
|
|
611cdd19cc | ||
|
|
4bf3eb6db2 | ||
|
|
133774cd3d | ||
|
|
e3ac49efbd | ||
|
|
98800e9129 | ||
|
|
2af4872a40 | ||
|
|
03b72d8f7e | ||
|
|
c7215bef07 | ||
|
|
1e4255e2a9 | ||
|
|
5cc91ab600 | ||
|
|
297f9d0277 | ||
|
|
34d525984c | ||
|
|
d9afe3fd9c | ||
|
|
c0fba03e4f | ||
|
|
e2e43d62fa | ||
|
|
2d8f0d9901 | ||
|
|
f8183bab87 | ||
|
|
d7ffc2f4e6 | ||
|
|
fe437ee844 | ||
|
|
678d558c5f | ||
|
|
30a0a6003b | ||
|
|
87c2dee13e | ||
|
|
525d703e16 | ||
|
|
898f2df025 | ||
|
|
fae993c118 | ||
|
|
ef2a3fcedb | ||
|
|
3f19a052e8 | ||
|
|
731b23bc89 | ||
|
|
395729d431 | ||
|
|
2bf6730fd5 | ||
|
|
b95527e140 | ||
|
|
c0374dd46f | ||
|
|
16b0026e27 | ||
|
|
1f6035070f | ||
|
|
c23bf865ce | ||
|
|
efc4bb3e2d | ||
|
|
f06b17c4c9 | ||
|
|
9b3f7a4304 | ||
|
|
2a467001f6 | ||
|
|
e587800164 | ||
|
|
38865fad3a | ||
|
|
fa807f3ffd | ||
|
|
a9c75cb099 | ||
|
|
699c36c019 | ||
|
|
f6ba23d463 | ||
|
|
b8f088e868 | ||
|
|
c5cef32897 | ||
|
|
4b0f1d753d | ||
|
|
40f79c1961 | ||
|
|
e136dd3df3 | ||
|
|
09ff9b650c | ||
|
|
59c8aaac34 | ||
|
|
5858c8e776 | ||
|
|
686f2ce822 | ||
|
|
144fa01c2f | ||
|
|
024646de54 | ||
|
|
57e04f55dc | ||
|
|
531012df1a | ||
|
|
d1e35c9573 | ||
|
|
4950294c26 | ||
|
|
e2bb1d3b42 | ||
|
|
288219fd6b | ||
|
|
648d81281f | ||
|
|
043e997713 | ||
|
|
ca5398be09 | ||
|
|
38d936ec0e | ||
|
|
5b862e6a3c | ||
|
|
7ccea58776 | ||
|
|
c570a32c21 | ||
|
|
c905b5d44f | ||
|
|
17a95c126a | ||
|
|
5813cd0505 | ||
|
|
9b82c7871d | ||
|
|
4df569e9f8 | ||
|
|
cc42bcbf80 | ||
|
|
8fee636309 | ||
|
|
5848de4851 | ||
|
|
e1e41be948 | ||
|
|
4a3504612c | ||
|
|
97bfe1e043 | ||
|
|
6529598909 | ||
|
|
72fb9dcb49 | ||
|
|
88b13a825b | ||
|
|
2d6a0f7bda | ||
|
|
3ee89515a0 | ||
|
|
053c032a70 | ||
|
|
5a17f79b03 | ||
|
|
aef7bcf288 | ||
|
|
ff1a447b4d | ||
|
|
47e644031f | ||
|
|
1b4debffee | ||
|
|
865356f6eb | ||
|
|
44fb9e9112 | ||
|
|
16bb548746 | ||
|
|
860da0f4b4 | ||
|
|
29e5ad610a | ||
|
|
ea0064625b | ||
|
|
843fe9b65f | ||
|
|
3041a808c3 | ||
|
|
a0baab5f3c | ||
|
|
3a33c37b9c | ||
|
|
ac3201d620 | ||
|
|
cd1e52eb7a | ||
|
|
316a9455b9 | ||
|
|
2205c2053c | ||
|
|
c87f953d81 | ||
|
|
9f77f8b24f | ||
|
|
aa1b8cc9bc | ||
|
|
30a64c585a | ||
|
|
3abd1f2dd0 | ||
|
|
6aa4f2bc33 | ||
|
|
e2acf378ea | ||
|
|
6a0506ca44 | ||
|
|
624924a77b | ||
|
|
b9f6fd215a | ||
|
|
9984741d94 | ||
|
|
6fa6462636 | ||
|
|
23ce5aeaa2 | ||
|
|
916b548240 | ||
|
|
5b4b915879 | ||
|
|
944305dc21 | ||
|
|
cdce73b226 | ||
|
|
fe7b37aced | ||
|
|
0341516a29 | ||
|
|
4392bdcdd4 | ||
|
|
9fe38c654f | ||
|
|
9ffd96724d | ||
|
|
7cab8a5006 | ||
|
|
7c1df8a7cd | ||
|
|
fb713cdedb | ||
|
|
d075e7322f | ||
|
|
bf13ec7fd4 | ||
|
|
280e1d68a6 | ||
|
|
9192881346 | ||
|
|
52bb99af35 | ||
|
|
700ece0721 | ||
|
|
3c3a5d0011 | ||
|
|
a7f21e8ec4 | ||
|
|
5d52ffedf4 | ||
|
|
83880dbed7 | ||
|
|
be67f63f4e | ||
|
|
fd729b32a8 | ||
|
|
d1ec29be7f | ||
|
|
f4b4720073 | ||
|
|
4110e4125d | ||
|
|
77bba625d7 | ||
|
|
46d7e75f3e | ||
|
|
b6a10ccb68 | ||
|
|
96965b179c | ||
|
|
b211838648 | ||
|
|
9322eacefd | ||
|
|
e75444ccd1 | ||
|
|
67abaf89eb | ||
|
|
321c0c9b1f | ||
|
|
863a54cbaf | ||
|
|
892ea1791a | ||
|
|
8066a90e87 | ||
|
|
bbcbbf845e | ||
|
|
d3ed08616b | ||
|
|
8396a0291b | ||
|
|
9d49cdcf05 | ||
|
|
59869b8bf6 | ||
|
|
76ed24fe8a | ||
|
|
ddf4292824 | ||
|
|
d8f77cca64 | ||
|
|
9178451ef9 | ||
|
|
c6f136c7f5 | ||
|
|
41692dfb4b | ||
|
|
2906d6a522 | ||
|
|
8a24ddaf49 | ||
|
|
5edf093643 | ||
|
|
0b03eec16b | ||
|
|
583257c28c | ||
|
|
7006ae120d | ||
|
|
6dcecd8f45 | ||
|
|
4f122e60b1 | ||
|
|
e602c2b271 | ||
|
|
d80bb0d82b | ||
|
|
2314235b3a | ||
|
|
36aa87e031 | ||
|
|
534dfed859 | ||
|
|
833333e131 | ||
|
|
6d5e40c324 | ||
|
|
d0b1f5b4c1 | ||
|
|
396e9e5ee6 | ||
|
|
244e5d34a0 | ||
|
|
c715993fb8 | ||
|
|
87d72dce4e | ||
|
|
6bdb00e24c | ||
|
|
1f9ccb2b58 | ||
|
|
ddf88aca09 | ||
|
|
480a818bf0 | ||
|
|
22cd5833fc | ||
|
|
19bd8baf9b | ||
|
|
de58cb417a | ||
|
|
bf7bc59a4d | ||
|
|
ea812a755e | ||
|
|
2cc51443c2 | ||
|
|
85aa5e3d9c | ||
|
|
9ddfe92820 | ||
|
|
c07ad19ca1 | ||
|
|
7cad902bb7 | ||
|
|
b34386ca5c | ||
|
|
cce138c8e5 | ||
|
|
6e00ffd62f | ||
|
|
906abf29d1 | ||
|
|
bc709ac7b7 | ||
|
|
b1d1e721d1 | ||
|
|
802567b7de | ||
|
|
ebde49944b | ||
|
|
5eefc73b57 | ||
|
|
a233e27865 | ||
|
|
00a06857c9 | ||
|
|
5341131cd0 | ||
|
|
1de617e355 | ||
|
|
b84a5f3d08 | ||
|
|
79e6c4915d | ||
|
|
5167ddaf49 | ||
|
|
2d51d61688 | ||
|
|
27fd725c6d | ||
|
|
734cc23e1f | ||
|
|
66cd8cfcee | ||
|
|
056d7653f3 | ||
|
|
3d61b0fe36 | ||
|
|
834a3cf520 | ||
|
|
5e0b56b8d3 | ||
|
|
26704061a4 | ||
|
|
45ff0e1775 | ||
|
|
920bc97629 | ||
|
|
bd51d8c1a5 | ||
|
|
e54f78c61c | ||
|
|
56dbda39ed | ||
|
|
fbe184f28a | ||
|
|
427220c7b1 | ||
|
|
6d93fd7c8f | ||
|
|
22107bb9fc | ||
|
|
5d3a78b4a6 | ||
|
|
bb0b31301a | ||
|
|
afe0494318 | ||
|
|
cbc77440c8 | ||
|
|
ca48baf495 | ||
|
|
817d47df42 | ||
|
|
238b217c4f | ||
|
|
c28fa1d309 | ||
|
|
00435529bb | ||
|
|
571308a94e | ||
|
|
5a58786a39 | ||
|
|
56893e9dcd | ||
|
|
94c9588719 | ||
|
|
33b4f0cfc7 | ||
|
|
eea1bc04d7 | ||
|
|
d548a78e55 | ||
|
|
72a5347f97 | ||
|
|
618ce43ee3 | ||
|
|
66670c3541 | ||
|
|
9d97d39575 | ||
|
|
a4b45edef2 | ||
|
|
114080d835 | ||
|
|
5c467b3954 | ||
|
|
ffddaf4a2e | ||
|
|
a402222464 | ||
|
|
6368caeb5a | ||
|
|
32e7a107e2 | ||
|
|
03ba06f70c | ||
|
|
f329aae724 | ||
|
|
54ffcd483f | ||
|
|
6370b61414 | ||
|
|
5616f3a0ae | ||
|
|
c1bb432eff | ||
|
|
7503bb0ca3 | ||
|
|
a6cf48596d | ||
|
|
d777341eaf | ||
|
|
36461db5bb | ||
|
|
c624761d32 | ||
|
|
05535a19f8 | ||
|
|
399bdb7f41 | ||
|
|
156669c28b | ||
|
|
3d3e69c6e4 | ||
|
|
1bb586d655 | ||
|
|
ee7c53c3e5 | ||
|
|
ac59bcbeac | ||
|
|
c291383ce2 | ||
|
|
0c3e067af1 | ||
|
|
04be61f88d | ||
|
|
af55d25675 | ||
|
|
6de0aa54fd | ||
|
|
cf4d29f86d | ||
|
|
46736a3355 | ||
|
|
e86eac96fa | ||
|
|
30d1aae140 | ||
|
|
c2e29537f5 | ||
|
|
1acf8188cd | ||
|
|
966642f76a | ||
|
|
f960b3872a | ||
|
|
f37e026026 | ||
|
|
b3c4f46179 | ||
|
|
4b671f4551 | ||
|
|
195b2a74bb | ||
|
|
38b99b80a2 | ||
|
|
d1a50282a7 | ||
|
|
8bb542baaf | ||
|
|
0716cb868e | ||
|
|
27a3964ff7 | ||
|
|
db47a91d40 | ||
|
|
e716e7347b | ||
|
|
12bde801f6 | ||
|
|
3a0fd4744d | ||
|
|
b1f7c349b5 | ||
|
|
3b19f2a7ed | ||
|
|
dace50628c | ||
|
|
f63d616bc0 | ||
|
|
21698c7665 | ||
|
|
c37f71d062 | ||
|
|
51acb54760 | ||
|
|
a8b19e5367 | ||
|
|
1f704cfb89 | ||
|
|
826589afcd | ||
|
|
dcb92d6268 | ||
|
|
e3e0dee639 | ||
|
|
f399ab25fc | ||
|
|
e81a6ff623 | ||
|
|
9a58252528 | ||
|
|
51187ecc90 | ||
|
|
c8eed36788 | ||
|
|
e15ed19db6 | ||
|
|
a984607f28 | ||
|
|
7893d9ece2 | ||
|
|
8393c76180 | ||
|
|
594f826aa1 | ||
|
|
5874d47f55 | ||
|
|
f871a29f27 | ||
|
|
4df1618aab | ||
|
|
5065a2585c | ||
|
|
923eef1929 | ||
|
|
5c33ef9997 | ||
|
|
908ee2cce1 | ||
|
|
dd83e0a849 | ||
|
|
2778766d67 | ||
|
|
3a8ba90dfb | ||
|
|
bce60be30f | ||
|
|
d1a72435d5 |
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.obj
|
||||||
|
*.lib
|
||||||
|
*.dll*
|
||||||
|
*.user
|
||||||
|
*.sdf
|
||||||
|
Debug
|
||||||
|
Release
|
||||||
|
*.manifest
|
||||||
|
*.swp
|
||||||
|
*.suo
|
||||||
|
x64
|
||||||
|
|
||||||
54
.travis.yml
Normal file
54
.travis.yml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
language: erlang
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- LUAROCKS_BASE=luarocks-2.0.13
|
||||||
|
matrix:
|
||||||
|
- LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
|
||||||
|
- LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
|
||||||
|
- LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ $LUA = "luajit" ]; then
|
||||||
|
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
|
||||||
|
fi
|
||||||
|
- sudo apt-get install $LUA
|
||||||
|
- sudo apt-get install $LUA_DEV
|
||||||
|
- lua$LUA_SFX -v
|
||||||
|
# Install a recent luarocks release
|
||||||
|
- wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
|
||||||
|
- tar zxvpf $LUAROCKS_BASE.tar.gz
|
||||||
|
- cd $LUAROCKS_BASE
|
||||||
|
- ./configure
|
||||||
|
--lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
|
||||||
|
- sudo make
|
||||||
|
- sudo make install
|
||||||
|
- cd $TRAVIS_BUILD_DIR
|
||||||
|
|
||||||
|
|
||||||
|
install:
|
||||||
|
- export DEBUG=DEBUG
|
||||||
|
- sudo -E luarocks make luasocket-scm-0.rockspec
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd test
|
||||||
|
- lua$LUA_SFX hello.lua
|
||||||
|
- lua$LUA_SFX testsrvr.lua > /dev/null &
|
||||||
|
- lua$LUA_SFX testclnt.lua
|
||||||
|
- lua$LUA_SFX stufftest.lua
|
||||||
|
- lua$LUA_SFX excepttest.lua
|
||||||
|
- lua$LUA_SFX test_bind.lua
|
||||||
|
- lua$LUA_SFX test_getaddrinfo.lua
|
||||||
|
- lua$LUA_SFX ltn12test.lua
|
||||||
|
- lua$LUA_SFX mimetest.lua
|
||||||
|
- lua$LUA_SFX urltest.lua
|
||||||
|
- lua$LUA_SFX test_socket_error.lua
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: change
|
||||||
|
on_failure: always
|
||||||
13
FIX
13
FIX
@@ -1,15 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
http was preserving old host header during redirects
|
http was preserving old host header during redirects
|
||||||
fix smtp.send hang on source error
|
fix smtp.send hang on source error
|
||||||
add create field to FTP and SMTP and fix HTTP ugliness
|
add create field to FTP and SMTP and fix HTTP ugliness
|
||||||
clean timeout argument to open functions in SMTP, HTTP and FTP
|
clean timeout argument to open functions in SMTP, HTTP and FTP
|
||||||
eliminate globals from namespaces created by module().
|
eliminate globals from namespaces created by module().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
url.absolute was not working when base_url was already parsed
|
url.absolute was not working when base_url was already parsed
|
||||||
http.request was redirecting even when the location header was empty
|
http.request was redirecting even when the location header was empty
|
||||||
tcp{client}:shutdown() was checking for group instead of class.
|
tcp{client}:shutdown() was checking for group instead of class.
|
||||||
|
|||||||
4
LICENSE
4
LICENSE
@@ -1,5 +1,5 @@
|
|||||||
LuaSocket 2.0.2 license
|
LuaSocket 3.0 license
|
||||||
Copyright © 2004-2007 Diego Nehab
|
Copyright © 2004-2013 Diego Nehab
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
|||||||
49
Lua.props
Executable file
49
Lua.props
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ImportGroup Label="PropertySheets" />
|
||||||
|
<PropertyGroup Condition="'$(Platform)'=='x64'" Label="LuaPlat">
|
||||||
|
<LUAPLAT>$(Platform)/$(Configuration)</LUAPLAT>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Platform)'=='Win32'" Label="LuaPlat">
|
||||||
|
<LUAPLAT>$(Configuration)</LUAPLAT>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="UserMacros">
|
||||||
|
<LUAV>5.3</LUAV>
|
||||||
|
<LUAPREFIX>z:\data\build\vc14\</LUAPREFIX>
|
||||||
|
<LUALIB>$(LUAPREFIX)\lib\lua\$(LUAV)\$(LUAPLAT)</LUALIB>
|
||||||
|
<LUACDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)</LUACDIR>
|
||||||
|
<LUALDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)\lua</LUALDIR>
|
||||||
|
<LUAINC>$(LUAPREFIX)\include\lua\$(LUAV);$(LUAPREFIX)\include\lua$(LUAV)</LUAINC>
|
||||||
|
<LUALIBNAME>lua$(LUAV.Replace('.', '')).lib</LUALIBNAME>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<_PropertySheetDisplayName>Lua</_PropertySheetDisplayName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<BuildMacro Include="LUAPLAT">
|
||||||
|
<Value>$(LUAPLAT)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUAPREFIX">
|
||||||
|
<Value>$(LUAPREFIX)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUAV">
|
||||||
|
<Value>$(LUAV)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUALIB">
|
||||||
|
<Value>$(LUALIB)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUAINC">
|
||||||
|
<Value>$(LUAINC)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUACDIR">
|
||||||
|
<Value>$(LUACDIR)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUALDIR">
|
||||||
|
<Value>$(LUALDIR)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
<BuildMacro Include="LUALIBNAME">
|
||||||
|
<Value>$(LUALIBNAME)</Value>
|
||||||
|
</BuildMacro>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
49
NEW
49
NEW
@@ -1,11 +1,44 @@
|
|||||||
What's New
|
What's New
|
||||||
|
|
||||||
This is just a bug-fix/update release.
|
Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
|
||||||
|
|
||||||
* Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
|
* Added: Compatible with Lua 5.2
|
||||||
* Fixed: return values are consistent when reading from closed sockets;
|
- Note that unless you define LUA_COMPAT_MODULE, package
|
||||||
* Fixed: case sensitivity in headers of multipart messages in
|
tables will not be exported as globals!
|
||||||
smtp.message() (Graham Henstridge);
|
* Added: IPv6 support;
|
||||||
* Fixed a couple instances of error() being called instead of base.error(). These would cause an error when an error was reported. :) (Ketmar Dark);
|
- Socket.connect and socket.bind support IPv6 addresses;
|
||||||
* Fixed: test script now uses pairs() iterator instead of the old
|
- Getpeername and getsockname support IPv6 addresses, and
|
||||||
Lua syntax (Robert Dodier).
|
return the socket family as a third value;
|
||||||
|
- URL module updated to support IPv6 host names;
|
||||||
|
- New socket.tcp6 and socket.udp6 functions;
|
||||||
|
- New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
|
||||||
|
* Added: getoption method;
|
||||||
|
* Fixed: url.unescape was returning additional values;
|
||||||
|
* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could
|
||||||
|
mistaking their own stack slots for functions arguments;
|
||||||
|
* Fixed: Receiving zero-length datagram is now possible;
|
||||||
|
* Improved: Hidden all internal library symbols;
|
||||||
|
* Improved: Better error messages;
|
||||||
|
* Improved: Better documentation of socket options.
|
||||||
|
* Fixed: manual sample of HTTP authentication now uses correct
|
||||||
|
"authorization" header (Alexandre Ittner);
|
||||||
|
* Fixed: failure on bind() was destroying the socket (Sam Roberts);
|
||||||
|
* Fixed: receive() returns immediatelly if prefix can satisfy
|
||||||
|
bytes requested (M Joonas Pihlaja);
|
||||||
|
* Fixed: multicast didn't work on Windows, or anywhere
|
||||||
|
else for that matter (Herbert Leuwer, Adrian Sietsma);
|
||||||
|
* Fixed: select() now reports an error when called with more
|
||||||
|
sockets than FD_SETSIZE (Lorenzo Leonini);
|
||||||
|
* Fixed: manual links to home.html changed to index.html (Robert Hahn);
|
||||||
|
* Fixed: mime.unb64() would return an empty string on results that started
|
||||||
|
with a null character (Robert Raschke);
|
||||||
|
* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
|
||||||
|
* Fixed: calling sleep() with negative numbers could
|
||||||
|
block forever, wasting CPU. Now it returns immediately (MPB);
|
||||||
|
* Improved: FTP commands are now sent in upper case to
|
||||||
|
help buggy servers (Anders Eurenius);
|
||||||
|
* Improved: known headers now sent in canonic
|
||||||
|
capitalization to help buggy servers (Joseph Stewart);
|
||||||
|
* Improved: Clarified tcp:receive() in the manual (MPB);
|
||||||
|
* Improved: Decent makefiles (LHF).
|
||||||
|
* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
|
||||||
|
|||||||
11
README
11
README
@@ -1,6 +1,11 @@
|
|||||||
This is the LuaSocket 2.0.1. It has been tested on WinXP, Mac OS X,
|
This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
|
||||||
and Linux. Please use the Lua mailing list to report any bugs
|
and Linux.
|
||||||
(or "features") you encounter.
|
|
||||||
|
Please use the project page at GitHub
|
||||||
|
|
||||||
|
https://github.com/diegonehab/luasocket
|
||||||
|
|
||||||
|
to file bug reports or propose changes.
|
||||||
|
|
||||||
Have fun,
|
Have fun,
|
||||||
Diego Nehab.
|
Diego Nehab.
|
||||||
|
|||||||
64
TODO
64
TODO
@@ -1,7 +1,67 @@
|
|||||||
|
- bizarre default values for getnameinfo should throw error instead!
|
||||||
|
|
||||||
|
> It's just too bad it can't talk to gmail -
|
||||||
|
> reason 1: they absolutely want TLS
|
||||||
|
> reason 2: unlike all the other SMTP implementations, they
|
||||||
|
> don't
|
||||||
|
> tolerate missing < > around adresses
|
||||||
|
|
||||||
|
- document the new bind and connect behavior.
|
||||||
|
- shouldn't we instead make the code compatible to Lua 5.2
|
||||||
|
without any compat stuff, and use a compatibility layer to
|
||||||
|
make it work on 5.1?
|
||||||
|
- add what's new to manual
|
||||||
|
- should there be an equivalent to tohostname for IPv6?
|
||||||
|
- should we add service name resolution as well to getaddrinfo?
|
||||||
|
- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
|
||||||
|
|
||||||
|
- add http POST sample to manual
|
||||||
|
people keep asking stupid questions
|
||||||
|
- documentation of dirty/getfd/setfd is problematic because of portability
|
||||||
|
same for unix and serial.
|
||||||
|
what to do about this? add a stronger disclaimer?
|
||||||
|
- fix makefile with decent defaults?
|
||||||
|
|
||||||
|
Done:
|
||||||
|
|
||||||
|
- added IPv6 support to getsockname
|
||||||
|
- simplified getpeername implementation
|
||||||
|
- added family to return of getsockname and getpeername
|
||||||
|
and added modification to the manual to describe
|
||||||
|
|
||||||
|
- connect and bind try all adresses returned by getaddrinfo
|
||||||
|
- document headers.lua?
|
||||||
|
- update copyright date everywhere?
|
||||||
|
- remove RCSID from files?
|
||||||
|
- move version to 2.1 rather than 2.1.1?
|
||||||
|
- fixed url package to support ipv6 hosts
|
||||||
|
- changed domain to family
|
||||||
|
- implement getfamily methods.
|
||||||
|
|
||||||
|
- remove references to Lua 5.0 from documentation, add 5.2?
|
||||||
|
- update lua and luasocket version in samples in documentation
|
||||||
|
- document ipv5_v6only default option being set?
|
||||||
|
- document tcp6 and udp6
|
||||||
|
- document dns.getaddrinfo
|
||||||
|
- documented zero-sized datagram change?
|
||||||
|
no.
|
||||||
|
- document unix socket and serial socket? add raw support?
|
||||||
|
no.
|
||||||
|
- document getoption
|
||||||
|
- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
replace \r\n with \0xD\0xA in everything
|
||||||
New mime support
|
New mime support
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ftp send should return server replies?
|
ftp send should return server replies?
|
||||||
make sure there are no object files in the distribution tarball
|
make sure there are no object files in the distribution tarball
|
||||||
http handling of 100-continue, see DB patch
|
http handling of 100-continue, see DB patch
|
||||||
|
|||||||
60
config
60
config
@@ -1,60 +0,0 @@
|
|||||||
#------
|
|
||||||
# LuaSocket makefile configuration
|
|
||||||
#
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Output file names
|
|
||||||
#
|
|
||||||
EXT=so
|
|
||||||
SOCKET_V=2.0.2
|
|
||||||
MIME_V=1.0.2
|
|
||||||
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
|
|
||||||
MIME_SO=mime.$(EXT).$(MIME_V)
|
|
||||||
UNIX_SO=unix.$(EXT)
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Lua includes and libraries
|
|
||||||
#
|
|
||||||
#LUAINC=-I/usr/local/include/lua50
|
|
||||||
#LUAINC=-I/usr/local/include/lua5.1
|
|
||||||
#LUAINC=-Ilua-5.1.1/src
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Compat-5.1 directory
|
|
||||||
#
|
|
||||||
#COMPAT=compat-5.1r5
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Top of your Lua installation
|
|
||||||
# Relative paths will be inside the src tree
|
|
||||||
#
|
|
||||||
#INSTALL_TOP_SHARE=/usr/local/share/lua/5.0
|
|
||||||
#INSTALL_TOP_LIB=/usr/local/lib/lua/5.0
|
|
||||||
INSTALL_TOP_SHARE=/usr/local/share/lua/5.1
|
|
||||||
INSTALL_TOP_LIB=/usr/local/lib/lua/5.1
|
|
||||||
|
|
||||||
INSTALL_DATA=cp
|
|
||||||
INSTALL_EXEC=cp
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Compiler and linker settings
|
|
||||||
# for Mac OS X
|
|
||||||
#
|
|
||||||
#CC=gcc
|
|
||||||
#DEF= -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN
|
|
||||||
#CFLAGS= $(LUAINC) -I$(COMPAT) $(DEF) -pedantic -Wall -O2 -fno-common
|
|
||||||
#LDFLAGS=-bundle -undefined dynamic_lookup
|
|
||||||
#LD=export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
|
|
||||||
|
|
||||||
#------
|
|
||||||
# Compiler and linker settings
|
|
||||||
# for Linux
|
|
||||||
CC=gcc
|
|
||||||
DEF=-DLUASOCKET_DEBUG
|
|
||||||
CFLAGS= $(LUAINC) $(DEF) -pedantic -Wall -O2 -fpic
|
|
||||||
LDFLAGS=-O -shared -fpic
|
|
||||||
LD=gcc
|
|
||||||
|
|
||||||
#------
|
|
||||||
# End of makefile configuration
|
|
||||||
#
|
|
||||||
69
doc/dns.html
69
doc/dns.html
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -39,12 +39,16 @@
|
|||||||
<h2 id=dns>DNS</h2>
|
<h2 id=dns>DNS</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Name resolution functions return <em>all</em> information obtained from the
|
IPv4 name resolution functions
|
||||||
resolver in a table of the form:
|
<a href=#toip><tt>dns.toip</tt></a>
|
||||||
|
and
|
||||||
|
<a href=#tohostname><tt>dns.tohostname</tt></a>
|
||||||
|
return <em>all</em> information obtained from
|
||||||
|
the resolver in a table of the form:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<blockquote><tt>
|
<blockquote><tt>
|
||||||
resolved = {<br>
|
resolved4 = {<br>
|
||||||
name = <i>canonic-name</i>,<br>
|
name = <i>canonic-name</i>,<br>
|
||||||
alias = <i>alias-list</i>,<br>
|
alias = <i>alias-list</i>,<br>
|
||||||
ip = <i>ip-address-list</i><br>
|
ip = <i>ip-address-list</i><br>
|
||||||
@@ -55,6 +59,53 @@ resolved = {<br>
|
|||||||
Note that the <tt>alias</tt> list can be empty.
|
Note that the <tt>alias</tt> list can be empty.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The more general name resolution function
|
||||||
|
<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which
|
||||||
|
supports both IPv6 and IPv4,
|
||||||
|
returns <em>all</em> information obtained from
|
||||||
|
the resolver in a table of the form:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<blockquote><tt>
|
||||||
|
resolved6 = {<br>
|
||||||
|
[1] = {<br>
|
||||||
|
family = <i>family-name-1</i>,<br>
|
||||||
|
addr = <i>address-1</i><br>
|
||||||
|
},<br>
|
||||||
|
...<br>
|
||||||
|
[n] = {<br>
|
||||||
|
family = <i>family-name-n</i>,<br>
|
||||||
|
addr = <i>address-n</i><br>
|
||||||
|
}<br>
|
||||||
|
}
|
||||||
|
</tt> </blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Here, <tt>family</tt> contains the string <tt>"inet"</tt> for IPv4
|
||||||
|
addresses, and <tt>"inet6"</tt> for IPv6 addresses.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=getaddrinfo>
|
||||||
|
socket.dns.<b>getaddrinfo(</b>address<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Converts from host name to address.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=parameters>
|
||||||
|
<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
The function returns a table with all information returned by
|
||||||
|
the resolver. In case of error, the function returns <b><tt>nil</tt></b>
|
||||||
|
followed by an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=gethostname>
|
<p class=name id=gethostname>
|
||||||
@@ -72,7 +123,7 @@ socket.dns.<b>tohostname(</b>address<b>)</b>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Converts from IP address to host name.
|
Converts from IPv4 address to host name.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -93,7 +144,7 @@ socket.dns.<b>toip(</b>address<b>)</b>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Converts from host name to IP address.
|
Converts from host name to IPv4 address.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -113,8 +164,8 @@ message.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
15
doc/ftp.html
15
doc/ftp.html
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
FTP (File Transfer Protocol) is a protocol used to transfer files
|
FTP (File Transfer Protocol) is a protocol used to transfer files
|
||||||
between hosts. The <tt>ftp</tt> namespace offers thorough support
|
between hosts. The <tt>ftp</tt> namespace offers thorough support
|
||||||
to FTP, under a simple interface. The implementation conforms to
|
to FTP, under a simple interface. The implementation conforms to
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc0959.txt">RFC 959</a>.
|
<a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -70,8 +70,8 @@ local ftp = require("socket.ftp")
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
URLs MUST conform to
|
URLs MUST conform to
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
|
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
|
||||||
1738</a>, that is, an URL is a string in the form:
|
that is, an URL is a string in the form:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -86,7 +86,6 @@ the FTP module:
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li> <tt>PASSWORD</tt>: default anonymous password.
|
<li> <tt>PASSWORD</tt>: default anonymous password.
|
||||||
<li> <tt>PORT</tt>: default port used for the control connection;
|
|
||||||
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
|
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
|
||||||
<li> <tt>USER</tt>: default anonymous user;
|
<li> <tt>USER</tt>: default anonymous user;
|
||||||
</ul>
|
</ul>
|
||||||
@@ -270,8 +269,8 @@ f, e = ftp.put{
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<h2 id=http>HTTP</h2>
|
<h2 id="http">HTTP</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
|
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
|
||||||
@@ -45,8 +45,7 @@ namespace offers full support for the client side of the HTTP
|
|||||||
protocol (i.e.,
|
protocol (i.e.,
|
||||||
the facilities that would be used by a web-browser implementation). The
|
the facilities that would be used by a web-browser implementation). The
|
||||||
implementation conforms to the HTTP/1.1 standard,
|
implementation conforms to the HTTP/1.1 standard,
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
|
<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
|
||||||
2616</a>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -67,8 +66,7 @@ local http = require("socket.http")
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
URLs must conform to
|
URLs must conform to
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
|
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
|
||||||
1738</a>,
|
|
||||||
that is, an URL is a string in the form:
|
that is, an URL is a string in the form:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -97,8 +95,9 @@ headers = {<br>
|
|||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Field names are case insensitive (as specified by the standard) and all
|
Field names are case insensitive (as specified by the standard) and all
|
||||||
functions work with lowercase field names.
|
functions work with lowercase field names (but see
|
||||||
|
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
|
||||||
Field values are left unmodified.
|
Field values are left unmodified.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -113,15 +112,19 @@ the HTTP module:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li> <tt>PORT</tt>: default port used for connections;
|
<li> <tt>PROXY</tt>: default proxy used for connections;
|
||||||
<li> <tt>PROXY</tt>: default proxy used for connections;
|
|
||||||
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
|
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
|
||||||
<li> <tt>USERAGENT</tt>: default user agent reported to server.
|
<li> <tt>USERAGENT</tt>: default user agent reported to server.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<p class=note id="post">
|
||||||
|
Note: These constants are global. Changing them will also
|
||||||
|
change the behavior other code that might be using LuaSocket.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=request>
|
<p class=name id="request">
|
||||||
http.<b>request(</b>url [, body]<b>)</b><br>
|
http.<b>request(</b>url [, body]<b>)</b><br>
|
||||||
http.<b>request{</b><br>
|
http.<b>request{</b><br>
|
||||||
url = <i>string</i>,<br>
|
url = <i>string</i>,<br>
|
||||||
@@ -132,7 +135,8 @@ http.<b>request{</b><br>
|
|||||||
[step = <i>LTN12 pump step</i>,]<br>
|
[step = <i>LTN12 pump step</i>,]<br>
|
||||||
[proxy = <i>string</i>,]<br>
|
[proxy = <i>string</i>,]<br>
|
||||||
[redirect = <i>boolean</i>,]<br>
|
[redirect = <i>boolean</i>,]<br>
|
||||||
[create = <i>function</i>]<br>
|
[create = <i>function</i>,]<br>
|
||||||
|
[maxredirects = <i>number</i>]<br>
|
||||||
<b>}</b>
|
<b>}</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -182,6 +186,7 @@ Defaults to the LTN12 <tt>pump.step</tt> function.
|
|||||||
function from automatically following 301 or 302 server redirect messages;
|
function from automatically following 301 or 302 server redirect messages;
|
||||||
<li><tt>create</tt>: An optional function to be used instead of
|
<li><tt>create</tt>: An optional function to be used instead of
|
||||||
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
|
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
|
||||||
|
<li><tt>maxredirects</tt>: An optional number specifying the maximum number of redirects to follow. Defaults to <tt>5</tt> if not specified. A boolean <tt>false</tt> value means no maximum (unlimited).
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
@@ -199,8 +204,7 @@ it usually returns a message body (a web page informing the
|
|||||||
URL was not found or some other useless page). To make sure the
|
URL was not found or some other useless page). To make sure the
|
||||||
operation was successful, check the returned status <tt>code</tt>. For
|
operation was successful, check the returned status <tt>code</tt>. For
|
||||||
a list of the possible values and their meanings, refer to <a
|
a list of the possible values and their meanings, refer to <a
|
||||||
href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
|
href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
|
||||||
2616</a>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
@@ -259,7 +263,7 @@ r, c, h = http.request {
|
|||||||
-- }
|
-- }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p class=note id=post>
|
<p class=note id="post">
|
||||||
Note: When sending a POST request, simple interface adds a
|
Note: When sending a POST request, simple interface adds a
|
||||||
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
|
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
|
||||||
header to the request. This is the type used by
|
header to the request. This is the type used by
|
||||||
@@ -267,7 +271,7 @@ HTML forms. If you need another type, use the generic
|
|||||||
interface.
|
interface.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note id=authentication>
|
<p class=note id="authentication">
|
||||||
Note: Some URLs are protected by their
|
Note: Some URLs are protected by their
|
||||||
servers from anonymous download. For those URLs, the server must receive
|
servers from anonymous download. For those URLs, the server must receive
|
||||||
some sort of authentication along with the request or it will deny
|
some sort of authentication along with the request or it will deny
|
||||||
@@ -278,7 +282,7 @@ download and return status "401 Authentication Required".
|
|||||||
The HTTP/1.1 standard defines two authentication methods: the Basic
|
The HTTP/1.1 standard defines two authentication methods: the Basic
|
||||||
Authentication Scheme and the Digest Authentication Scheme, both
|
Authentication Scheme and the Digest Authentication Scheme, both
|
||||||
explained in detail in
|
explained in detail in
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2068.txt">RFC 2068</a>.
|
<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>The Basic Authentication Scheme sends
|
<p class=note>The Basic Authentication Scheme sends
|
||||||
@@ -304,7 +308,7 @@ b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
|
|||||||
-- the request directly.
|
-- the request directly.
|
||||||
r, c = http.request {
|
r, c = http.request {
|
||||||
url = "http://www.example.com/private/index.html",
|
url = "http://www.example.com/private/index.html",
|
||||||
headers = { authentication = "Basic " .. (mime.b64("fulano:silva")) }
|
headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -314,16 +318,16 @@ r, c = http.request {
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
Last modified by Diego Nehab on <br>
|
Last modified by Eric Westbrook on <br>
|
||||||
Thu Apr 20 00:25:26 EDT 2006
|
Sat Feb 23 19:09:42 UTC 2019
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
|
|||||||
130
doc/index.html
130
doc/index.html
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -49,7 +49,7 @@ functionality commonly needed by applications that deal with the Internet.
|
|||||||
The core support has been implemented so that it is both efficient and
|
The core support has been implemented so that it is both efficient and
|
||||||
simple to use. It is available to any Lua application once it has been
|
simple to use. It is available to any Lua application once it has been
|
||||||
properly initialized by the interpreter in use. The code has been tested
|
properly initialized by the interpreter in use. The code has been tested
|
||||||
and runs well on several Windows and Unix platforms. </p>
|
and runs well on several Windows and UNIX platforms. </p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Among the support modules, the most commonly used implement the
|
Among the support modules, the most commonly used implement the
|
||||||
@@ -78,8 +78,8 @@ LuaSocket.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Copyright © 2004-2007 Diego Nehab. All rights reserved. <br>
|
Copyright © 1999-2013 Diego Nehab. All rights reserved. <br>
|
||||||
Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
|
Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
@@ -87,25 +87,18 @@ Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
|
|||||||
<h2 id=download>Download</h2>
|
<h2 id=download>Download</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
LuaSocket version 2.0.2 is now available for download! It is
|
LuaSocket version 3.0-rc1 is now available for download!
|
||||||
compatible with Lua 5.1, and has
|
It is compatible with Lua 5.1 and 5.2, and has
|
||||||
been tested on Windows XP, Linux, and Mac OS X. Chances
|
been tested on Windows XP, Linux, and Mac OS X. Chances
|
||||||
are it works well on most UNIX distributions and Windows flavors.
|
are it works well on most UNIX distributions and Windows flavors.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The library can be downloaded in source code from the
|
The current version of the library can be found at
|
||||||
<a href=http://luaforge.net/projects/luasocket/>LuaSocket
|
the <a href="https://github.com/diegonehab/luasocket">LuaSocket
|
||||||
project page</a> at LuaForge.
|
project page</a> on GitHub. Besides the full C and Lua source code
|
||||||
Besides the full C and Lua source code for the library, the distribution
|
for the library, the distribution contains several examples,
|
||||||
contains several examples, this user's manual and basic test procedures.
|
this user's manual and basic test procedures.
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Danilo Tuler is maintaining Win32 binaries for LuaSocket, which are also
|
|
||||||
available from LuaForge. These are compatible with the
|
|
||||||
<a href=http://luaforge.net/projects/luabinaries>LuaBinaries</a>,
|
|
||||||
also available from LuaForge.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p> Take a look at the <a
|
<p> Take a look at the <a
|
||||||
@@ -118,14 +111,14 @@ manual to find out how to properly install the library.
|
|||||||
<h2 id=thanks>Special thanks</h2>
|
<h2 id=thanks>Special thanks</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Throughout LuaSocket's history, many people gave suggestions that helped
|
This marks the first release of LuaSocket that
|
||||||
improve it. For that, I thank the Lua community.
|
wholeheartedly embraces the open-source development
|
||||||
Special thanks go to
|
philosophy. After a long hiatus, Matthew Wild finally
|
||||||
David Burgess, who has helped push the library to a new level of quality and
|
convinced me it was time for a release including IPv6 and
|
||||||
from whom I have learned a lot of stuff that doesn't show up in RFCs.
|
Lua 5.2 support. It was more work than we anticipated.
|
||||||
Special thanks also to Carlos Cassino, who played a big part in the
|
Special thanks to Sam Roberts, Florian Zeitz, and Paul
|
||||||
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall
|
Aurich, Liam Devine, Alexey Melnichuk, and everybody else
|
||||||
has been helping a lot too! Thanks to you all!
|
that has helped bring this library back to life.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
@@ -133,41 +126,58 @@ has been helping a lot too! Thanks to you all!
|
|||||||
<h2 id=new>What's New</h2>
|
<h2 id=new>What's New</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
2.0.2 is just a bug-fix/update release.
|
Main changes for LuaSocket 3.0-rc1 are IPv6 support
|
||||||
|
and Lua 5.2 compatibility.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
|
<li> Added: Compatible with Lua 5.2
|
||||||
<li> Fixed: return values are consistent when reading from closed sockets;
|
<ul>
|
||||||
<li> Fixed: case sensitivity in headers of multipart
|
<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
|
||||||
messages in smtp.message() (Graham Henstridge);
|
package tables will <em>not</em> be exported as globals!
|
||||||
<li> Fixed a couple instances of error() being called instead of
|
|
||||||
base.error(). These would cause an error when an error was
|
|
||||||
reported :) (Ketmar Dark);
|
|
||||||
<li> Fixed: test script now uses pairs() iterator instead
|
|
||||||
of the old Lua syntax (Robert Dodier).
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<li> Added: IPv6 support;
|
||||||
<p>
|
|
||||||
2.0.1 is just a bug-fix/update release.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li> Updated: now using <tt>compat-5.1r5</tt>;
|
<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
|
||||||
<li> Improved: <tt>http.request</tt> is more robust to
|
<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
|
||||||
malformed URLs (Adrian Sietsma);
|
IPv6 addresses, and return the socket family as a third value;
|
||||||
<li> Improved: the simple <tt>http.request</tt> interface sends a
|
<li> URL module updated to support IPv6 host names;
|
||||||
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
|
<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
|
||||||
header (William Trenker);
|
<li> New <tt>socket.dns.getaddrinfo</tt> and
|
||||||
<li> Improved: <tt>http.request</tt> is robust to evil
|
<tt>socket.dns.getnameinfo</tt> functions;
|
||||||
servers that send inappropriate 100-continue messages
|
</ul>
|
||||||
(David Burgess);
|
<li> Added: <tt>getoption</tt> method;
|
||||||
<li> Fixed: <tt>http.request</tt> was using the old host header during
|
<li> Fixed: <tt>url.unescape</tt> was returning additional values;
|
||||||
redirects (Florian Berger);
|
<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
|
||||||
<li> Fixed: sample <tt>unix.c</tt> had fallen through the
|
<tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
|
||||||
cracks during development (Matthew Percival);
|
mistaking their own stack slots for functions arguments;
|
||||||
<li> Fixed: error code was not being propagated correctly in
|
<li> Fixed: Receiving zero-length datagram is now possible;
|
||||||
ftp.lua (David Burgess).
|
<li> Improved: Hidden all internal library symbols;
|
||||||
|
<li> Improved: Better error messages;
|
||||||
|
<li> Improved: Better documentation of socket options.
|
||||||
|
<li> Fixed: manual sample of HTTP authentication now uses correct
|
||||||
|
"authorization" header (Alexandre Ittner);
|
||||||
|
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
|
||||||
|
<li> Fixed: receive() returns immediatelly if prefix can satisfy
|
||||||
|
bytes requested (M Joonas Pihlaja);
|
||||||
|
<li> Fixed: multicast didn't work on Windows, or anywhere
|
||||||
|
else for that matter (Herbert Leuwer, Adrian Sietsma);
|
||||||
|
<li> Fixed: select() now reports an error when called with more
|
||||||
|
sockets than FD_SETSIZE (Lorenzo Leonini);
|
||||||
|
<li> Fixed: manual links to home.html changed to index.html
|
||||||
|
(Robert Hahn);
|
||||||
|
<li> Fixed: mime.unb64() would return an empty string on results that started
|
||||||
|
with a null character (Robert Raschke);
|
||||||
|
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
|
||||||
|
<li> Fixed: calling sleep() with negative numbers could
|
||||||
|
block forever, wasting CPU. Now it returns immediately (MPB);
|
||||||
|
<li> Improved: FTP commands are now sent in upper case to
|
||||||
|
help buggy servers (Anders Eurenius);
|
||||||
|
<li> Improved: known headers now sent in canonic
|
||||||
|
capitalization to help buggy servers (Joseph Stewart);
|
||||||
|
<li> Improved: Clarified tcp:receive() in the manual (MPB);
|
||||||
|
<li> Improved: Decent makefiles (LHF).
|
||||||
|
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
@@ -176,7 +186,7 @@ ftp.lua (David Burgess).
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
All previous versions of the LuaSocket library can be downloaded <a
|
All previous versions of the LuaSocket library can be downloaded <a
|
||||||
href="http://www.cs.princeton.edu/~diego/professional/luasocket/old">
|
href="http://www.impa.br/~diego/software/luasocket/old">
|
||||||
here</a>. Although these versions are no longer supported, they are
|
here</a>. Although these versions are no longer supported, they are
|
||||||
still available for those that have compatibility issues.
|
still available for those that have compatibility issues.
|
||||||
</p>
|
</p>
|
||||||
@@ -187,7 +197,7 @@ still available for those that have compatibility issues.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -195,7 +205,7 @@ still available for those that have compatibility issues.
|
|||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
Last modified by Diego Nehab on <br>
|
Last modified by Diego Nehab on <br>
|
||||||
Thu Apr 20 00:25:23 EDT 2006
|
Tue Jun 11 18:50:23 HKT 2013
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ Installation">
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -39,24 +39,10 @@ Installation">
|
|||||||
|
|
||||||
<h2>Installation</h2>
|
<h2>Installation</h2>
|
||||||
|
|
||||||
<p> LuaSocket 2.0.2 uses the new package system for Lua 5.1.
|
<p> Here we describe the standard distribution. If the
|
||||||
All Lua library developers are encouraged to update their libraries so that
|
standard doesn't meet your needs, we refer you to the Lua
|
||||||
all libraries can coexist peacefully and users can benefit from the
|
discussion list, where any question about the package scheme
|
||||||
standardization and flexibility of the standard.
|
will likely already have been answered. </p>
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Those stuck with Lua 5.0 will need the
|
|
||||||
<a href=http://www.keplerproject.org/compat/>compat-5.1</a>
|
|
||||||
module. It is maintained by
|
|
||||||
<a href=http://www.keplerproject.org/>The Kepler
|
|
||||||
Project</a>'s team, and implements the Lua 5.1 package proposal
|
|
||||||
on top of Lua 5.0. </p>
|
|
||||||
|
|
||||||
<p> Here we will only describe the standard distribution.
|
|
||||||
If the standard doesn't meet your needs, we refer you to the
|
|
||||||
Lua discussion list, where any question about the package
|
|
||||||
scheme will likely already have been answered. </p>
|
|
||||||
|
|
||||||
<h3>Directory structure</h3>
|
<h3>Directory structure</h3>
|
||||||
|
|
||||||
@@ -64,14 +50,19 @@ scheme will likely already have been answered. </p>
|
|||||||
directories, one for system dependent files, and another for system
|
directories, one for system dependent files, and another for system
|
||||||
independent files. Let's call these directories <tt><CDIR></tt>
|
independent files. Let's call these directories <tt><CDIR></tt>
|
||||||
and <tt><LDIR></tt>, respectively.
|
and <tt><LDIR></tt>, respectively.
|
||||||
For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for
|
For example, in my laptp, Lua 5.1 is configured to
|
||||||
<tt><CDIR></tt> and '<tt>/usr/local/share/lua/5.0</tt>' for
|
use '<tt>/usr/local/lib/lua/5.1</tt>' for
|
||||||
<tt><LDIR></tt>. On Windows, sometimes only one directory is used, say
|
<tt><CDIR></tt> and '<tt>/usr/local/share/lua/5.1</tt>' for
|
||||||
'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket
|
<tt><LDIR></tt>. On Windows, <tt><CDIR></tt>
|
||||||
|
usually points to the directory where the Lua executable is
|
||||||
|
found, and <tt><LDIR></tt> points to a
|
||||||
|
<tt>lua/</tt> directory inside <tt><CDIR></tt>. (These
|
||||||
|
settings can be overridden by environment variables
|
||||||
|
<tt>LUA_PATH</tt> and <tt>LUA_CPATH</tt>. See the Lua
|
||||||
|
documentation for details.) Here is the standard LuaSocket
|
||||||
distribution directory structure:</p>
|
distribution directory structure:</p>
|
||||||
|
|
||||||
<pre class=example>
|
<pre class=example>
|
||||||
<LDIR>/compat-5.1.lua
|
|
||||||
<LDIR>/ltn12.lua
|
<LDIR>/ltn12.lua
|
||||||
<LDIR>/socket.lua
|
<LDIR>/socket.lua
|
||||||
<CDIR>/socket/core.dll
|
<CDIR>/socket/core.dll
|
||||||
@@ -88,33 +79,6 @@ distribution directory structure:</p>
|
|||||||
would be replaced by <tt>core.so</tt>.
|
would be replaced by <tt>core.so</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p> In order for the interpreter to find all LuaSocket components, three
|
|
||||||
environment variables need to be set. The first environment variable tells
|
|
||||||
the interpreter to load the <tt>compat-5.1.lua</tt> module at startup: </p>
|
|
||||||
|
|
||||||
<pre class=example>
|
|
||||||
LUA_INIT=@<LDIR>/compat-5.1.lua
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This is only need for Lua 5.0! Lua 5.1 comes with
|
|
||||||
the package system built in, of course.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The other two environment variables instruct the compatibility module to
|
|
||||||
look for dynamic libraries and extension modules in the appropriate
|
|
||||||
directories and with the appropriate filename extensions.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre class=example>
|
|
||||||
LUA_PATH=<LDIR>/?.lua;?.lua
|
|
||||||
LUA_CPATH=<CDIR>/?.dll;?.dll
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p> Again, naturally, on Unix systems the shared library extension would be
|
|
||||||
<tt>.so</tt> instead of <tt>.dll</tt>.</p>
|
|
||||||
|
|
||||||
<h3>Using LuaSocket</h3>
|
<h3>Using LuaSocket</h3>
|
||||||
|
|
||||||
<p> With the above setup, and an interpreter with shared library support,
|
<p> With the above setup, and an interpreter with shared library support,
|
||||||
@@ -122,19 +86,19 @@ it should be easy to use LuaSocket. Just fire the interpreter and use the
|
|||||||
<tt>require</tt> function to gain access to whatever module you need:</p>
|
<tt>require</tt> function to gain access to whatever module you need:</p>
|
||||||
|
|
||||||
<pre class=example>
|
<pre class=example>
|
||||||
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
|
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
|
||||||
> socket = require("socket")
|
> socket = require("socket")
|
||||||
> print(socket._VERSION)
|
> print(socket._VERSION)
|
||||||
--> LuaSocket 2.0.2
|
--> LuaSocket 3.0-rc1
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p> Each module loads their dependencies automatically, so you only need to
|
<p> Each module loads their dependencies automatically, so you only need to
|
||||||
load the modules you directly depend upon: </p>
|
load the modules you directly depend upon: </p>
|
||||||
|
|
||||||
<pre class=example>
|
<pre class=example>
|
||||||
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
|
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
|
||||||
> http = require("socket.http")
|
> http = require("socket.http")
|
||||||
> print(http.request("http://www.cs.princeton.edu/~diego/professional/luasocket"))
|
> print(http.request("http://www.impa.br/~diego/software/luasocket"))
|
||||||
--> homepage gets dumped to terminal
|
--> homepage gets dumped to terminal
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -144,8 +108,8 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -153,7 +117,7 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
|
|||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
Last modified by Diego Nehab on <br>
|
Last modified by Diego Nehab on <br>
|
||||||
Thu Apr 20 00:25:30 EDT 2006
|
Tue Jun 11 19:06:14 HKT 2013
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ Library, Support">
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -314,8 +314,8 @@ and many others are covered by the <a href=reference.html>reference manual</a>.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ Pump, Support, Library">
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -224,8 +224,8 @@ local ltn12 = require("ltn12")
|
|||||||
|
|
||||||
-- copy a file
|
-- copy a file
|
||||||
ltn12.pump.all(
|
ltn12.pump.all(
|
||||||
ltn12.source.file(io.open("original.png")),
|
ltn12.source.file(io.open("original.png", "rb")),
|
||||||
ltn12.sink.file(io.open("copy.png"))
|
ltn12.sink.file(io.open("copy.png", "wb"))
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -379,8 +379,8 @@ local ltn12 = require("ltn12")
|
|||||||
|
|
||||||
-- copy a file
|
-- copy a file
|
||||||
ltn12.pump.all(
|
ltn12.pump.all(
|
||||||
ltn12.source.file(io.open("original.png")),
|
ltn12.source.file(io.open("original.png", "rb")),
|
||||||
ltn12.sink.file(io.open("copy.png"))
|
ltn12.sink.file(io.open("copy.png", "wb"))
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -405,14 +405,24 @@ Creates and returns a source that produces the contents of a
|
|||||||
<tt>string</tt>, chunk by chunk.
|
<tt>string</tt>, chunk by chunk.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- table +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="source.table">
|
||||||
|
ltn12.source.<b>table(</b>table<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Creates and returns a source that produces the numerically-indexed values of a <tt>table</tt> successively beginning at 1. The source returns nil (end-of-stream) whenever a nil value is produced by the current index, which proceeds forward regardless.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<div class=footer>
|
<div class=footer>
|
||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -44,11 +44,11 @@ content transfer encodings, such as Base64 and Quoted-Printable.
|
|||||||
It also provides functions to break text into lines and change
|
It also provides functions to break text into lines and change
|
||||||
the end-of-line convention.
|
the end-of-line convention.
|
||||||
MIME is described mainly in
|
MIME is described mainly in
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>,
|
<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>,
|
<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>,
|
<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and
|
<a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2048.txt">2049</a>.
|
<a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -72,34 +72,6 @@ local mime = require("mime")
|
|||||||
|
|
||||||
<h3 id=high>High-level filters</h3>
|
<h3 id=high>High-level filters</h3>
|
||||||
|
|
||||||
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
|
||||||
|
|
||||||
<p class=name id="normalize">
|
|
||||||
mime.<b>normalize(</b>[marker]<b>)</b>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=description>
|
|
||||||
Converts most common end-of-line markers to a specific given marker.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=parameters>
|
|
||||||
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
|
|
||||||
end-of-line marker defined by the MIME standard.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=return>
|
|
||||||
The function returns a filter that performs the conversion.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
Note: There is no perfect solution to this problem. Different end-of-line
|
|
||||||
markers are an evil that will probably plague developers forever.
|
|
||||||
This function, however, will work perfectly for text created with any of
|
|
||||||
the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
|
|
||||||
or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
|
|
||||||
markers, the function will still work well, although it doesn't
|
|
||||||
guarantee that the number of empty lines will be correct.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
@@ -159,6 +131,35 @@ base64 = ltn12.filter.chain(
|
|||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="normalize">
|
||||||
|
mime.<b>normalize(</b>[marker]<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Converts most common end-of-line markers to a specific given marker.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=parameters>
|
||||||
|
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
|
||||||
|
end-of-line marker defined by the MIME standard.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
The function returns a filter that performs the conversion.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: There is no perfect solution to this problem. Different end-of-line
|
||||||
|
markers are an evil that will probably plague developers forever.
|
||||||
|
This function, however, will work perfectly for text created with any of
|
||||||
|
the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
|
||||||
|
or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
|
||||||
|
markers, the function will still work well, although it doesn't
|
||||||
|
guarantee that the number of empty lines will be correct.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id="stuff">
|
<p class=name id="stuff">
|
||||||
@@ -457,8 +458,8 @@ marker.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -466,7 +467,7 @@ marker.
|
|||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
Last modified by Diego Nehab on <br>
|
Last modified by Diego Nehab on <br>
|
||||||
Thu Apr 20 00:25:44 EDT 2006
|
Fri Mar 4 15:19:17 BRT 2016
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ body {
|
|||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
font-family: "Verdana", sans-serif;
|
font-family: "Verdana", sans-serif;
|
||||||
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
tt {
|
tt {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ Support, Manual">
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -42,9 +42,10 @@ Support, Manual">
|
|||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="dns.html">DNS (in socket)</a>
|
<a href="dns.html">DNS (in socket)</a>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="dns.html#toip">toip</a>,
|
<a href="dns.html#getaddrinfo">getaddrinfo</a>,
|
||||||
|
<a href="dns.html#gethostname">gethostname</a>,
|
||||||
<a href="dns.html#tohostname">tohostname</a>,
|
<a href="dns.html#tohostname">tohostname</a>,
|
||||||
<a href="dns.html#gethostname">gethostname</a>.
|
<a href="dns.html#toip">toip</a>.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
@@ -98,7 +99,8 @@ Support, Manual">
|
|||||||
<a href="ltn12.html#source.error">error</a>,
|
<a href="ltn12.html#source.error">error</a>,
|
||||||
<a href="ltn12.html#source.file">file</a>,
|
<a href="ltn12.html#source.file">file</a>,
|
||||||
<a href="ltn12.html#source.simplify">simplify</a>,
|
<a href="ltn12.html#source.simplify">simplify</a>,
|
||||||
<a href="ltn12.html#source.string">string</a>.
|
<a href="ltn12.html#source.string">string</a>,
|
||||||
|
<a href="ltn12.html#source.table">table</a>.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
@@ -108,9 +110,9 @@ Support, Manual">
|
|||||||
<a href="mime.html">MIME</a>
|
<a href="mime.html">MIME</a>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="mime.html#high">high-level</a>:
|
<a href="mime.html#high">high-level</a>:
|
||||||
<a href="mime.html#normalize">normalize</a>,
|
|
||||||
<a href="mime.html#decode">decode</a>,
|
<a href="mime.html#decode">decode</a>,
|
||||||
<a href="mime.html#encode">encode</a>,
|
<a href="mime.html#encode">encode</a>,
|
||||||
|
<a href="mime.html#normalize">normalize</a>,
|
||||||
<a href="mime.html#stuff">stuff</a>,
|
<a href="mime.html#stuff">stuff</a>,
|
||||||
<a href="mime.html#wrap">wrap</a>.
|
<a href="mime.html#wrap">wrap</a>.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
@@ -120,10 +122,10 @@ Support, Manual">
|
|||||||
<a href="mime.html#dot">dot</a>,
|
<a href="mime.html#dot">dot</a>,
|
||||||
<a href="mime.html#eol">eol</a>,
|
<a href="mime.html#eol">eol</a>,
|
||||||
<a href="mime.html#qp">qp</a>,
|
<a href="mime.html#qp">qp</a>,
|
||||||
<a href="mime.html#wrp">wrp</a>,
|
<a href="mime.html#qpwrp">qpwrp</a>,
|
||||||
<a href="mime.html#qpwrp">qpwrp</a>.
|
|
||||||
<a href="mime.html#unb64">unb64</a>,
|
<a href="mime.html#unb64">unb64</a>,
|
||||||
<a href="mime.html#unqp">unqp</a>,
|
<a href="mime.html#unqp">unqp</a>,
|
||||||
|
<a href="mime.html#wrp">wrp</a>.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
@@ -142,19 +144,31 @@ Support, Manual">
|
|||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="socket.html">Socket</a>
|
<a href="socket.html">Socket</a>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
|
<a href="socket.html#bind">bind</a>,
|
||||||
|
<a href="socket.html#connect">connect</a>,
|
||||||
|
<a href="socket.html#connect">connect4</a>,
|
||||||
|
<a href="socket.html#connect">connect6</a>,
|
||||||
|
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
|
||||||
<a href="socket.html#debug">_DEBUG</a>,
|
<a href="socket.html#debug">_DEBUG</a>,
|
||||||
<a href="dns.html#dns">dns</a>,
|
<a href="dns.html#dns">dns</a>,
|
||||||
<a href="socket.html#gettime">gettime</a>,
|
<a href="socket.html#gettime">gettime</a>,
|
||||||
|
<a href="socket.html#headers.canonic">headers.canonic</a>,
|
||||||
<a href="socket.html#newtry">newtry</a>,
|
<a href="socket.html#newtry">newtry</a>,
|
||||||
<a href="socket.html#protect">protect</a>,
|
<a href="socket.html#protect">protect</a>,
|
||||||
<a href="socket.html#select">select</a>,
|
<a href="socket.html#select">select</a>,
|
||||||
<a href="socket.html#sink">sink</a>,
|
<a href="socket.html#sink">sink</a>,
|
||||||
<a href="socket.html#skip">skip</a>,
|
<a href="socket.html#skip">skip</a>,
|
||||||
<a href="socket.html#sleep">sleep</a>,
|
<a href="socket.html#sleep">sleep</a>,
|
||||||
|
<a href="socket.html#setsize">_SETSIZE</a>,
|
||||||
|
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
|
||||||
<a href="socket.html#source">source</a>,
|
<a href="socket.html#source">source</a>,
|
||||||
<a href="tcp.html#tcp">tcp</a>,
|
<a href="tcp.html#socket.tcp">tcp</a>,
|
||||||
|
<a href="tcp.html#socket.tcp4">tcp4</a>,
|
||||||
|
<a href="tcp.html#socket.tcp6">tcp6</a>,
|
||||||
<a href="socket.html#try">try</a>,
|
<a href="socket.html#try">try</a>,
|
||||||
<a href="udp.html#udp">udp</a>,
|
<a href="udp.html#socket.udp">udp</a>,
|
||||||
|
<a href="udp.html#socket.udp4">udp4</a>,
|
||||||
|
<a href="udp.html#socket.udp6">udp6</a>,
|
||||||
<a href="socket.html#version">_VERSION</a>.
|
<a href="socket.html#version">_VERSION</a>.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
@@ -168,11 +182,17 @@ Support, Manual">
|
|||||||
<a href="tcp.html#bind">bind</a>,
|
<a href="tcp.html#bind">bind</a>,
|
||||||
<a href="tcp.html#close">close</a>,
|
<a href="tcp.html#close">close</a>,
|
||||||
<a href="tcp.html#connect">connect</a>,
|
<a href="tcp.html#connect">connect</a>,
|
||||||
|
<a href="tcp.html#dirty">dirty</a>,
|
||||||
|
<a href="tcp.html#getfd">getfd</a>,
|
||||||
|
<a href="tcp.html#getoption">getoption</a>,
|
||||||
<a href="tcp.html#getpeername">getpeername</a>,
|
<a href="tcp.html#getpeername">getpeername</a>,
|
||||||
<a href="tcp.html#getsockname">getsockname</a>,
|
<a href="tcp.html#getsockname">getsockname</a>,
|
||||||
<a href="tcp.html#getstats">getstats</a>,
|
<a href="tcp.html#getstats">getstats</a>,
|
||||||
|
<a href="tcp.html#gettimeout">gettimeout</a>,
|
||||||
|
<a href="tcp.html#listen">listen</a>,
|
||||||
<a href="tcp.html#receive">receive</a>,
|
<a href="tcp.html#receive">receive</a>,
|
||||||
<a href="tcp.html#send">send</a>,
|
<a href="tcp.html#send">send</a>,
|
||||||
|
<a href="tcp.html#setfd">setfd</a>,
|
||||||
<a href="tcp.html#setoption">setoption</a>,
|
<a href="tcp.html#setoption">setoption</a>,
|
||||||
<a href="tcp.html#setstats">setstats</a>,
|
<a href="tcp.html#setstats">setstats</a>,
|
||||||
<a href="tcp.html#settimeout">settimeout</a>,
|
<a href="tcp.html#settimeout">settimeout</a>,
|
||||||
@@ -186,8 +206,10 @@ Support, Manual">
|
|||||||
<a href="udp.html">UDP (in socket)</a>
|
<a href="udp.html">UDP (in socket)</a>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="udp.html#close">close</a>,
|
<a href="udp.html#close">close</a>,
|
||||||
|
<a href="udp.html#getoption">getoption</a>,
|
||||||
<a href="udp.html#getpeername">getpeername</a>,
|
<a href="udp.html#getpeername">getpeername</a>,
|
||||||
<a href="udp.html#getsockname">getsockname</a>,
|
<a href="udp.html#getsockname">getsockname</a>,
|
||||||
|
<a href="udp.html#gettimeout">gettimeout</a>,
|
||||||
<a href="udp.html#receive">receive</a>,
|
<a href="udp.html#receive">receive</a>,
|
||||||
<a href="udp.html#receivefrom">receivefrom</a>,
|
<a href="udp.html#receivefrom">receivefrom</a>,
|
||||||
<a href="udp.html#send">send</a>,
|
<a href="udp.html#send">send</a>,
|
||||||
@@ -220,8 +242,8 @@ Support, Manual">
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
343
doc/smtp.html
343
doc/smtp.html
@@ -25,8 +25,8 @@ Library, Support">
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -48,14 +48,13 @@ control (if you bother to read the code).
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>The implementation conforms to the Simple Mail Transfer Protocol,
|
<p>The implementation conforms to the Simple Mail Transfer Protocol,
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>.
|
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>.
|
||||||
Another RFC of interest is <a
|
Another RFC of interest is <a
|
||||||
href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>,
|
href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
|
||||||
which governs the Internet Message Format.
|
which governs the Internet Message Format.
|
||||||
Multipart messages (those that contain attachments) are part
|
Multipart messages (those that contain attachments) are part
|
||||||
of the MIME standard, but described mainly
|
of the MIME standard, but described mainly
|
||||||
in <a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">RFC
|
in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
|
||||||
2046</a>
|
|
||||||
|
|
||||||
<p> In the description below, good understanding of <a
|
<p> In the description below, good understanding of <a
|
||||||
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
|
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
|
||||||
@@ -91,8 +90,9 @@ headers = {<br>
|
|||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Field names are case insensitive (as specified by the standard) and all
|
Field names are case insensitive (as specified by the standard) and all
|
||||||
functions work with lowercase field names.
|
functions work with lowercase field names (but see
|
||||||
|
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
|
||||||
Field values are left unmodified.
|
Field values are left unmodified.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -114,167 +114,6 @@ the SMTP module:
|
|||||||
<li> <tt>ZONE</tt>: default time zone.
|
<li> <tt>ZONE</tt>: default time zone.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
|
||||||
|
|
||||||
<p class=name id=send>
|
|
||||||
smtp.<b>send{</b><br>
|
|
||||||
from = <i>string</i>,<br>
|
|
||||||
rcpt = <i>string</i> or <i>string-table</i>,<br>
|
|
||||||
source = <i>LTN12 source</i>,<br>
|
|
||||||
[user = <i>string</i>,]<br>
|
|
||||||
[password = <i>string</i>,]<br>
|
|
||||||
[server = <i>string</i>,]<br>
|
|
||||||
[port = <i>number</i>,]<br>
|
|
||||||
[domain = <i>string</i>,]<br>
|
|
||||||
[step = <i>LTN12 pump step</i>,]<br>
|
|
||||||
[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><fulano@example.com></tt>" in the <tt>from</tt> and
|
|
||||||
<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
|
|
||||||
addresses can take whatever form you like. </p>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
Big note: There is a good deal of misconception with the use of the
|
|
||||||
destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
|
|
||||||
and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
|
|
||||||
'<tt>Bcc</tt>' header to your messages because it will probably do the
|
|
||||||
exact opposite of what you expect.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
|
|
||||||
message. Each recipient of an SMTP mail message receives a copy of the
|
|
||||||
message body along with the headers, and nothing more. The headers
|
|
||||||
<em>are</em> part of the message and should be produced by the
|
|
||||||
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
|
|
||||||
<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em>
|
|
||||||
part of the message and will not be sent to anyone.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>
|
|
||||||
has two <em>important and short</em> sections, "3.6.3. Destination address
|
|
||||||
fields" and "5. Security considerations", explaining the proper
|
|
||||||
use of these headers. Here is a summary of what it says:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
|
|
||||||
of the message;
|
|
||||||
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
|
|
||||||
making a copy on a typewriter using carbon paper) contains the
|
|
||||||
addresses of others who are to receive the message, though the
|
|
||||||
content of the message may not be directed at them;
|
|
||||||
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
|
|
||||||
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
The LuaSocket <tt>send</tt> function does not care or interpret the
|
|
||||||
headers you send, but it gives you full control over what is sent and
|
|
||||||
to whom it is sent:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li> If someone is to receive the message, the e-mail address <em>has</em>
|
|
||||||
to be in the recipient list. This is the only parameter that controls who
|
|
||||||
gets a copy of the message;
|
|
||||||
<li> If there are multiple recipients, none of them will automatically
|
|
||||||
know that someone else got that message. That is, the default behavior is
|
|
||||||
similar to the <tt>Bcc</tt> field of popular e-mail clients;
|
|
||||||
<li> It is up to you to add the <tt>To</tt> header with the list of primary
|
|
||||||
recipients so that other recipients can see it;
|
|
||||||
<li> It is also up to you to add the <tt>Cc</tt> header with the
|
|
||||||
list of additional recipients so that everyone else sees it;
|
|
||||||
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
|
|
||||||
empty. Otherwise, everyone receiving the message will see it and that is
|
|
||||||
exactly what you <em>don't</em> want to happen!
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
I hope this clarifies the issue. Otherwise, please refer to
|
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>
|
|
||||||
and
|
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre class=example>
|
|
||||||
-- load the smtp support
|
|
||||||
local smtp = require("socket.smtp")
|
|
||||||
|
|
||||||
-- Connects to server "localhost" and sends a message to users
|
|
||||||
-- "fulano@example.com", "beltrano@example.com",
|
|
||||||
-- and "sicrano@example.com".
|
|
||||||
-- Note that "fulano" is the primary recipient, "beltrano" receives a
|
|
||||||
-- carbon copy and neither of them knows that "sicrano" received a blind
|
|
||||||
-- carbon copy of the message.
|
|
||||||
from = "<luasocket@example.com>"
|
|
||||||
|
|
||||||
rcpt = {
|
|
||||||
"<fulano@example.com>",
|
|
||||||
"<beltrano@example.com>",
|
|
||||||
"<sicrano@example.com>"
|
|
||||||
}
|
|
||||||
|
|
||||||
mesgt = {
|
|
||||||
headers = {
|
|
||||||
to = "Fulano da Silva <fulano@example.com>",
|
|
||||||
cc = '"Beltrano F. Nunes" <beltrano@example.com>',
|
|
||||||
subject = "My first message"
|
|
||||||
},
|
|
||||||
body = "I hope this works. If it does, I can send you another 1000 copies."
|
|
||||||
}
|
|
||||||
|
|
||||||
r, e = smtp.send{
|
|
||||||
from = from,
|
|
||||||
rcpt = rcpt,
|
|
||||||
source = smtp.message(mesgt)
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=message>
|
<p class=name id=message>
|
||||||
@@ -392,14 +231,176 @@ r, e = smtp.send{
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=send>
|
||||||
|
smtp.<b>send{</b><br>
|
||||||
|
from = <i>string</i>,<br>
|
||||||
|
rcpt = <i>string</i> or <i>string-table</i>,<br>
|
||||||
|
source = <i>LTN12 source</i>,<br>
|
||||||
|
[user = <i>string</i>,]<br>
|
||||||
|
[password = <i>string</i>,]<br>
|
||||||
|
[server = <i>string</i>,]<br>
|
||||||
|
[port = <i>number</i>,]<br>
|
||||||
|
[domain = <i>string</i>,]<br>
|
||||||
|
[step = <i>LTN12 pump step</i>,]<br>
|
||||||
|
[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><fulano@example.com></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 = "<luasocket@example.com>"
|
||||||
|
|
||||||
|
rcpt = {
|
||||||
|
"<fulano@example.com>",
|
||||||
|
"<beltrano@example.com>",
|
||||||
|
"<sicrano@example.com>"
|
||||||
|
}
|
||||||
|
|
||||||
|
mesgt = {
|
||||||
|
headers = {
|
||||||
|
to = "Fulano da Silva <fulano@example.com>",
|
||||||
|
cc = '"Beltrano F. Nunes" <beltrano@example.com>',
|
||||||
|
subject = "My first message"
|
||||||
|
},
|
||||||
|
body = "I hope this works. If it does, I can send you another 1000 copies."
|
||||||
|
}
|
||||||
|
|
||||||
|
r, e = smtp.send{
|
||||||
|
from = from,
|
||||||
|
rcpt = rcpt,
|
||||||
|
source = smtp.message(mesgt)
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<div class=footer>
|
<div class=footer>
|
||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
150
doc/socket.html
150
doc/socket.html
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -51,6 +51,30 @@ To obtain the <tt>socket</tt> namespace, run:
|
|||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="headers.canonic">
|
||||||
|
socket.headers.<b>canonic</b></p>
|
||||||
|
|
||||||
|
<p> The <tt>socket.headers.canonic</tt> table
|
||||||
|
is used by the HTTP and SMTP modules to translate from
|
||||||
|
lowercase field names back into their canonic
|
||||||
|
capitalization. When a lowercase field name exists as a key
|
||||||
|
in this table, the associated value is substituted in
|
||||||
|
whenever the field name is sent out.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can obtain the <tt>headers</tt> namespace if case run-time
|
||||||
|
modifications are required by running:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre class=example>
|
||||||
|
-- loads the headers module
|
||||||
|
local headers = require("headers")
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=bind>
|
<p class=name id=bind>
|
||||||
@@ -73,19 +97,24 @@ set to <tt><b>true</b></tt>.
|
|||||||
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=connect>
|
<p class=name id=connect>
|
||||||
socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b>
|
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
This function is a shortcut that creates and returns a TCP client object
|
This function is a shortcut that creates and returns a TCP client object
|
||||||
connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally,
|
connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
|
||||||
the user can also specify the local address and port to bind
|
the user can also specify the local address and port to bind
|
||||||
(<tt>locaddr</tt> and <tt>locport</tt>).
|
(<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
|
||||||
|
to "<tt>inet</tt>" or "<tt>inet6</tt>".
|
||||||
|
Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
|
||||||
|
connection is created depends on your system configuration. Two variations
|
||||||
|
of connect are defined as simple helper functions that restrict the
|
||||||
|
<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=debug>
|
<p class=name id=debug>
|
||||||
socket.<b>_DEBUG</b>
|
socket.<b>_DEBUG</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -94,6 +123,36 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
|
|||||||
with debug support.
|
with debug support.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=debug>
|
||||||
|
socket.<b>_DATAGRAMSIZE</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Default datagram size used by calls to
|
||||||
|
<a href="udp.html#receive"<tt>receive</tt></a> and
|
||||||
|
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
|
||||||
|
(Unless changed in compile time, the value is 8192.)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=gettime>
|
||||||
|
socket.<b>gettime()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Returns the UNIX time in seconds. You should subtract the values returned by this function
|
||||||
|
to get meaningful values.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre class=example>
|
||||||
|
t = socket.gettime()
|
||||||
|
-- do stuff
|
||||||
|
print(socket.gettime() - t .. " seconds elapsed")
|
||||||
|
</pre>
|
||||||
|
|
||||||
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=newtry>
|
<p class=name id=newtry>
|
||||||
@@ -109,8 +168,7 @@ is raised.
|
|||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Finalizer</tt> is a function that will be called before
|
<tt>Finalizer</tt> is a function that will be called before
|
||||||
<tt>try</tt> throws the exception. It will be called
|
<tt>try</tt> throws the exception.
|
||||||
in <em>protected</em> mode.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
@@ -158,15 +216,9 @@ to throw exceptions.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
Returns an equivalent function that instead of throwing exceptions,
|
Returns an equivalent function that instead of throwing exceptions in case of
|
||||||
returns <tt><b>nil</b></tt> followed by an error message.
|
a failed <a href=#try><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
|
||||||
</p>
|
followed by an error message.
|
||||||
|
|
||||||
<p class=note>
|
|
||||||
Note: Beware that if your function performs some illegal operation that
|
|
||||||
raises an error, the protected function will catch the error and return it
|
|
||||||
as a string. This is because the <a href=#try><tt>try</tt></a> function
|
|
||||||
uses errors as the mechanism to throw exceptions.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
@@ -192,13 +244,24 @@ non-numeric indices) in the arrays will be silently ignored.
|
|||||||
|
|
||||||
<p class=return> The function returns a list with the sockets ready for
|
<p class=return> The function returns a list with the sockets ready for
|
||||||
reading, a list with the sockets ready for writing and an error message.
|
reading, a list with the sockets ready for writing and an error message.
|
||||||
The error message is "<tt>timeout</tt>" if a timeout condition was met and
|
The error message is "<tt>timeout</tt>" if a timeout
|
||||||
|
condition was met, "<tt>select failed</tt>" if the call
|
||||||
|
to <tt>select</tt> failed, and
|
||||||
<tt><b>nil</b></tt> otherwise. The returned tables are
|
<tt><b>nil</b></tt> otherwise. The returned tables are
|
||||||
doubly keyed both by integers and also by the sockets
|
doubly keyed both by integers and also by the sockets
|
||||||
themselves, to simplify the test if a specific socket has
|
themselves, to simplify the test if a specific socket has
|
||||||
changed status.
|
changed status.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
<b>Note:</b> <tt>select</tt> can monitor a limited number
|
||||||
|
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
|
||||||
|
number may be as high as 1024 or as low as 64 by default,
|
||||||
|
depending on the system. It is usually possible to change this
|
||||||
|
at compile time. Invoking <tt>select</tt> with a larger
|
||||||
|
number of sockets will raise an error.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
|
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
|
||||||
on non-blocking TCP sockets. The function may return a socket as
|
on non-blocking TCP sockets. The function may return a socket as
|
||||||
@@ -217,6 +280,22 @@ method or <tt>accept</tt> might block forever.
|
|||||||
it to <tt>select</tt>, it will be ignored.
|
it to <tt>select</tt>, it will be ignored.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id=setsize>
|
||||||
|
socket.<b>_SETSIZE</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
The maximum number of sockets that the <a
|
||||||
|
href=#select><tt>select</tt></a> function can handle.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=sink>
|
<p class=name id=sink>
|
||||||
@@ -288,8 +367,8 @@ Freezes the program execution during a given amount of time.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Time</tt> is the number of seconds to sleep for.
|
<tt>Time</tt> is the number of seconds to sleep for. If
|
||||||
The function truncates <tt>time</tt> down to the nearest integer.
|
<tt>time</tt> is negative, the function returns immediately.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
@@ -324,24 +403,16 @@ side closes the connection.
|
|||||||
The function returns a source with the appropriate behavior.
|
The function returns a source with the appropriate behavior.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- time ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=gettime>
|
<p class=name id=socketinvalid>
|
||||||
socket.<b>gettime()</b>
|
socket.<b>_SOCKETINVALID</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Returns the time in seconds, relative to the origin of the
|
The OS value for an invalid socket.
|
||||||
universe. You should subtract the values returned by this function
|
|
||||||
to get meaningful values.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class=example>
|
|
||||||
t = socket.gettime()
|
|
||||||
-- do stuff
|
|
||||||
print(socket.gettime() - t .. " seconds elapsed")
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=try>
|
<p class=name id=try>
|
||||||
@@ -349,9 +420,9 @@ socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Throws an exception in case of error. The exception can only be caught
|
Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
|
||||||
by the <a href=#protect><tt>protect</tt></a> function. It does not explode
|
<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
|
||||||
into an error message.
|
by a <a href=#protect><tt>protect</tt></a>ed function only.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -362,7 +433,10 @@ nested with <tt>try</tt>.
|
|||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
|
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
|
||||||
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt>. Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub>.
|
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
|
||||||
|
Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
|
||||||
|
in a table with metatable used by <a href=#protect><tt>protect</tt></a> to
|
||||||
|
distinguish exceptions from runtime errors.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class=example>
|
<pre class=example>
|
||||||
@@ -386,8 +460,8 @@ This constant has a string describing the current LuaSocket version.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
413
doc/tcp.html
413
doc/tcp.html
@@ -1,10 +1,10 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||||
"http://www.w3.org/TR/html4/strict.dtd">
|
"http://www.w3.org/TR/html4/strict.dtd">
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta name="description" content="LuaSocket: The TCP/IP support">
|
<meta name="description" content="LuaSocket: The TCP/IP support">
|
||||||
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
|
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
|
||||||
<title>LuaSocket: TCP/IP support</title>
|
<title>LuaSocket: TCP/IP support</title>
|
||||||
<link rel="stylesheet" href="reference.css" type="text/css">
|
<link rel="stylesheet" href="reference.css" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
@@ -24,11 +24,11 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
<hr>
|
<hr>
|
||||||
@@ -36,31 +36,11 @@
|
|||||||
|
|
||||||
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<h2 id=tcp>TCP</h2>
|
<h2 id="tcp">TCP</h2>
|
||||||
|
|
||||||
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
|
||||||
|
|
||||||
<p class=name id=socket.tcp>
|
|
||||||
socket.<b>tcp()</b>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class=description>
|
|
||||||
Creates and returns a TCP master object. A master object can
|
|
||||||
be transformed into a server object with the method
|
|
||||||
<a href=#listen><tt>listen</tt></a> (after a call to <a
|
|
||||||
href=#bind><tt>bind</tt></a>) or into a client object with
|
|
||||||
the method <a href=#connect><tt>connect</tt></a>. The only other
|
|
||||||
method supported by a master object is the
|
|
||||||
<a href=#close><tt>close</tt></a> method.</p>
|
|
||||||
|
|
||||||
<p class=return>
|
|
||||||
In case of success, a new master object is returned. In case of error,
|
|
||||||
<b><tt>nil</tt></b> is returned, followed by an error message.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=accept>
|
<p class=name id="accept">
|
||||||
server:<b>accept()</b>
|
server:<b>accept()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -70,9 +50,9 @@ object and returns a client object representing that connection.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
If a connection is successfully initiated, a client object is returned.
|
If a connection is successfully initiated, a client object is returned.
|
||||||
If a timeout condition is met, the method returns <b><tt>nil</tt></b>
|
If a timeout condition is met, the method returns <b><tt>nil</tt></b>
|
||||||
followed by the error string '<tt>timeout</tt>'. Other errors are
|
followed by the error string '<tt>timeout</tt>'. Other errors are
|
||||||
reported by <b><tt>nil</tt></b> followed by a message describing the error.
|
reported by <b><tt>nil</tt></b> followed by a message describing the error.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -82,26 +62,28 @@ with a server object in
|
|||||||
the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
|
the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
|
||||||
<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
|
<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
|
||||||
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
|
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
|
||||||
might block until <em>another</em> client shows up.
|
might block until <em>another</em> client shows up.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=bind>
|
<p class=name id="bind">
|
||||||
master:<b>bind(</b>address, port<b>)</b>
|
master:<b>bind(</b>address, port<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
|
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
|
||||||
local host.
|
local host.
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Address</tt> can be an IP address or a host name.
|
<tt>Address</tt> can be an IP address or a host name.
|
||||||
<tt>Port</tt> must be an integer number in the range [0..64K).
|
<tt>Port</tt> must be an integer number in the range [0..64K).
|
||||||
If <tt>address</tt>
|
If <tt>address</tt>
|
||||||
is '<tt>*</tt>', the system binds to all local interfaces
|
is '<tt>*</tt>', the system binds to all local interfaces
|
||||||
using the <tt>INADDR_ANY</tt> constant. If <tt>port</tt> is 0, the system automatically
|
using the <tt>INADDR_ANY</tt> constant or
|
||||||
chooses an ephemeral port.
|
<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
|
||||||
|
If <tt>port</tt> is 0, the system automatically
|
||||||
|
chooses an ephemeral port.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
@@ -110,13 +92,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
|
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
|
||||||
is available and is a shortcut for the creation of server sockets.
|
is available and is a shortcut for the creation of server sockets.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=close>
|
<p class=name id="close">
|
||||||
master:<b>close()</b><br>
|
master:<b>close()</b><br>
|
||||||
client:<b>close()</b><br>
|
client:<b>close()</b><br>
|
||||||
server:<b>close()</b>
|
server:<b>close()</b>
|
||||||
@@ -127,37 +109,37 @@ Closes a TCP object. The internal socket used by the object is closed
|
|||||||
and the local address to which the object was
|
and the local address to which the object was
|
||||||
bound is made available to other applications. No further operations
|
bound is made available to other applications. No further operations
|
||||||
(except for further calls to the <tt>close</tt> method) are allowed on
|
(except for further calls to the <tt>close</tt> method) are allowed on
|
||||||
a closed socket.
|
a closed socket.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
Note: It is important to close all used sockets once they are not
|
Note: It is important to close all used sockets once they are not
|
||||||
needed, since, in many systems, each socket uses a file descriptor,
|
needed, since, in many systems, each socket uses a file descriptor,
|
||||||
which are limited system resources. Garbage-collected objects are
|
which are limited system resources. Garbage-collected objects are
|
||||||
automatically closed before destruction, though.
|
automatically closed before destruction, though.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=connect>
|
<p class=name id="connect">
|
||||||
master:<b>connect(</b>address, port<b>)</b>
|
master:<b>connect(</b>address, port<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Attempts to connect a master object to a remote host, transforming it into a
|
Attempts to connect a master object to a remote host, transforming it into a
|
||||||
client object.
|
client object.
|
||||||
Client objects support methods
|
Client objects support methods
|
||||||
<a href=#send><tt>send</tt></a>,
|
<a href=#send><tt>send</tt></a>,
|
||||||
<a href=#receive><tt>receive</tt></a>,
|
<a href=#receive><tt>receive</tt></a>,
|
||||||
<a href=#getsockname><tt>getsockname</tt></a>,
|
<a href=#getsockname><tt>getsockname</tt></a>,
|
||||||
<a href=#getpeername><tt>getpeername</tt></a>,
|
<a href=#getpeername><tt>getpeername</tt></a>,
|
||||||
<a href=#settimeout><tt>settimeout</tt></a>,
|
<a href=#settimeout><tt>settimeout</tt></a>,
|
||||||
and <a href=#close><tt>close</tt></a>.
|
and <a href=#close><tt>close</tt></a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Address</tt> can be an IP address or a host name.
|
<tt>Address</tt> can be an IP address or a host name.
|
||||||
<tt>Port</tt> must be an integer number in the range [1..64K).
|
<tt>Port</tt> must be an integer number in the range [1..64K).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
@@ -166,23 +148,107 @@ describing the error. In case of success, the method returns 1.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
|
Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
|
||||||
is available and is a shortcut for the creation of client sockets.
|
is available and is a shortcut for the creation of client sockets.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
Note: Starting with LuaSocket 2.0,
|
Note: Starting with LuaSocket 2.0,
|
||||||
the <a href=#settimeout><tt>settimeout</tt></a>
|
the <a href=#settimeout><tt>settimeout</tt></a>
|
||||||
method affects the behavior of <tt>connect</tt>, causing it to return
|
method affects the behavior of <tt>connect</tt>, causing it to return
|
||||||
with an error in case of a timeout. If that happens, you can still call <a
|
with an error in case of a timeout. If that happens, you can still call <a
|
||||||
href=socket.html#select><tt>socket.select</tt></a> with the socket in the
|
href=socket.html#select><tt>socket.select</tt></a> with the socket in the
|
||||||
<tt>sendt</tt> table. The socket will be writable when the connection is
|
<tt>sendt</tt> table. The socket will be writable when the connection is
|
||||||
established.
|
established.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: Starting with LuaSocket 3.0, the host name resolution
|
||||||
|
depends on whether the socket was created by
|
||||||
|
<a href=#socket.tcp><tt>socket.tcp</tt></a>,
|
||||||
|
<a href=#socket.tcp4><tt>socket.tcp4</tt></a> or
|
||||||
|
<a href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
|
||||||
|
the appropriate family (or both) are tried in the order
|
||||||
|
returned by the resolver until the
|
||||||
|
first success or until the last failure. If the timeout was
|
||||||
|
set to zero, only the first address is tried.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="dirty">
|
||||||
|
master:<b>dirty()</b><br>
|
||||||
|
client:<b>dirty()</b><br>
|
||||||
|
server:<b>dirty()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Check the read buffer status.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: <b>This is an internal method, use at your own risk.</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="getfd">
|
||||||
|
master:<b>getfd()</b><br>
|
||||||
|
client:<b>getfd()</b><br>
|
||||||
|
server:<b>getfd()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Returns the underling socket descriptor or handle associated to the object.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
The descriptor or handle. In case the object has been closed, the return will be -1.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: <b>This is an internal method. Unlikely to be
|
||||||
|
portable. Use at your own risk. </b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="getoption">
|
||||||
|
client:<b>getoption(</b>option)</b><br>
|
||||||
|
server:<b>getoption(</b>option)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Gets options for the TCP object.
|
||||||
|
See <a href=#setoption><tt>setoption</tt></a> for description of the
|
||||||
|
option names and values.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=parameters>
|
||||||
|
<tt>Option</tt> is a string with the option name.
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li> '<tt>keepalive</tt>'
|
||||||
|
<li> '<tt>linger</tt>'
|
||||||
|
<li> '<tt>reuseaddr</tt>'
|
||||||
|
<li> '<tt>tcp-nodelay</tt>'
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
The method returns the option <tt>value</tt> in case of success, or
|
||||||
|
<b><tt>nil</tt></b> followed by an error message otherwise.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=getpeername>
|
<p class=name id="getpeername">
|
||||||
client:<b>getpeername()</b>
|
client:<b>getpeername()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -191,9 +257,10 @@ Returns information about the remote side of a connected client object.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
Returns a string with the IP address of the peer, followed by the
|
Returns a string with the IP address of the peer, the
|
||||||
port number that peer is using for the connection.
|
port number that peer is using for the connection,
|
||||||
In case of error, the method returns <b><tt>nil</tt></b>.
|
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
|
||||||
|
In case of error, the method returns <b><tt>nil</tt></b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
@@ -202,24 +269,26 @@ Note: It makes no sense to call this method on server objects.
|
|||||||
|
|
||||||
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=getsockname>
|
<p class=name id="getsockname">
|
||||||
master:<b>getsockname()</b><br>
|
master:<b>getsockname()</b><br>
|
||||||
client:<b>getsockname()</b><br>
|
client:<b>getsockname()</b><br>
|
||||||
server:<b>getsockname()</b>
|
server:<b>getsockname()</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Returns the local address information associated to the object.
|
Returns the local address information associated to the object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The method returns a string with local IP address and a number with
|
The method returns a string with local IP address, a number with
|
||||||
the port. In case of error, the method returns <b><tt>nil</tt></b>.
|
the local port,
|
||||||
|
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
|
||||||
|
In case of error, the method returns <b><tt>nil</tt></b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=getstats>
|
<p class=name id="getstats">
|
||||||
master:<b>getstats()</b><br>
|
master:<b>getstats()</b><br>
|
||||||
client:<b>getstats()</b><br>
|
client:<b>getstats()</b><br>
|
||||||
server:<b>getstats()</b><br>
|
server:<b>getstats()</b><br>
|
||||||
@@ -227,32 +296,46 @@ server:<b>getstats()</b><br>
|
|||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Returns accounting information on the socket, useful for throttling
|
Returns accounting information on the socket, useful for throttling
|
||||||
of bandwidth.
|
of bandwidth.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The method returns the number of bytes received, the number of bytes sent,
|
The method returns the number of bytes received, the number of bytes sent,
|
||||||
and the age of the socket object in seconds.
|
and the age of the socket object in seconds.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="gettimeout">
|
||||||
|
master:<b>gettimeout()</b><br>
|
||||||
|
client:<b>gettimeout()</b><br>
|
||||||
|
server:<b>gettimeout()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Returns the current block timeout followed by the curent
|
||||||
|
total timeout.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=listen>
|
<p class=name id="listen">
|
||||||
master:<b>listen(</b>backlog<b>)</b>
|
master:<b>listen(</b>backlog<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Specifies the socket is willing to receive connections, transforming the
|
Specifies the socket is willing to receive connections, transforming the
|
||||||
object into a server object. Server objects support the
|
object into a server object. Server objects support the
|
||||||
<a href=#accept><tt>accept</tt></a>,
|
<a href=#accept><tt>accept</tt></a>,
|
||||||
<a href=#getsockname><tt>getsockname</tt></a>,
|
<a href=#getsockname><tt>getsockname</tt></a>,
|
||||||
<a href=#setoption><tt>setoption</tt></a>,
|
<a href=#setoption><tt>setoption</tt></a>,
|
||||||
<a href=#settimeout><tt>settimeout</tt></a>,
|
<a href=#settimeout><tt>settimeout</tt></a>,
|
||||||
and <a href=#close><tt>close</tt></a> methods.
|
and <a href=#close><tt>close</tt></a> methods.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
The parameter <tt>backlog</tt> specifies the number of client
|
The parameter <tt>backlog</tt> specifies the number of client
|
||||||
connections that can
|
connections that can
|
||||||
be queued waiting for service. If the queue is full and another client
|
be queued waiting for service. If the queue is full and another client
|
||||||
attempts connection, the connection is refused.
|
attempts connection, the connection is refused.
|
||||||
@@ -265,17 +348,17 @@ method returns <b><tt>nil</tt></b> followed by an error message.
|
|||||||
|
|
||||||
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=receive>
|
<p class=name id="receive">
|
||||||
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
|
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Reads data from a client object, according to the specified <em>read
|
Reads data from a client object, according to the specified <em>read
|
||||||
pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
|
pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Pattern</tt> can be any of the following:
|
<tt>Pattern</tt> can be any of the following:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@@ -284,8 +367,9 @@ closed. No end-of-line translation is performed;
|
|||||||
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is
|
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is
|
||||||
terminated by a LF character (ASCII 10), optionally preceded by a
|
terminated by a LF character (ASCII 10), optionally preceded by a
|
||||||
CR character (ASCII 13). The CR and LF characters are not included in
|
CR character (ASCII 13). The CR and LF characters are not included in
|
||||||
the returned line. This is the default pattern;
|
the returned line. In fact, <em>all</em> CR characters are
|
||||||
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
|
ignored by the pattern. This is the default pattern;
|
||||||
|
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
|
||||||
of bytes from the socket.
|
of bytes from the socket.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -296,26 +380,26 @@ of any received data before return.
|
|||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
If successful, the method returns the received pattern. In case of error,
|
If successful, the method returns the received pattern. In case of error,
|
||||||
the method returns <tt><b>nil</b></tt> followed by an error message which
|
the method returns <tt><b>nil</b></tt> followed by an error
|
||||||
can be the string '<tt>closed</tt>' in case the connection was
|
message, followed by a (possibly empty) string containing
|
||||||
|
the partial that was received. The error message can be
|
||||||
|
the string '<tt>closed</tt>' in case the connection was
|
||||||
closed before the transmission was completed or the string
|
closed before the transmission was completed or the string
|
||||||
'<tt>timeout</tt>' in case there was a timeout during the operation.
|
'<tt>timeout</tt>' in case there was a timeout during the operation.
|
||||||
Also, after the error message, the function returns the partial result of
|
|
||||||
the transmission.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
<b>Important note</b>: This function was changed <em>severely</em>. It used
|
<b>Important note</b>: This function was changed <em>severely</em>. It used
|
||||||
to support multiple patterns (but I have never seen this feature used) and
|
to support multiple patterns (but I have never seen this feature used) and
|
||||||
now it doesn't anymore. Partial results used to be returned in the same
|
now it doesn't anymore. Partial results used to be returned in the same
|
||||||
way as successful results. This last feature violated the idea that all
|
way as successful results. This last feature violated the idea that all
|
||||||
functions should return <tt><b>nil</b></tt> on error. Thus it was changed
|
functions should return <tt><b>nil</b></tt> on error. Thus it was changed
|
||||||
too.
|
too.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=send>
|
<p class=name id="send">
|
||||||
client:<b>send(</b>data [, i [, j]]<b>)</b>
|
client:<b>send(</b>data [, i [, j]]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -326,7 +410,7 @@ Sends <tt>data</tt> through client object.
|
|||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Data</tt> is the string to be sent. The optional arguments
|
<tt>Data</tt> is the string to be sent. The optional arguments
|
||||||
<tt>i</tt> and <tt>j</tt> work exactly like the standard
|
<tt>i</tt> and <tt>j</tt> work exactly like the standard
|
||||||
<tt>string.sub</tt> Lua function to allow the selection of a
|
<tt>string.sub</tt> Lua function to allow the selection of a
|
||||||
substring to be sent.
|
substring to be sent.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -345,27 +429,27 @@ there was a timeout during the operation.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
Note: Output is <em>not</em> buffered. For small strings,
|
Note: Output is <em>not</em> buffered. For small strings,
|
||||||
it is always better to concatenate them in Lua
|
it is always better to concatenate them in Lua
|
||||||
(with the '<tt>..</tt>' operator) and send the result in one call
|
(with the '<tt>..</tt>' operator) and send the result in one call
|
||||||
instead of calling the method several times.
|
instead of calling the method several times.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=setoption>
|
<p class=name id="setoption">
|
||||||
client:<b>setoption(</b>option [, value]<b>)</b><br>
|
client:<b>setoption(</b>option [, value]<b>)</b><br>
|
||||||
server:<b>setoption(</b>option [, value]<b>)</b>
|
server:<b>setoption(</b>option [, value]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Sets options for the TCP object. Options are only needed by low-level or
|
Sets options for the TCP object. Options are only needed by low-level or
|
||||||
time-critical applications. You should only modify an option if you
|
time-critical applications. You should only modify an option if you
|
||||||
are sure you need it.
|
are sure you need it.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
<tt>Option</tt> is a string with the option name, and <tt>value</tt>
|
<tt>Option</tt> is a string with the option name, and <tt>value</tt>
|
||||||
depends on the option being set:
|
depends on the option being set:
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@@ -373,7 +457,7 @@ depends on the option being set:
|
|||||||
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
|
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
|
||||||
the periodic transmission of messages on a connected socket. Should the
|
the periodic transmission of messages on a connected socket. Should the
|
||||||
connected party fail to respond to these messages, the connection is
|
connected party fail to respond to these messages, the connection is
|
||||||
considered broken and processes using the socket are notified;
|
considered broken and processes using the socket are notified;
|
||||||
|
|
||||||
<li> '<tt>linger</tt>': Controls the action taken when unsent data are
|
<li> '<tt>linger</tt>': Controls the action taken when unsent data are
|
||||||
queued on a socket and a close is performed. The value is a table with a
|
queued on a socket and a close is performed. The value is a table with a
|
||||||
@@ -384,19 +468,29 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
|
|||||||
'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
|
'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
|
||||||
process the close in a manner that allows the process to continue as
|
process the close in a manner that allows the process to continue as
|
||||||
quickly as possible. I do not advise you to set this to anything other than
|
quickly as possible. I do not advise you to set this to anything other than
|
||||||
zero;
|
zero;
|
||||||
|
|
||||||
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
|
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
|
||||||
used in validating addresses supplied in a call to
|
used in validating addresses supplied in a call to
|
||||||
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
|
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
|
||||||
|
|
||||||
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
|
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
|
||||||
disables the Nagle's algorithm for the connection.
|
disables the Nagle's algorithm for the connection;
|
||||||
|
|
||||||
|
<li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!!
|
||||||
|
|
||||||
|
<li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!!
|
||||||
|
|
||||||
|
<li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!!
|
||||||
|
|
||||||
|
<li> '<tt>ipv6-v6only</tt>':
|
||||||
|
Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
|
||||||
|
sending and receiving only IPv6 packets.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise.
|
The method returns 1 in case of success, or <b><tt>nil</tt></b>
|
||||||
|
followed by an error message otherwise.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=note>
|
<p class=note>
|
||||||
@@ -405,7 +499,7 @@ Note: The descriptions above come from the man pages.
|
|||||||
|
|
||||||
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=setstats>
|
<p class=name id="setstats">
|
||||||
master:<b>setstats(</b>received, sent, age<b>)</b><br>
|
master:<b>setstats(</b>received, sent, age<b>)</b><br>
|
||||||
client:<b>setstats(</b>received, sent, age<b>)</b><br>
|
client:<b>setstats(</b>received, sent, age<b>)</b><br>
|
||||||
server:<b>setstats(</b>received, sent, age<b>)</b><br>
|
server:<b>setstats(</b>received, sent, age<b>)</b><br>
|
||||||
@@ -413,7 +507,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
|
|||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Resets accounting information on the socket, useful for throttling
|
Resets accounting information on the socket, useful for throttling
|
||||||
of bandwidth.
|
of bandwidth.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -423,12 +517,12 @@ of bandwidth.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=return>
|
<p class=return>
|
||||||
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
|
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=settimeout>
|
<p class=name id="settimeout">
|
||||||
master:<b>settimeout(</b>value [, mode]<b>)</b><br>
|
master:<b>settimeout(</b>value [, mode]<b>)</b><br>
|
||||||
client:<b>settimeout(</b>value [, mode]<b>)</b><br>
|
client:<b>settimeout(</b>value [, mode]<b>)</b><br>
|
||||||
server:<b>settimeout(</b>value [, mode]<b>)</b>
|
server:<b>settimeout(</b>value [, mode]<b>)</b>
|
||||||
@@ -437,8 +531,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
|
|||||||
<p class=description>
|
<p class=description>
|
||||||
Changes the timeout values for the object. By default,
|
Changes the timeout values for the object. By default,
|
||||||
all I/O operations are blocking. That is, any call to the methods
|
all I/O operations are blocking. That is, any call to the methods
|
||||||
<a href=#send><tt>send</tt></a>,
|
<a href=#send><tt>send</tt></a>,
|
||||||
<a href=#receive><tt>receive</tt></a>, and
|
<a href=#receive><tt>receive</tt></a>, and
|
||||||
<a href=#accept><tt>accept</tt></a>
|
<a href=#accept><tt>accept</tt></a>
|
||||||
will block indefinitely, until the operation completes. The
|
will block indefinitely, until the operation completes. The
|
||||||
<tt>settimeout</tt> method defines a limit on the amount of time the
|
<tt>settimeout</tt> method defines a limit on the amount of time the
|
||||||
@@ -449,7 +543,7 @@ time has elapsed, the affected methods give up and fail with an error code.
|
|||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
The amount of time to wait is specified as the
|
The amount of time to wait is specified as the
|
||||||
<tt>value</tt> parameter, in seconds. There are two timeout modes and
|
<tt>value</tt> parameter, in seconds. There are two timeout modes and
|
||||||
both can be used together for fine tuning:
|
both can be used together for fine tuning:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@@ -460,7 +554,7 @@ default mode;</li>
|
|||||||
|
|
||||||
<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on
|
<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on
|
||||||
the amount of time LuaSocket can block a Lua script before returning from
|
the amount of time LuaSocket can block a Lua script before returning from
|
||||||
a call.</li>
|
a call.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -485,12 +579,12 @@ contained verbs making their imperative nature obvious.
|
|||||||
|
|
||||||
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=shutdown>
|
<p class=name id="shutdown">
|
||||||
client:<b>shutdown(</b>mode<b>)</b><br>
|
client:<b>shutdown(</b>mode<b>)</b><br>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
Shuts down part of a full-duplex connection.
|
Shuts down part of a full-duplex connection.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=parameters>
|
<p class=parameters>
|
||||||
@@ -507,14 +601,115 @@ This is the default mode;
|
|||||||
This function returns 1.
|
This function returns 1.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="setfd">
|
||||||
|
master:<b>setfd(</b>fd<b>)</b><br>
|
||||||
|
client:<b>setfd(</b>fd<b>)</b><br>
|
||||||
|
server:<b>setfd(</b>fd<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
No return value.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: <b>This is an internal method. Unlikely to be
|
||||||
|
portable. Use at your own risk. </b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="socket.tcp">
|
||||||
|
socket.<b>tcp()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Creates and returns an TCP master object. A master object can
|
||||||
|
be transformed into a server object with the method
|
||||||
|
<a href=#listen><tt>listen</tt></a> (after a call to <a
|
||||||
|
href=#bind><tt>bind</tt></a>) or into a client object with
|
||||||
|
the method <a href=#connect><tt>connect</tt></a>. The only other
|
||||||
|
method supported by a master object is the
|
||||||
|
<a href=#close><tt>close</tt></a> method.</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
In case of success, a new master object is returned. In case of error,
|
||||||
|
<b><tt>nil</tt></b> is returned, followed by an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: The choice between IPv4 and IPv6 happens during a call to
|
||||||
|
<a href=#bind><tt>bind</tt></a> or <a
|
||||||
|
href=#bind><tt>connect</tt></a>, depending on the address
|
||||||
|
family obtained from the resolver.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: Before the choice between IPv4 and IPv6 happens,
|
||||||
|
the internal socket object is invalid and therefore <a
|
||||||
|
href=#setoption><tt>setoption</tt></a> will fail.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="socket.tcp4">
|
||||||
|
socket.<b>tcp4()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Creates and returns an IPv4 TCP master object. A master object can
|
||||||
|
be transformed into a server object with the method
|
||||||
|
<a href=#listen><tt>listen</tt></a> (after a call to <a
|
||||||
|
href=#bind><tt>bind</tt></a>) or into a client object with
|
||||||
|
the method <a href=#connect><tt>connect</tt></a>. The only other
|
||||||
|
method supported by a master object is the
|
||||||
|
<a href=#close><tt>close</tt></a> method.</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
In case of success, a new master object is returned. In case of error,
|
||||||
|
<b><tt>nil</tt></b> is returned, followed by an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="socket.tcp6">
|
||||||
|
socket.<b>tcp6()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Creates and returns an IPv6 TCP master object. A master object can
|
||||||
|
be transformed into a server object with the method
|
||||||
|
<a href=#listen><tt>listen</tt></a> (after a call to <a
|
||||||
|
href=#bind><tt>bind</tt></a>) or into a client object with
|
||||||
|
the method <a href=#connect><tt>connect</tt></a>. The only other
|
||||||
|
method supported by a master object is the
|
||||||
|
<a href=#close><tt>close</tt></a> method.</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
In case of success, a new master object is returned. In case of error,
|
||||||
|
<b><tt>nil</tt></b> is returned, followed by an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: The TCP object returned will have the option
|
||||||
|
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<div class=footer>
|
<div class=footer>
|
||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
358
doc/udp.html
358
doc/udp.html
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta name="description" content="LuaSocket: The UDP support">
|
<meta name="description" content="LuaSocket: The UDP support">
|
||||||
<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
|
<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
|
||||||
<title>LuaSocket: UDP support</title>
|
<title>LuaSocket: UDP support</title>
|
||||||
<link rel="stylesheet" href="reference.css" type="text/css">
|
<link rel="stylesheet" href="reference.css" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
@@ -24,11 +24,11 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
</p>
|
</p>
|
||||||
</center>
|
</center>
|
||||||
<hr>
|
<hr>
|
||||||
@@ -37,34 +37,7 @@
|
|||||||
|
|
||||||
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<h2 id=udp>UDP</h2>
|
<h2 id="udp">UDP</h2>
|
||||||
|
|
||||||
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
|
||||||
|
|
||||||
<p class="name" id="socket.udp">
|
|
||||||
socket.<b>udp()</b>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="description">
|
|
||||||
Creates and returns an unconnected UDP object. Unconnected objects support the
|
|
||||||
<a href="#sendto"><tt>sendto</tt></a>,
|
|
||||||
<a href="#receive"><tt>receive</tt></a>,
|
|
||||||
<a href="#receivefrom"><tt>receivefrom</tt></a>,
|
|
||||||
<a href="#getsockname"><tt>getsockname</tt></a>,
|
|
||||||
<a href="#setoption"><tt>setoption</tt></a>,
|
|
||||||
<a href="#settimeout"><tt>settimeout</tt></a>,
|
|
||||||
<a href="#setpeername"><tt>setpeername</tt></a>,
|
|
||||||
<a href="#setsockname"><tt>setsockname</tt></a>, and
|
|
||||||
<a href="#close"><tt>close</tt></a>.
|
|
||||||
The <a href="#setpeername"><tt>setpeername</tt></a>
|
|
||||||
is used to connect the object.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="return">
|
|
||||||
In case of success, a new unconnected UDP object
|
|
||||||
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
|
||||||
an error message.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
@@ -89,6 +62,40 @@ Garbage-collected objects are automatically closed before
|
|||||||
destruction, though.
|
destruction, though.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class="name" id="getoption">
|
||||||
|
connected:<b>getoption()</b><br>
|
||||||
|
unconnected:<b>getoption()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
Gets an option value from the UDP object.
|
||||||
|
See <a href=#setoption><tt>setoption</tt></a> for
|
||||||
|
description of the option names and values.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="parameters"><tt>Option</tt> is a string with the option name.
|
||||||
|
<ul>
|
||||||
|
<li> '<tt>dontroute</tt>'
|
||||||
|
<li> '<tt>broadcast</tt>'
|
||||||
|
<li> '<tt>reuseaddr</tt>'
|
||||||
|
<li> '<tt>reuseport</tt>'
|
||||||
|
<li> '<tt>ip-multicast-loop</tt>'
|
||||||
|
<li> '<tt>ipv6-v6only</tt>'
|
||||||
|
<li> '<tt>ip-multicast-if</tt>'
|
||||||
|
<li> '<tt>ip-multicast-ttl</tt>'
|
||||||
|
<li> '<tt>ip-add-membership</tt>'
|
||||||
|
<li> '<tt>ip-drop-membership</tt>'
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=return>
|
||||||
|
The method returns the option <tt>value</tt> in case of
|
||||||
|
success, or
|
||||||
|
<b><tt>nil</tt></b> followed by an error message otherwise.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="getpeername">
|
<p class="name" id="getpeername">
|
||||||
@@ -100,8 +107,12 @@ Retrieves information about the peer
|
|||||||
associated with a connected UDP object.
|
associated with a connected UDP object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="return">
|
|
||||||
Returns the IP address and port number of the peer.
|
<p class=return>
|
||||||
|
Returns a string with the IP address of the peer, the
|
||||||
|
port number that peer is using for the connection,
|
||||||
|
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
|
||||||
|
In case of error, the method returns <b><tt>nil</tt></b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="note">
|
<p class="note">
|
||||||
@@ -119,10 +130,12 @@ unconnected:<b>getsockname()</b>
|
|||||||
Returns the local address information associated to the object.
|
Returns the local address information associated to the object.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="return">
|
|
||||||
The method returns a string with local IP
|
<p class=return>
|
||||||
address and a number with the port. In case of error, the method
|
The method returns a string with local IP address, a number with
|
||||||
returns <b><tt>nil</tt></b>.
|
the local port,
|
||||||
|
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
|
||||||
|
In case of error, the method returns <b><tt>nil</tt></b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="note">
|
<p class="note">
|
||||||
@@ -133,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the
|
|||||||
wild-card address).
|
wild-card address).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class=name id="gettimeout">
|
||||||
|
connected:<b>settimeout(</b>value<b>)</b><br>
|
||||||
|
unconnected:<b>settimeout(</b>value<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=description>
|
||||||
|
Returns the current timeout value.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="receive">
|
<p class="name" id="receive">
|
||||||
@@ -153,9 +178,12 @@ specifies the maximum size of the datagram to be retrieved. If
|
|||||||
there are more than <tt>size</tt> bytes available in the datagram,
|
there are more than <tt>size</tt> bytes available in the datagram,
|
||||||
the excess bytes are discarded. If there are less then
|
the excess bytes are discarded. If there are less then
|
||||||
<tt>size</tt> bytes available in the current datagram, the
|
<tt>size</tt> bytes available in the current datagram, the
|
||||||
available bytes are returned. If <tt>size</tt> is omitted, the
|
available bytes are returned.
|
||||||
maximum datagram size is used (which is currently limited by the
|
If <tt>size</tt> is omitted, the
|
||||||
implementation to 8192 bytes).
|
compile-time constant <a
|
||||||
|
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
|
||||||
|
(it defaults to 8192 bytes). Larger sizes will cause a
|
||||||
|
temporary buffer to be allocated for the operation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="return">
|
<p class="return">
|
||||||
@@ -171,7 +199,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="description">
|
<p class="description">
|
||||||
Works exactly as the <a href="#receive"><tt>receive</tt></a>
|
Works exactly as the <a href="#receive"><tt>receive</tt></a>
|
||||||
method, except it returns the IP
|
method, except it returns the IP
|
||||||
address and port as extra return values (and is therefore slightly less
|
address and port as extra return values (and is therefore slightly less
|
||||||
efficient).
|
efficient).
|
||||||
@@ -188,7 +216,7 @@ Sends a datagram to the UDP peer of a connected object.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="parameters">
|
<p class="parameters">
|
||||||
<tt>Datagram</tt> is a string with the datagram contents.
|
<tt>Datagram</tt> is a string with the datagram contents.
|
||||||
The maximum datagram size for UDP is 64K minus IP layer overhead.
|
The maximum datagram size for UDP is 64K minus IP layer overhead.
|
||||||
However datagrams larger than the link layer packet size will be
|
However datagrams larger than the link layer packet size will be
|
||||||
fragmented, which may deteriorate performance and/or reliability.
|
fragmented, which may deteriorate performance and/or reliability.
|
||||||
@@ -218,11 +246,11 @@ Sends a datagram to the specified IP address and port number.
|
|||||||
|
|
||||||
<p class="parameters">
|
<p class="parameters">
|
||||||
<tt>Datagram</tt> is a string with the
|
<tt>Datagram</tt> is a string with the
|
||||||
datagram contents.
|
datagram contents.
|
||||||
The maximum datagram size for UDP is 64K minus IP layer overhead.
|
The maximum datagram size for UDP is 64K minus IP layer overhead.
|
||||||
However datagrams larger than the link layer packet size will be
|
However datagrams larger than the link layer packet size will be
|
||||||
fragmented, which may deteriorate performance and/or reliability.
|
fragmented, which may deteriorate performance and/or reliability.
|
||||||
<tt>Ip</tt> is the IP address of the recipient.
|
<tt>Ip</tt> is the IP address of the recipient.
|
||||||
Host names are <em>not</em> allowed for performance reasons.
|
Host names are <em>not</em> allowed for performance reasons.
|
||||||
|
|
||||||
<tt>Port</tt> is the port number at the recipient.
|
<tt>Port</tt> is the port number at the recipient.
|
||||||
@@ -240,6 +268,75 @@ refuses to send a message to the specified address (i.e. no
|
|||||||
interface accepts the address).
|
interface accepts the address).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class="name" id="setoption">
|
||||||
|
connected:<b>setoption(</b>option [, value]<b>)</b><br>
|
||||||
|
unconnected:<b>setoption(</b>option [, value]<b>)</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
Sets options for the UDP object. Options are
|
||||||
|
only needed by low-level or time-critical applications. You should
|
||||||
|
only modify an option if you are sure you need it.</p>
|
||||||
|
<p class="parameters"><tt>Option</tt> is a string with the option
|
||||||
|
name, and <tt>value</tt> depends on the option being set:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> '<tt>dontroute</tt>': Indicates that outgoing
|
||||||
|
messages should bypass the standard routing facilities.
|
||||||
|
Receives a boolean value;
|
||||||
|
<li> '<tt>broadcast</tt>': Requests permission to send
|
||||||
|
broadcast datagrams on the socket.
|
||||||
|
Receives a boolean value;
|
||||||
|
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
|
||||||
|
validating addresses supplied in a <tt>bind()</tt> call
|
||||||
|
should allow reuse of local addresses.
|
||||||
|
Receives a boolean value;
|
||||||
|
<li> '<tt>reuseport</tt>': Allows completely duplicate
|
||||||
|
bindings by multiple processes if they all set
|
||||||
|
'<tt>reuseport</tt>' before binding the port.
|
||||||
|
Receives a boolean value;
|
||||||
|
<li> '<tt>ip-multicast-loop</tt>':
|
||||||
|
Specifies whether or not a copy of an outgoing multicast
|
||||||
|
datagram is delivered to the sending host as long as it is a
|
||||||
|
member of the multicast group.
|
||||||
|
Receives a boolean value;
|
||||||
|
<li> '<tt>ipv6-v6only</tt>':
|
||||||
|
Specifies whether to restrict <tt>inet6</tt> sockets to
|
||||||
|
sending and receiving only IPv6 packets.
|
||||||
|
Receive a boolean value;
|
||||||
|
<li> '<tt>ip-multicast-if</tt>':
|
||||||
|
Sets the interface over which outgoing multicast datagrams
|
||||||
|
are sent.
|
||||||
|
Receives an IP address;
|
||||||
|
<li> '<tt>ip-multicast-ttl</tt>':
|
||||||
|
Sets the Time To Live in the IP header for outgoing
|
||||||
|
multicast datagrams.
|
||||||
|
Receives a number;
|
||||||
|
<li> '<tt>ip-add-membership</tt>':
|
||||||
|
Joins the multicast group specified.
|
||||||
|
Receives a table with fields
|
||||||
|
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
|
||||||
|
IP address;
|
||||||
|
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
|
||||||
|
group specified.
|
||||||
|
Receives a table with fields
|
||||||
|
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
|
||||||
|
IP address.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="return">
|
||||||
|
The method returns 1 in case of success, or
|
||||||
|
<b><tt>nil</tt></b> followed by an error message otherwise.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: The descriptions above come from the man pages.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="setpeername">
|
<p class="name" id="setpeername">
|
||||||
@@ -257,9 +354,9 @@ object or vice versa.
|
|||||||
For connected objects, outgoing datagrams
|
For connected objects, outgoing datagrams
|
||||||
will be sent to the specified peer, and datagrams received from
|
will be sent to the specified peer, and datagrams received from
|
||||||
other peers will be discarded by the OS. Connected UDP objects must
|
other peers will be discarded by the OS. Connected UDP objects must
|
||||||
use the <a href="#send"><tt>send</tt></a> and
|
use the <a href="#send"><tt>send</tt></a> and
|
||||||
<a href="#receive"><tt>receive</tt></a> methods instead of
|
<a href="#receive"><tt>receive</tt></a> methods instead of
|
||||||
<a href="#sendto"><tt>sendto</tt></a> and
|
<a href="#sendto"><tt>sendto</tt></a> and
|
||||||
<a href="#receivefrom"><tt>receivefrom</tt></a>.
|
<a href="#receivefrom"><tt>receivefrom</tt></a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -284,6 +381,15 @@ is recommended when the same peer is used for several transmissions
|
|||||||
and can result in up to 30% performance gains.
|
and can result in up to 30% performance gains.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: Starting with LuaSocket 3.0, the host name resolution
|
||||||
|
depends on whether the socket was created by <a
|
||||||
|
href=#socket.udp><tt>socket.udp</tt></a> or <a
|
||||||
|
href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from
|
||||||
|
the appropriate family are tried in succession until the
|
||||||
|
first success or until the last failure.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="setsockname">
|
<p class="name" id="setsockname">
|
||||||
@@ -317,40 +423,6 @@ system or explicitly by <tt>setsockname</tt>, it cannot be
|
|||||||
changed.
|
changed.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
|
||||||
|
|
||||||
<p class="name" id="setoption">
|
|
||||||
connected:<b>setoption(</b>option [, value]<b>)</b><br>
|
|
||||||
unconnected:<b>setoption(</b>option [, value]<b>)</b>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="description">
|
|
||||||
Sets options for the UDP object. Options are
|
|
||||||
only needed by low-level or time-critical applications. You should
|
|
||||||
only modify an option if you are sure you need it.</p>
|
|
||||||
<p class="parameters"><tt>Option</tt> is a string with the option
|
|
||||||
name, and <tt>value</tt> depends on the option being set:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>'<tt>dontroute</tt>': Setting this option to <tt>true</tt>
|
|
||||||
indicates that outgoing messages should bypass the standard routing
|
|
||||||
facilities;</li>
|
|
||||||
<li>'<tt>broadcast</tt>': Setting this option to <tt>true</tt>
|
|
||||||
requests permission to send broadcast datagrams on the
|
|
||||||
socket.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class="return">
|
|
||||||
The method returns 1 in case of success, or
|
|
||||||
<b><tt>nil</tt></b> followed by an error message otherwise.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="note">
|
|
||||||
Note: The descriptions above come from the man
|
|
||||||
pages.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class="name" id="settimeout">
|
<p class="name" id="settimeout">
|
||||||
@@ -359,14 +431,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="description">
|
<p class="description">
|
||||||
Changes the timeout values for the object. By default, the
|
Changes the timeout values for the object. By default, the
|
||||||
<a href="#receive"><tt>receive</tt></a> and
|
<a href="#receive"><tt>receive</tt></a> and
|
||||||
<a href="#receivefrom"><tt>receivefrom</tt></a>
|
<a href="#receivefrom"><tt>receivefrom</tt></a>
|
||||||
operations are blocking. That is, any call to the methods will block
|
operations are blocking. That is, any call to the methods will block
|
||||||
indefinitely, until data arrives. The <tt>settimeout</tt> function defines
|
indefinitely, until data arrives. The <tt>settimeout</tt> function defines
|
||||||
a limit on the amount of time the functions can block. When a timeout is
|
a limit on the amount of time the functions can block. When a timeout is
|
||||||
set and the specified amount of time has elapsed, the affected methods
|
set and the specified amount of time has elapsed, the affected methods
|
||||||
give up and fail with an error code.
|
give up and fail with an error code.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="parameters">
|
<p class="parameters">
|
||||||
@@ -391,17 +463,125 @@ all other method names already contained verbs making their
|
|||||||
imperative nature obvious.
|
imperative nature obvious.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class="name" id="socket.udp">
|
||||||
|
socket.<b>udp()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
Creates and returns an unconnected UDP object.
|
||||||
|
Unconnected objects support the
|
||||||
|
<a href="#sendto"><tt>sendto</tt></a>,
|
||||||
|
<a href="#receive"><tt>receive</tt></a>,
|
||||||
|
<a href="#receivefrom"><tt>receivefrom</tt></a>,
|
||||||
|
<a href="#getoption"><tt>getoption</tt></a>,
|
||||||
|
<a href="#getsockname"><tt>getsockname</tt></a>,
|
||||||
|
<a href="#setoption"><tt>setoption</tt></a>,
|
||||||
|
<a href="#settimeout"><tt>settimeout</tt></a>,
|
||||||
|
<a href="#setpeername"><tt>setpeername</tt></a>,
|
||||||
|
<a href="#setsockname"><tt>setsockname</tt></a>, and
|
||||||
|
<a href="#close"><tt>close</tt></a>.
|
||||||
|
The <a href="#setpeername"><tt>setpeername</tt></a>
|
||||||
|
is used to connect the object.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="return">
|
||||||
|
In case of success, a new unconnected UDP object
|
||||||
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
|
an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: The choice between IPv4 and IPv6 happens during a call to
|
||||||
|
<a href=#sendto><tt>sendto</tt></a>, <a
|
||||||
|
href=#setpeername><tt>setpeername</tt></a>, or <a
|
||||||
|
href=#setsockname><tt>sockname</tt></a>, depending on the address
|
||||||
|
family obtained from the resolver.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: Before the choice between IPv4 and IPv6 happens,
|
||||||
|
the internal socket object is invalid and therefore <a
|
||||||
|
href=#setoption><tt>setoption</tt></a> will fail.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class="name" id="socket.udp">
|
||||||
|
socket.<b>udp4()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
Creates and returns an unconnected IPv4 UDP object.
|
||||||
|
Unconnected objects support the
|
||||||
|
<a href="#sendto"><tt>sendto</tt></a>,
|
||||||
|
<a href="#receive"><tt>receive</tt></a>,
|
||||||
|
<a href="#receivefrom"><tt>receivefrom</tt></a>,
|
||||||
|
<a href="#getoption"><tt>getoption</tt></a>,
|
||||||
|
<a href="#getsockname"><tt>getsockname</tt></a>,
|
||||||
|
<a href="#setoption"><tt>setoption</tt></a>,
|
||||||
|
<a href="#settimeout"><tt>settimeout</tt></a>,
|
||||||
|
<a href="#setpeername"><tt>setpeername</tt></a>,
|
||||||
|
<a href="#setsockname"><tt>setsockname</tt></a>, and
|
||||||
|
<a href="#close"><tt>close</tt></a>.
|
||||||
|
The <a href="#setpeername"><tt>setpeername</tt></a>
|
||||||
|
is used to connect the object.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="return">
|
||||||
|
In case of success, a new unconnected UDP object
|
||||||
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
|
an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
|
<p class="name" id="socket.udp6">
|
||||||
|
socket.<b>udp6()</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
Creates and returns an unconnected IPv6 UDP object.
|
||||||
|
Unconnected objects support the
|
||||||
|
<a href="#sendto"><tt>sendto</tt></a>,
|
||||||
|
<a href="#receive"><tt>receive</tt></a>,
|
||||||
|
<a href="#receivefrom"><tt>receivefrom</tt></a>,
|
||||||
|
<a href="#getoption"><tt>getoption</tt></a>,
|
||||||
|
<a href="#getsockname"><tt>getsockname</tt></a>,
|
||||||
|
<a href="#setoption"><tt>setoption</tt></a>,
|
||||||
|
<a href="#settimeout"><tt>settimeout</tt></a>,
|
||||||
|
<a href="#setpeername"><tt>setpeername</tt></a>,
|
||||||
|
<a href="#setsockname"><tt>setsockname</tt></a>, and
|
||||||
|
<a href="#close"><tt>close</tt></a>.
|
||||||
|
The <a href="#setpeername"><tt>setpeername</tt></a>
|
||||||
|
is used to connect the object.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="return">
|
||||||
|
In case of success, a new unconnected UDP object
|
||||||
|
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
|
||||||
|
an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class=note>
|
||||||
|
Note: The TCP object returned will have the option
|
||||||
|
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<div class=footer>
|
<div class=footer>
|
||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
|
|||||||
25
doc/url.html
25
doc/url.html
@@ -24,8 +24,8 @@
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#download">download</a> ·
|
<a href="index.html#download">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
@@ -36,14 +36,13 @@
|
|||||||
|
|
||||||
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<h2 id=url>URL</h2>
|
<h2 id="url">URL</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <tt>url</tt> namespace provides functions to parse, protect,
|
The <tt>url</tt> namespace provides functions to parse, protect,
|
||||||
and build URLs, as well as functions to compose absolute URLs
|
and build URLs, as well as functions to compose absolute URLs
|
||||||
from base and relative URLs, according to
|
from base and relative URLs, according to
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC
|
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
|
||||||
2396</a>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -70,7 +69,7 @@ An URL is defined by the following grammar:
|
|||||||
|
|
||||||
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=absolute>
|
<p class=name id="absolute">
|
||||||
url.<b>absolute(</b>base, relative<b>)</b>
|
url.<b>absolute(</b>base, relative<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -91,7 +90,7 @@ The function returns a string with the absolute URL.
|
|||||||
<p class=note>
|
<p class=note>
|
||||||
Note: The rules that
|
Note: The rules that
|
||||||
govern the composition are fairly complex, and are described in detail in
|
govern the composition are fairly complex, and are described in detail in
|
||||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC 2396</a>.
|
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
|
||||||
The example bellow should give an idea of what the rules are.
|
The example bellow should give an idea of what the rules are.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -126,7 +125,7 @@ g;x?y#s = http://a/b/c/g;x?y#s
|
|||||||
|
|
||||||
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=build>
|
<p class=name id="build">
|
||||||
url.<b>build(</b>parsed_url<b>)</b>
|
url.<b>build(</b>parsed_url<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ The function returns a string with the built URL.
|
|||||||
|
|
||||||
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=build_path>
|
<p class=name id="build_path">
|
||||||
url.<b>build_path(</b>segments, unsafe<b>)</b>
|
url.<b>build_path(</b>segments, unsafe<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -201,7 +200,7 @@ code = url.escape("/#?;")
|
|||||||
|
|
||||||
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=parse>
|
<p class=name id="parse">
|
||||||
url.<b>parse(</b>url, default<b>)</b>
|
url.<b>parse(</b>url, default<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -266,7 +265,7 @@ parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
|
|||||||
|
|
||||||
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=parse_path>
|
<p class=name id="parse_path">
|
||||||
url.<b>parse_path(</b>path<b>)</b>
|
url.<b>parse_path(</b>path<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -310,8 +309,8 @@ The function returns the decoded string.
|
|||||||
<hr>
|
<hr>
|
||||||
<center>
|
<center>
|
||||||
<p class=bar>
|
<p class=bar>
|
||||||
<a href="home.html">home</a> ·
|
<a href="index.html">home</a> ·
|
||||||
<a href="home.html#down">download</a> ·
|
<a href="index.html#down">download</a> ·
|
||||||
<a href="installation.html">installation</a> ·
|
<a href="installation.html">installation</a> ·
|
||||||
<a href="introduction.html">introduction</a> ·
|
<a href="introduction.html">introduction</a> ·
|
||||||
<a href="reference.html">reference</a>
|
<a href="reference.html">reference</a>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- Little program to convert to and from Base64
|
-- Little program to convert to and from Base64
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
-- non-blocking I/O via the dispatcher module.
|
-- non-blocking I/O via the dispatcher module.
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local url = require("socket.url")
|
local url = require("socket.url")
|
||||||
local dispatch = require("dispatch")
|
local dispatch = require("dispatch")
|
||||||
@@ -12,7 +11,7 @@ dispatch.TIMEOUT = 10
|
|||||||
|
|
||||||
-- make sure the user knows how to invoke us
|
-- make sure the user knows how to invoke us
|
||||||
arg = arg or {}
|
arg = arg or {}
|
||||||
if table.getn(arg) < 1 then
|
if #arg < 1 then
|
||||||
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
|
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
|
||||||
exit()
|
exit()
|
||||||
end
|
end
|
||||||
|
|||||||
88
etc/cookie.lua
Normal file
88
etc/cookie.lua
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
local socket = require"socket"
|
||||||
|
local http = require"socket.http"
|
||||||
|
local url = require"socket.url"
|
||||||
|
local ltn12 = require"ltn12"
|
||||||
|
|
||||||
|
local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
|
||||||
|
|
||||||
|
local function unquote(t, quoted)
|
||||||
|
local n = string.match(t, "%$(%d+)$")
|
||||||
|
if n then n = tonumber(n) end
|
||||||
|
if quoted[n] then return quoted[n]
|
||||||
|
else return t end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parse_set_cookie(c, quoted, cookie_table)
|
||||||
|
c = c .. ";$last=last;"
|
||||||
|
local _, __, n, v, i = string.find(c, "(" .. token_class ..
|
||||||
|
"+)%s*=%s*(.-)%s*;%s*()")
|
||||||
|
local cookie = {
|
||||||
|
name = n,
|
||||||
|
value = unquote(v, quoted),
|
||||||
|
attributes = {}
|
||||||
|
}
|
||||||
|
while 1 do
|
||||||
|
_, __, n, v, i = string.find(c, "(" .. token_class ..
|
||||||
|
"+)%s*=?%s*(.-)%s*;%s*()", i)
|
||||||
|
if not n or n == "$last" then break end
|
||||||
|
cookie.attributes[#cookie.attributes+1] = {
|
||||||
|
name = n,
|
||||||
|
value = unquote(v, quoted)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
cookie_table[#cookie_table+1] = cookie
|
||||||
|
end
|
||||||
|
|
||||||
|
local function split_set_cookie(s, cookie_table)
|
||||||
|
cookie_table = cookie_table or {}
|
||||||
|
-- remove quoted strings from cookie list
|
||||||
|
local quoted = {}
|
||||||
|
s = string.gsub(s, '"(.-)"', function(q)
|
||||||
|
quoted[#quoted+1] = q
|
||||||
|
return "$" .. #quoted
|
||||||
|
end)
|
||||||
|
-- add sentinel
|
||||||
|
s = s .. ",$last="
|
||||||
|
-- split into individual cookies
|
||||||
|
i = 1
|
||||||
|
while 1 do
|
||||||
|
local _, __, cookie, next_token
|
||||||
|
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
|
||||||
|
token_class .. "+)%s*=", i)
|
||||||
|
if not next_token then break end
|
||||||
|
parse_set_cookie(cookie, quoted, cookie_table)
|
||||||
|
if next_token == "$last" then break end
|
||||||
|
end
|
||||||
|
return cookie_table
|
||||||
|
end
|
||||||
|
|
||||||
|
local function quote(s)
|
||||||
|
if string.find(s, "[ %,%;]") then return '"' .. s .. '"'
|
||||||
|
else return s end
|
||||||
|
end
|
||||||
|
|
||||||
|
local _empty = {}
|
||||||
|
local function build_cookies(cookies)
|
||||||
|
s = ""
|
||||||
|
for i,v in ipairs(cookies or _empty) do
|
||||||
|
if v.name then
|
||||||
|
s = s .. v.name
|
||||||
|
if v.value and v.value ~= "" then
|
||||||
|
s = s .. '=' .. quote(v.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if v.name and #(v.attributes or _empty) > 0 then s = s .. "; " end
|
||||||
|
for j,u in ipairs(v.attributes or _empty) do
|
||||||
|
if u.name then
|
||||||
|
s = s .. u.name
|
||||||
|
if u.value and u.value ~= "" then
|
||||||
|
s = s .. '=' .. quote(u.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if j < #v.attributes then s = s .. "; " end
|
||||||
|
end
|
||||||
|
if i < #cookies then s = s .. ", " end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
45
etc/dict.lua
45
etc/dict.lua
@@ -2,7 +2,6 @@
|
|||||||
-- Little program to download DICT word definitions
|
-- Little program to download DICT word definitions
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -44,48 +43,48 @@ function metat.__index:check(ok)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:getdef()
|
function metat.__index:getdef()
|
||||||
local line = socket.try(self.tp:receive())
|
local line = socket.try(self.tp:receive())
|
||||||
local def = {}
|
local def = {}
|
||||||
while line ~= "." do
|
while line ~= "." do
|
||||||
table.insert(def, line)
|
table.insert(def, line)
|
||||||
line = socket.try(self.tp:receive())
|
line = socket.try(self.tp:receive())
|
||||||
end
|
end
|
||||||
return table.concat(def, "\n")
|
return table.concat(def, "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:define(database, word)
|
function metat.__index:define(database, word)
|
||||||
database = database or "!"
|
database = database or "!"
|
||||||
socket.try(self.tp:command("DEFINE", database .. " " .. word))
|
socket.try(self.tp:command("DEFINE", database .. " " .. word))
|
||||||
local code, count = self:check(150)
|
local code, count = self:check(150)
|
||||||
local defs = {}
|
local defs = {}
|
||||||
for i = 1, count do
|
for i = 1, count do
|
||||||
self:check(151)
|
self:check(151)
|
||||||
table.insert(defs, self:getdef())
|
table.insert(defs, self:getdef())
|
||||||
end
|
end
|
||||||
self:check(250)
|
self:check(250)
|
||||||
return defs
|
return defs
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:match(database, strat, word)
|
function metat.__index:match(database, strat, word)
|
||||||
database = database or "!"
|
database = database or "!"
|
||||||
strat = strat or "."
|
strat = strat or "."
|
||||||
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
|
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
|
||||||
self:check(152)
|
self:check(152)
|
||||||
local mat = {}
|
local mat = {}
|
||||||
local line = socket.try(self.tp:receive())
|
local line = socket.try(self.tp:receive())
|
||||||
while line ~= '.' do
|
while line ~= '.' do
|
||||||
database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
|
database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
|
||||||
if not mat[database] then mat[database] = {} end
|
if not mat[database] then mat[database] = {} end
|
||||||
table.insert(mat[database], word)
|
table.insert(mat[database], word)
|
||||||
line = socket.try(self.tp:receive())
|
line = socket.try(self.tp:receive())
|
||||||
end
|
end
|
||||||
self:check(250)
|
self:check(250)
|
||||||
return mat
|
return mat
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:quit()
|
function metat.__index:quit()
|
||||||
self.tp:command("QUIT")
|
self.tp:command("QUIT")
|
||||||
return self:check(221)
|
return self:check(221)
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:close()
|
function metat.__index:close()
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
-- A hacked dispatcher module
|
-- A hacked dispatcher module
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local base = _G
|
local base = _G
|
||||||
local table = require("table")
|
local table = require("table")
|
||||||
|
local string = require("string")
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
local coroutine = require("coroutine")
|
local coroutine = require("coroutine")
|
||||||
module("dispatch")
|
module("dispatch")
|
||||||
@@ -44,26 +44,32 @@ end
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Mega hack. Don't try to do this at home.
|
-- Mega hack. Don't try to do this at home.
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- we can't yield across calls to protect, so we rewrite it with coxpcall
|
-- we can't yield across calls to protect on Lua 5.1, so we rewrite it with
|
||||||
|
-- coroutines
|
||||||
-- make sure you don't require any module that uses socket.protect before
|
-- make sure you don't require any module that uses socket.protect before
|
||||||
-- loading our hack
|
-- loading our hack
|
||||||
function socket.protect(f)
|
if string.sub(base._VERSION, -3) == "5.1" then
|
||||||
return function(...)
|
local function _protect(co, status, ...)
|
||||||
local co = coroutine.create(f)
|
if not status then
|
||||||
while true do
|
local msg = ...
|
||||||
local results = {coroutine.resume(co, base.unpack(arg))}
|
if base.type(msg) == 'table' then
|
||||||
local status = table.remove(results, 1)
|
return nil, msg[1]
|
||||||
if not status then
|
|
||||||
if type(results[1]) == 'table' then
|
|
||||||
return nil, results[1][1]
|
|
||||||
else base.error(results[1]) end
|
|
||||||
end
|
|
||||||
if coroutine.status(co) == "suspended" then
|
|
||||||
arg = {coroutine.yield(base.unpack(results))}
|
|
||||||
else
|
else
|
||||||
return base.unpack(results)
|
base.error(msg, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if coroutine.status(co) == "suspended" then
|
||||||
|
return _protect(co, coroutine.resume(co, coroutine.yield(...)))
|
||||||
|
else
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function socket.protect(f)
|
||||||
|
return function(...)
|
||||||
|
local co = coroutine.create(f)
|
||||||
|
return _protect(co, coroutine.resume(co, ...))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -77,7 +83,7 @@ local function newset()
|
|||||||
insert = function(set, value)
|
insert = function(set, value)
|
||||||
if not reverse[value] then
|
if not reverse[value] then
|
||||||
table.insert(set, value)
|
table.insert(set, value)
|
||||||
reverse[value] = table.getn(set)
|
reverse[value] = #set
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
remove = function(set, value)
|
remove = function(set, value)
|
||||||
@@ -105,8 +111,7 @@ local function cowrap(dispatcher, tcp, error)
|
|||||||
-- don't override explicitly.
|
-- don't override explicitly.
|
||||||
local metat = { __index = function(table, key)
|
local metat = { __index = function(table, key)
|
||||||
table[key] = function(...)
|
table[key] = function(...)
|
||||||
arg[1] = tcp
|
return tcp[key](tcp,select(2,...))
|
||||||
return tcp[key](base.unpack(arg))
|
|
||||||
end
|
end
|
||||||
return table[key]
|
return table[key]
|
||||||
end}
|
end}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- Little program to adjust end of line markers.
|
-- Little program to adjust end of line markers.
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ local dispatch = require("dispatch")
|
|||||||
local handler = dispatch.newhandler()
|
local handler = dispatch.newhandler()
|
||||||
|
|
||||||
-- make sure the user knows how to invoke us
|
-- make sure the user knows how to invoke us
|
||||||
if table.getn(arg) < 1 then
|
if #arg < 1 then
|
||||||
print("Usage")
|
print("Usage")
|
||||||
print(" lua forward.lua <iport:ohost:oport> ...")
|
print(" lua forward.lua <iport:ohost:oport> ...")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
|
|||||||
109
etc/get.lua
109
etc/get.lua
@@ -2,7 +2,6 @@
|
|||||||
-- Little program to download files from URLs
|
-- Little program to download files from URLs
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
local http = require("socket.http")
|
local http = require("socket.http")
|
||||||
@@ -12,53 +11,53 @@ local ltn12 = require("ltn12")
|
|||||||
|
|
||||||
-- formats a number of seconds into human readable form
|
-- formats a number of seconds into human readable form
|
||||||
function nicetime(s)
|
function nicetime(s)
|
||||||
local l = "s"
|
local l = "s"
|
||||||
if s > 60 then
|
if s > 60 then
|
||||||
s = s / 60
|
s = s / 60
|
||||||
l = "m"
|
l = "m"
|
||||||
if s > 60 then
|
if s > 60 then
|
||||||
s = s / 60
|
s = s / 60
|
||||||
l = "h"
|
l = "h"
|
||||||
if s > 24 then
|
if s > 24 then
|
||||||
s = s / 24
|
s = s / 24
|
||||||
l = "d" -- hmmm
|
l = "d" -- hmmm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if l == "s" then return string.format("%5.0f%s", s, l)
|
if l == "s" then return string.format("%5.0f%s", s, l)
|
||||||
else return string.format("%5.2f%s", s, l) end
|
else return string.format("%5.2f%s", s, l) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- formats a number of bytes into human readable form
|
-- formats a number of bytes into human readable form
|
||||||
function nicesize(b)
|
function nicesize(b)
|
||||||
local l = "B"
|
local l = "B"
|
||||||
if b > 1024 then
|
if b > 1024 then
|
||||||
b = b / 1024
|
b = b / 1024
|
||||||
l = "KB"
|
l = "KB"
|
||||||
if b > 1024 then
|
if b > 1024 then
|
||||||
b = b / 1024
|
b = b / 1024
|
||||||
l = "MB"
|
l = "MB"
|
||||||
if b > 1024 then
|
if b > 1024 then
|
||||||
b = b / 1024
|
b = b / 1024
|
||||||
l = "GB" -- hmmm
|
l = "GB" -- hmmm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return string.format("%7.2f%2s", b, l)
|
return string.format("%7.2f%2s", b, l)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- returns a string with the current state of the download
|
-- returns a string with the current state of the download
|
||||||
local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
|
local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
|
||||||
local elapsed_s = "%s received, %s/s throughput, %s elapsed "
|
local elapsed_s = "%s received, %s/s throughput, %s elapsed "
|
||||||
function gauge(got, delta, size)
|
function gauge(got, delta, size)
|
||||||
local rate = got / delta
|
local rate = got / delta
|
||||||
if size and size >= 1 then
|
if size and size >= 1 then
|
||||||
return string.format(remaining_s, nicesize(got), nicesize(rate),
|
return string.format(remaining_s, nicesize(got), nicesize(rate),
|
||||||
100*got/size, nicetime((size-got)/rate))
|
100*got/size, nicetime((size-got)/rate))
|
||||||
else
|
else
|
||||||
return string.format(elapsed_s, nicesize(got),
|
return string.format(elapsed_s, nicesize(got),
|
||||||
nicesize(rate), nicetime(delta))
|
nicesize(rate), nicetime(delta))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- creates a new instance of a receive_cb that saves to disk
|
-- creates a new instance of a receive_cb that saves to disk
|
||||||
@@ -89,10 +88,10 @@ end
|
|||||||
|
|
||||||
-- determines the size of a http file
|
-- determines the size of a http file
|
||||||
function gethttpsize(u)
|
function gethttpsize(u)
|
||||||
local r, c, h = http.request {method = "HEAD", url = u}
|
local r, c, h = http.request {method = "HEAD", url = u}
|
||||||
if c == 200 then
|
if c == 200 then
|
||||||
return tonumber(h["content-length"])
|
return tonumber(h["content-length"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- downloads a file using the http protocol
|
-- downloads a file using the http protocol
|
||||||
@@ -101,7 +100,7 @@ function getbyhttp(u, file)
|
|||||||
-- only print feedback if output is not stdout
|
-- only print feedback if output is not stdout
|
||||||
if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
|
if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
|
||||||
local r, c, h, s = http.request {url = u, sink = save }
|
local r, c, h, s = http.request {url = u, sink = save }
|
||||||
if c ~= 200 then io.stderr:write(s or c, "\n") end
|
if c ~= 200 then io.stderr:write(s or c, "\n") end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- downloads a file using the ftp protocol
|
-- downloads a file using the ftp protocol
|
||||||
@@ -114,29 +113,29 @@ function getbyftp(u, file)
|
|||||||
gett.sink = save
|
gett.sink = save
|
||||||
gett.type = "i"
|
gett.type = "i"
|
||||||
local ret, err = ftp.get(gett)
|
local ret, err = ftp.get(gett)
|
||||||
if err then print(err) end
|
if err then print(err) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- determines the scheme
|
-- determines the scheme
|
||||||
function getscheme(u)
|
function getscheme(u)
|
||||||
-- this is an heuristic to solve a common invalid url poblem
|
-- this is an heuristic to solve a common invalid url poblem
|
||||||
if not string.find(u, "//") then u = "//" .. u end
|
if not string.find(u, "//") then u = "//" .. u end
|
||||||
local parsed = url.parse(u, {scheme = "http"})
|
local parsed = url.parse(u, {scheme = "http"})
|
||||||
return parsed.scheme
|
return parsed.scheme
|
||||||
end
|
end
|
||||||
|
|
||||||
-- gets a file either by http or ftp, saving as <name>
|
-- gets a file either by http or ftp, saving as <name>
|
||||||
function get(u, name)
|
function get(u, name)
|
||||||
local fout = name and io.open(name, "wb")
|
local fout = name and io.open(name, "wb")
|
||||||
local scheme = getscheme(u)
|
local scheme = getscheme(u)
|
||||||
if scheme == "ftp" then getbyftp(u, fout)
|
if scheme == "ftp" then getbyftp(u, fout)
|
||||||
elseif scheme == "http" then getbyhttp(u, fout)
|
elseif scheme == "http" then getbyhttp(u, fout)
|
||||||
else print("unknown scheme" .. scheme) end
|
else print("unknown scheme" .. scheme) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- main program
|
-- main program
|
||||||
arg = arg or {}
|
arg = arg or {}
|
||||||
if table.getn(arg) < 1 then
|
if #arg < 1 then
|
||||||
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
|
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
else get(arg[1], arg[2]) end
|
else get(arg[1], arg[2]) end
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: David Burgess
|
-- Author: David Burgess
|
||||||
-- Modified by Diego Nehab, but David is in charge
|
-- Modified by Diego Nehab, but David is in charge
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
--[[
|
--[[
|
||||||
if you have any questions: RFC 1179
|
if you have any questions: RFC 1179
|
||||||
@@ -268,11 +267,11 @@ send = socket.protect(function(option)
|
|||||||
local class = string.sub(option.class or localip or localhost,1,31)
|
local class = string.sub(option.class or localip or localhost,1,31)
|
||||||
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
|
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
|
||||||
ctlfn = string.sub(ctlfn or file,1,131)
|
ctlfn = string.sub(ctlfn or file,1,131)
|
||||||
local cfile =
|
local cfile =
|
||||||
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
|
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
|
||||||
localhost,
|
localhost,
|
||||||
class,
|
class,
|
||||||
option.job or "LuaSocket",
|
option.job or "LuaSocket",
|
||||||
user,
|
user,
|
||||||
fmt, lpfile,
|
fmt, lpfile,
|
||||||
lpfile,
|
lpfile,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- Little program to convert to and from Quoted-Printable
|
-- Little program to convert to and from Quoted-Printable
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
|
|||||||
69
etc/tftp.lua
69
etc/tftp.lua
@@ -2,7 +2,6 @@
|
|||||||
-- TFTP support for the Lua language
|
-- TFTP support for the Lua language
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -35,18 +34,18 @@ local OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
|
|||||||
-- Packet creation functions
|
-- Packet creation functions
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local function RRQ(source, mode)
|
local function RRQ(source, mode)
|
||||||
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
|
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function WRQ(source, mode)
|
local function WRQ(source, mode)
|
||||||
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
|
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ACK(block)
|
local function ACK(block)
|
||||||
local low, high
|
local low, high
|
||||||
low = math.mod(block, 256)
|
low = math.mod(block, 256)
|
||||||
high = (block - low)/256
|
high = (block - low)/256
|
||||||
return char(0, OP_ACK, high, low)
|
return char(0, OP_ACK, high, low)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_OP(dgram)
|
local function get_OP(dgram)
|
||||||
@@ -58,16 +57,16 @@ end
|
|||||||
-- Packet analysis functions
|
-- Packet analysis functions
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local function split_DATA(dgram)
|
local function split_DATA(dgram)
|
||||||
local block = byte(dgram, 3)*256 + byte(dgram, 4)
|
local block = byte(dgram, 3)*256 + byte(dgram, 4)
|
||||||
local data = string.sub(dgram, 5)
|
local data = string.sub(dgram, 5)
|
||||||
return block, data
|
return block, data
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_ERROR(dgram)
|
local function get_ERROR(dgram)
|
||||||
local code = byte(dgram, 3)*256 + byte(dgram, 4)
|
local code = byte(dgram, 3)*256 + byte(dgram, 4)
|
||||||
local msg
|
local msg
|
||||||
_,_, msg = string.find(dgram, "(.*)\000", 5)
|
_,_, msg = string.find(dgram, "(.*)\000", 5)
|
||||||
return string.format("error code %d: %s", code, msg)
|
return string.format("error code %d: %s", code, msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -77,40 +76,40 @@ local function tget(gett)
|
|||||||
local retries, dgram, sent, datahost, dataport, code
|
local retries, dgram, sent, datahost, dataport, code
|
||||||
local last = 0
|
local last = 0
|
||||||
socket.try(gett.host, "missing host")
|
socket.try(gett.host, "missing host")
|
||||||
local con = socket.try(socket.udp())
|
local con = socket.try(socket.udp())
|
||||||
local try = socket.newtry(function() con:close() end)
|
local try = socket.newtry(function() con:close() end)
|
||||||
-- convert from name to ip if needed
|
-- convert from name to ip if needed
|
||||||
gett.host = try(socket.dns.toip(gett.host))
|
gett.host = try(socket.dns.toip(gett.host))
|
||||||
con:settimeout(1)
|
con:settimeout(1)
|
||||||
-- first packet gives data host/port to be used for data transfers
|
-- first packet gives data host/port to be used for data transfers
|
||||||
local path = string.gsub(gett.path or "", "^/", "")
|
local path = string.gsub(gett.path or "", "^/", "")
|
||||||
path = url.unescape(path)
|
path = url.unescape(path)
|
||||||
retries = 0
|
retries = 0
|
||||||
repeat
|
repeat
|
||||||
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
|
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
|
||||||
dgram, datahost, dataport = con:receivefrom()
|
dgram, datahost, dataport = con:receivefrom()
|
||||||
retries = retries + 1
|
retries = retries + 1
|
||||||
until dgram or datahost ~= "timeout" or retries > 5
|
until dgram or datahost ~= "timeout" or retries > 5
|
||||||
try(dgram, datahost)
|
try(dgram, datahost)
|
||||||
-- associate socket with data host/port
|
-- associate socket with data host/port
|
||||||
try(con:setpeername(datahost, dataport))
|
try(con:setpeername(datahost, dataport))
|
||||||
-- default sink
|
-- default sink
|
||||||
local sink = gett.sink or ltn12.sink.null()
|
local sink = gett.sink or ltn12.sink.null()
|
||||||
-- process all data packets
|
-- process all data packets
|
||||||
while 1 do
|
while 1 do
|
||||||
-- decode packet
|
-- decode packet
|
||||||
code = get_OP(dgram)
|
code = get_OP(dgram)
|
||||||
try(code ~= OP_ERROR, get_ERROR(dgram))
|
try(code ~= OP_ERROR, get_ERROR(dgram))
|
||||||
try(code == OP_DATA, "unhandled opcode " .. code)
|
try(code == OP_DATA, "unhandled opcode " .. code)
|
||||||
-- get data packet parts
|
-- get data packet parts
|
||||||
local block, data = split_DATA(dgram)
|
local block, data = split_DATA(dgram)
|
||||||
-- if not repeated, write
|
-- if not repeated, write
|
||||||
if block == last+1 then
|
if block == last+1 then
|
||||||
try(sink(data))
|
try(sink(data))
|
||||||
last = block
|
last = block
|
||||||
end
|
end
|
||||||
-- last packet brings less than 512 bytes of data
|
-- last packet brings less than 512 bytes of data
|
||||||
if string.len(data) < 512 then
|
if string.len(data) < 512 then
|
||||||
try(con:send(ACK(block)))
|
try(con:send(ACK(block)))
|
||||||
try(con:close())
|
try(con:close())
|
||||||
try(sink(nil))
|
try(sink(nil))
|
||||||
@@ -118,13 +117,13 @@ local function tget(gett)
|
|||||||
end
|
end
|
||||||
-- get the next packet
|
-- get the next packet
|
||||||
retries = 0
|
retries = 0
|
||||||
repeat
|
repeat
|
||||||
sent = try(con:send(ACK(last)))
|
sent = try(con:send(ACK(last)))
|
||||||
dgram, err = con:receive()
|
dgram, err = con:receive()
|
||||||
retries = retries + 1
|
retries = retries + 1
|
||||||
until dgram or err ~= "timeout" or retries > 5
|
until dgram or err ~= "timeout" or retries > 5
|
||||||
try(dgram, err)
|
try(dgram, err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local default = {
|
local default = {
|
||||||
|
|||||||
371
gem/ltn012.tex
371
gem/ltn012.tex
@@ -6,7 +6,10 @@
|
|||||||
\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
|
\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
|
||||||
\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
|
\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
|
||||||
\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
|
\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
|
||||||
|
\newcommand{\CR}{\texttt{CR}}
|
||||||
|
\newcommand{\LF}{\texttt{LF}}
|
||||||
|
\newcommand{\CRLF}{\texttt{CR~LF}}
|
||||||
|
\newcommand{\nil}{\texttt{nil}}
|
||||||
|
|
||||||
\title{Filters, sources, sinks, and pumps\\
|
\title{Filters, sources, sinks, and pumps\\
|
||||||
{\large or Functional programming for the rest of us}}
|
{\large or Functional programming for the rest of us}}
|
||||||
@@ -17,30 +20,31 @@
|
|||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
\begin{abstract}
|
\begin{abstract}
|
||||||
Certain data processing operations can be implemented in the
|
Certain data processing operations can be implemented in the
|
||||||
form of filters. A filter is a function that can process data
|
form of filters. A filter is a function that can process
|
||||||
received in consecutive function calls, returning partial
|
data received in consecutive invocations, returning partial
|
||||||
results after each invocation. Examples of operations that can be
|
results each time it is called. Examples of operations that
|
||||||
implemented as filters include the end-of-line normalization
|
can be implemented as filters include the end-of-line
|
||||||
for text, Base64 and Quoted-Printable transfer content
|
normalization for text, Base64 and Quoted-Printable transfer
|
||||||
encodings, the breaking of text into lines, SMTP dot-stuffing,
|
content encodings, the breaking of text into lines, SMTP
|
||||||
and there are many others. Filters become even
|
dot-stuffing, and there are many others. Filters become
|
||||||
more powerful when we allow them to be chained together to
|
even more powerful when we allow them to be chained together
|
||||||
create composite filters. In this context, filters can be seen
|
to create composite filters. In this context, filters can be
|
||||||
as the middle links in a chain of data transformations. Sources an sinks
|
seen as the internal links in a chain of data transformations.
|
||||||
are the corresponding end points of these chains. A source
|
Sources and sinks are the corresponding end points in these
|
||||||
is a function that produces data, chunk by chunk, and a sink
|
chains. A source is a function that produces data, chunk by
|
||||||
is a function that takes data, chunk by chunk. In this
|
chunk, and a sink is a function that takes data, chunk by
|
||||||
article, we describe the design of an elegant interface for filters,
|
chunk. Finally, pumps are procedures that actively drive
|
||||||
sources, sinks, and chaining, and illustrate each step
|
data from a source to a sink, and indirectly through all
|
||||||
with concrete examples.
|
intervening filters. In this article, we describe the design of an
|
||||||
|
elegant interface for filters, sources, sinks, chains, and
|
||||||
|
pumps, and we illustrate each step with concrete examples.
|
||||||
\end{abstract}
|
\end{abstract}
|
||||||
|
|
||||||
|
|
||||||
\section{Introduction}
|
\section{Introduction}
|
||||||
|
|
||||||
Within the realm of networking applications, we are often
|
Within the realm of networking applications, we are often
|
||||||
required apply transformations to streams of data. Examples
|
required to apply transformations to streams of data. Examples
|
||||||
include the end-of-line normalization for text, Base64 and
|
include the end-of-line normalization for text, Base64 and
|
||||||
Quoted-Printable transfer content encodings, breaking text
|
Quoted-Printable transfer content encodings, breaking text
|
||||||
into lines with a maximum number of columns, SMTP
|
into lines with a maximum number of columns, SMTP
|
||||||
@@ -50,38 +54,37 @@ transfer coding, and the list goes on.
|
|||||||
Many complex tasks require a combination of two or more such
|
Many complex tasks require a combination of two or more such
|
||||||
transformations, and therefore a general mechanism for
|
transformations, and therefore a general mechanism for
|
||||||
promoting reuse is desirable. In the process of designing
|
promoting reuse is desirable. In the process of designing
|
||||||
\texttt{LuaSocket~2.0}, David Burgess and I were forced to deal with
|
\texttt{LuaSocket~2.0}, we repeatedly faced this problem.
|
||||||
this problem. The solution we reached proved to be very
|
The solution we reached proved to be very general and
|
||||||
general and convenient. It is based on the concepts of
|
convenient. It is based on the concepts of filters, sources,
|
||||||
filters, sources, sinks, and pumps, which we introduce
|
sinks, and pumps, which we introduce below.
|
||||||
below.
|
|
||||||
|
|
||||||
\emph{Filters} are functions that can be repeatedly invoked
|
\emph{Filters} are functions that can be repeatedly invoked
|
||||||
with chunks of input, successively returning processed
|
with chunks of input, successively returning processed
|
||||||
chunks of output. More importantly, the result of
|
chunks of output. Naturally, the result of
|
||||||
concatenating all the output chunks must be the same as the
|
concatenating all the output chunks must be the same as the
|
||||||
result of applying the filter to the concatenation of all
|
result of applying the filter to the concatenation of all
|
||||||
input chunks. In fancier language, filters \emph{commute}
|
input chunks. In fancier language, filters \emph{commute}
|
||||||
with the concatenation operator. As a result, chunk
|
with the concatenation operator. More importantly, filters
|
||||||
boundaries are irrelevant: filters correctly handle input
|
must handle input data correctly no matter how the stream
|
||||||
data no matter how it is split.
|
has been split into chunks.
|
||||||
|
|
||||||
A \emph{chain} transparently combines the effect of one or
|
A \emph{chain} is a function that transparently combines the
|
||||||
more filters. The interface of a chain is
|
effect of one or more filters. The interface of a chain is
|
||||||
indistinguishable from the interface of its components.
|
indistinguishable from the interface of its component
|
||||||
This allows a chained filter to be used wherever an atomic
|
filters. This allows a chained filter to be used wherever
|
||||||
filter is expected. In particular, chains can be
|
an atomic filter is accepted. In particular, chains can be
|
||||||
themselves chained to create arbitrarily complex operations.
|
themselves chained to create arbitrarily complex operations.
|
||||||
|
|
||||||
Filters can be seen as internal nodes in a network through
|
Filters can be seen as internal nodes in a network through
|
||||||
which data will flow, potentially being transformed many
|
which data will flow, potentially being transformed many
|
||||||
times along its way. Chains connect these nodes together.
|
times along the way. Chains connect these nodes together.
|
||||||
To complete the picture, we need \emph{sources} and
|
The initial and final nodes of the network are
|
||||||
\emph{sinks}. These are the initial and final nodes of the
|
\emph{sources} and \emph{sinks}, respectively. Less
|
||||||
network, respectively. Less abstractly, a source is a
|
abstractly, a source is a function that produces new chunks
|
||||||
function that produces new data every time it is called.
|
of data every time it is invoked. Conversely, sinks are
|
||||||
Conversely, sinks are functions that give a final
|
functions that give a final destination to the chunks of
|
||||||
destination to the data they receive. Naturally, sources
|
data they receive in sucessive calls. Naturally, sources
|
||||||
and sinks can also be chained with filters to produce
|
and sinks can also be chained with filters to produce
|
||||||
filtered sources and sinks.
|
filtered sources and sinks.
|
||||||
|
|
||||||
@@ -89,37 +92,38 @@ Finally, filters, chains, sources, and sinks are all passive
|
|||||||
entities: they must be repeatedly invoked in order for
|
entities: they must be repeatedly invoked in order for
|
||||||
anything to happen. \emph{Pumps} provide the driving force
|
anything to happen. \emph{Pumps} provide the driving force
|
||||||
that pushes data through the network, from a source to a
|
that pushes data through the network, from a source to a
|
||||||
sink.
|
sink, and indirectly through all intervening filters.
|
||||||
|
|
||||||
In the following sections, we start with a simplified
|
In the following sections, we start with a simplified
|
||||||
interface, which we later refine. The evolution we present
|
interface, which we later refine. The evolution we present
|
||||||
is not contrived: it recreates the steps we followed
|
is not contrived: it recreates the steps we ourselves
|
||||||
ourselves as we consolidated our understanding of these
|
followed as we consolidated our understanding of these
|
||||||
concepts within our application domain.
|
concepts within our application domain.
|
||||||
|
|
||||||
\subsection{A simple example}
|
\subsection{A simple example}
|
||||||
|
|
||||||
Let us use the end-of-line normalization of text as an
|
The end-of-line normalization of text is a good
|
||||||
example to motivate our initial filter interface.
|
example to motivate our initial filter interface.
|
||||||
Assume we are given text in an unknown end-of-line
|
Assume we are given text in an unknown end-of-line
|
||||||
convention (including possibly mixed conventions) out of the
|
convention (including possibly mixed conventions) out of the
|
||||||
commonly found Unix (LF), Mac OS (CR), and DOS (CRLF)
|
commonly found Unix (\LF), Mac OS (\CR), and
|
||||||
conventions. We would like to be able to write code like the
|
DOS (\CRLF) conventions. We would like to be able to
|
||||||
following:
|
use the folowing code to normalize the end-of-line markers:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
local in = source.chain(source.file(io.stdin), normalize("\r\n"))
|
local CRLF = "\013\010"
|
||||||
local out = sink.file(io.stdout)
|
local input = source.chain(source.file(io.stdin), normalize(CRLF))
|
||||||
pump.all(in, out)
|
local output = sink.file(io.stdout)
|
||||||
|
pump.all(input, output)
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
|
|
||||||
This program should read data from the standard input stream
|
This program should read data from the standard input stream
|
||||||
and normalize the end-of-line markers to the canonic CRLF
|
and normalize the end-of-line markers to the canonic
|
||||||
marker, as defined by the MIME standard. Finally, the
|
\CRLF\ marker, as defined by the MIME standard.
|
||||||
normalized text should be sent to the standard output
|
Finally, the normalized text should be sent to the standard output
|
||||||
stream. We use a \emph{file source} that produces data from
|
stream. We use a \emph{file source} that produces data from
|
||||||
standard input, and chain it with a filter that normalizes
|
standard input, and chain it with a filter that normalizes
|
||||||
the data. The pump then repeatedly obtains data from the
|
the data. The pump then repeatedly obtains data from the
|
||||||
@@ -127,27 +131,28 @@ source, and passes it to the \emph{file sink}, which sends
|
|||||||
it to the standard output.
|
it to the standard output.
|
||||||
|
|
||||||
In the code above, the \texttt{normalize} \emph{factory} is a
|
In the code above, the \texttt{normalize} \emph{factory} is a
|
||||||
function that creates our normalization filter. This filter
|
function that creates our normalization filter, which
|
||||||
will replace any end-of-line marker with the canonic
|
replaces any end-of-line marker with the canonic marker.
|
||||||
`\verb|\r\n|' marker. The initial filter interface is
|
The initial filter interface is
|
||||||
trivial: a filter function receives a chunk of input data,
|
trivial: a filter function receives a chunk of input data,
|
||||||
and returns a chunk of processed data. When there are no
|
and returns a chunk of processed data. When there are no
|
||||||
more input data left, the caller notifies the filter by invoking
|
more input data left, the caller notifies the filter by invoking
|
||||||
it with a \texttt{nil} chunk. The filter responds by returning
|
it with a \nil\ chunk. The filter responds by returning
|
||||||
the final chunk of processed data.
|
the final chunk of processed data (which could of course be
|
||||||
|
the empty string).
|
||||||
|
|
||||||
Although the interface is extremely simple, the
|
Although the interface is extremely simple, the
|
||||||
implementation is not so obvious. A normalization filter
|
implementation is not so obvious. A normalization filter
|
||||||
respecting this interface needs to keep some kind of context
|
respecting this interface needs to keep some kind of context
|
||||||
between calls. This is because a chunk boundary may lie between
|
between calls. This is because a chunk boundary may lie between
|
||||||
the CR and LF characters marking the end of a line. This
|
the \CR\ and \LF\ characters marking the end of a single line. This
|
||||||
need for contextual storage motivates the use of
|
need for contextual storage motivates the use of
|
||||||
factories: each time the factory is invoked, it returns a
|
factories: each time the factory is invoked, it returns a
|
||||||
filter with its own context so that we can have several
|
filter with its own context so that we can have several
|
||||||
independent filters being used at the same time. For
|
independent filters being used at the same time. For
|
||||||
efficiency reasons, we must avoid the obvious solution of
|
efficiency reasons, we must avoid the obvious solution of
|
||||||
concatenating all the input into the context before
|
concatenating all the input into the context before
|
||||||
producing any output.
|
producing any output chunks.
|
||||||
|
|
||||||
To that end, we break the implementation into two parts:
|
To that end, we break the implementation into two parts:
|
||||||
a low-level filter, and a factory of high-level filters. The
|
a low-level filter, and a factory of high-level filters. The
|
||||||
@@ -167,10 +172,10 @@ end-of-line normalization filters:
|
|||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
function filter.cycle(low, ctx, extra)
|
function filter.cycle(lowlevel, context, extra)
|
||||||
return function(chunk)
|
return function(chunk)
|
||||||
local ret
|
local ret
|
||||||
ret, ctx = low(ctx, chunk, extra)
|
ret, context = lowlevel(context, chunk, extra)
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -178,27 +183,30 @@ end
|
|||||||
|
|
||||||
@stick#
|
@stick#
|
||||||
function normalize(marker)
|
function normalize(marker)
|
||||||
return cycle(eol, 0, marker)
|
return filter.cycle(eol, 0, marker)
|
||||||
end
|
end
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
|
|
||||||
The \texttt{normalize} factory simply calls a more generic
|
The \texttt{normalize} factory simply calls a more generic
|
||||||
factory, the \texttt{cycle} factory. This factory receives a
|
factory, the \texttt{cycle}~factory, passing the low-level
|
||||||
|
filter~\texttt{eol}. The \texttt{cycle}~factory receives a
|
||||||
low-level filter, an initial context, and an extra
|
low-level filter, an initial context, and an extra
|
||||||
parameter, and returns a new high-level filter. Each time
|
parameter, and returns a new high-level filter. Each time
|
||||||
the high-level filer is passed a new chunk, it invokes the
|
the high-level filer is passed a new chunk, it invokes the
|
||||||
low-level filter with the previous context, the new chunk,
|
low-level filter with the previous context, the new chunk,
|
||||||
and the extra argument. It is the low-level filter that
|
and the extra argument. It is the low-level filter that
|
||||||
does all the work, producing the chunk of processed data and
|
does all the work, producing the chunk of processed data and
|
||||||
a new context. The high-level filter then updates its
|
a new context. The high-level filter then replaces its
|
||||||
internal context, and returns the processed chunk of data to
|
internal context, and returns the processed chunk of data to
|
||||||
the user. Notice that we take advantage of Lua's lexical
|
the user. Notice that we take advantage of Lua's lexical
|
||||||
scoping to store the context in a closure between function
|
scoping to store the context in a closure between function
|
||||||
calls.
|
calls.
|
||||||
|
|
||||||
Concerning the low-level filter code, we must first accept
|
\subsection{The C part of the filter}
|
||||||
|
|
||||||
|
As for the low-level filter, we must first accept
|
||||||
that there is no perfect solution to the end-of-line marker
|
that there is no perfect solution to the end-of-line marker
|
||||||
normalization problem. The difficulty comes from an
|
normalization problem. The difficulty comes from an
|
||||||
inherent ambiguity in the definition of empty lines within
|
inherent ambiguity in the definition of empty lines within
|
||||||
@@ -208,39 +216,39 @@ mixed input. It also does a reasonable job with empty lines
|
|||||||
and serves as a good example of how to implement a low-level
|
and serves as a good example of how to implement a low-level
|
||||||
filter.
|
filter.
|
||||||
|
|
||||||
The idea is to consider both CR and~LF as end-of-line
|
The idea is to consider both \CR\ and~\LF\ as end-of-line
|
||||||
\emph{candidates}. We issue a single break if any candidate
|
\emph{candidates}. We issue a single break if any candidate
|
||||||
is seen alone, or followed by a different candidate. In
|
is seen alone, or if it is followed by a different
|
||||||
other words, CR~CR~and LF~LF each issue two end-of-line
|
candidate. In other words, \CR~\CR~and \LF~\LF\ each issue
|
||||||
markers, whereas CR~LF~and LF~CR issue only one marker each.
|
two end-of-line markers, whereas \CR~\LF~and \LF~\CR\ issue
|
||||||
This method correctly handles the Unix, DOS/MIME, VMS, and Mac
|
only one marker each. It is easy to see that this method
|
||||||
OS conventions.
|
correctly handles the most common end-of-line conventions.
|
||||||
|
|
||||||
\subsection{The C part of the filter}
|
With this in mind, we divide the low-level filter into two
|
||||||
|
simple functions. The inner function~\texttt{pushchar} performs the
|
||||||
Our low-level filter is divided into two simple functions.
|
normalization itself. It takes each input character in turn,
|
||||||
The inner function performs the normalization itself. It takes
|
deciding what to output and how to modify the context. The
|
||||||
each input character in turn, deciding what to output and
|
context tells if the last processed character was an
|
||||||
how to modify the context. The context tells if the last
|
end-of-line candidate, and if so, which candidate it was.
|
||||||
processed character was an end-of-line candidate, and if so,
|
For efficiency, we use Lua's auxiliary library's buffer
|
||||||
which candidate it was. For efficiency, it uses
|
interface:
|
||||||
Lua's auxiliary library's buffer interface:
|
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{C}
|
\begin{C}
|
||||||
@stick#
|
@stick#
|
||||||
@#define candidate(c) (c == CR || c == LF)
|
@#define candidate(c) (c == CR || c == LF)
|
||||||
static int process(int c, int last, const char *marker,
|
static int pushchar(int c, int last, const char *marker,
|
||||||
luaL_Buffer *buffer) {
|
luaL_Buffer *buffer) {
|
||||||
if (candidate(c)) {
|
if (candidate(c)) {
|
||||||
if (candidate(last)) {
|
if (candidate(last)) {
|
||||||
if (c == last) luaL_addstring(buffer, marker);
|
if (c == last)
|
||||||
|
luaL_addstring(buffer, marker);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
luaL_addstring(buffer, marker);
|
luaL_addstring(buffer, marker);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
luaL_putchar(buffer, c);
|
luaL_pushchar(buffer, c);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,15 +256,20 @@ static int process(int c, int last, const char *marker,
|
|||||||
\end{C}
|
\end{C}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
|
|
||||||
The outer function simply interfaces with Lua. It receives the
|
The outer function~\texttt{eol} simply interfaces with Lua.
|
||||||
context and input chunk (as well as an optional
|
It receives the context and input chunk (as well as an
|
||||||
custom end-of-line marker), and returns the transformed
|
optional custom end-of-line marker), and returns the
|
||||||
output chunk and the new context:
|
transformed output chunk and the new context.
|
||||||
|
Notice that if the input chunk is \nil, the operation
|
||||||
|
is considered to be finished. In that case, the loop will
|
||||||
|
not execute a single time and the context is reset to the
|
||||||
|
initial state. This allows the filter to be reused many
|
||||||
|
times:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{C}
|
\begin{C}
|
||||||
@stick#
|
@stick#
|
||||||
static int eol(lua_State *L) {
|
static int eol(lua_State *L) {
|
||||||
int ctx = luaL_checkint(L, 1);
|
int context = luaL_checkint(L, 1);
|
||||||
size_t isize = 0;
|
size_t isize = 0;
|
||||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||||
const char *last = input + isize;
|
const char *last = input + isize;
|
||||||
@@ -269,24 +282,18 @@ static int eol(lua_State *L) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
while (input < last)
|
while (input < last)
|
||||||
ctx = process(*input++, ctx, marker, &buffer);
|
context = pushchar(*input++, context, marker, &buffer);
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
lua_pushnumber(L, ctx);
|
lua_pushnumber(L, context);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
%
|
%
|
||||||
\end{C}
|
\end{C}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
|
|
||||||
Notice that if the input chunk is \texttt{nil}, the operation
|
When designing filters, the challenging part is usually
|
||||||
is considered to be finished. In that case, the loop will
|
deciding what to store in the context. For line breaking, for
|
||||||
not execute a single time and the context is reset to the
|
instance, it could be the number of bytes that still fit in the
|
||||||
initial state. This allows the filter to be reused many
|
|
||||||
times.
|
|
||||||
|
|
||||||
When designing your own filters, the challenging part is to
|
|
||||||
decide what will be in the context. For line breaking, for
|
|
||||||
instance, it could be the number of bytes left in the
|
|
||||||
current line. For Base64 encoding, it could be a string
|
current line. For Base64 encoding, it could be a string
|
||||||
with the bytes that remain after the division of the input
|
with the bytes that remain after the division of the input
|
||||||
into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
|
into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
|
||||||
@@ -294,19 +301,22 @@ distribution has many other examples.
|
|||||||
|
|
||||||
\section{Filter chains}
|
\section{Filter chains}
|
||||||
|
|
||||||
Chains add a lot to the power of filters. For example,
|
Chains greatly increase the power of filters. For example,
|
||||||
according to the standard for Quoted-Printable encoding,
|
according to the standard for Quoted-Printable encoding,
|
||||||
text must be normalized to a canonic end-of-line marker
|
text should be normalized to a canonic end-of-line marker
|
||||||
prior to encoding. To help specifying complex
|
prior to encoding. After encoding, the resulting text must
|
||||||
transformations like this, we define a chain factory that
|
be broken into lines of no more than 76 characters, with the
|
||||||
creates a composite filter from one or more filters. A
|
use of soft line breaks (a line terminated by the \texttt{=}
|
||||||
chained filter passes data through all its components, and
|
sign). To help specifying complex transformations like
|
||||||
can be used wherever a primitive filter is accepted.
|
this, we define a chain factory that creates a composite
|
||||||
|
filter from one or more filters. A chained filter passes
|
||||||
|
data through all its components, and can be used wherever a
|
||||||
|
primitive filter is accepted.
|
||||||
|
|
||||||
The chaining factory is very simple. The auxiliary
|
The chaining factory is very simple. The auxiliary
|
||||||
function~\texttt{chainpair} chains two filters together,
|
function~\texttt{chainpair} chains two filters together,
|
||||||
taking special care if the chunk is the last. This is
|
taking special care if the chunk is the last. This is
|
||||||
because the final \texttt{nil} chunk notification has to be
|
because the final \nil\ chunk notification has to be
|
||||||
pushed through both filters in turn:
|
pushed through both filters in turn:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@@ -322,9 +332,9 @@ end
|
|||||||
|
|
||||||
@stick#
|
@stick#
|
||||||
function filter.chain(...)
|
function filter.chain(...)
|
||||||
local f = arg[1]
|
local f = select(1, ...)
|
||||||
for i = 2, @#arg do
|
for i = 2, select('@#', ...) do
|
||||||
f = chainpair(f, arg[i])
|
f = chainpair(f, select(i, ...))
|
||||||
end
|
end
|
||||||
return f
|
return f
|
||||||
end
|
end
|
||||||
@@ -337,11 +347,11 @@ define the Quoted-Printable conversion as such:
|
|||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
local qp = filter.chain(normalize("\r\n"),
|
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
|
||||||
encode("quoted-printable"))
|
wrap("quoted-printable"))
|
||||||
local in = source.chain(source.file(io.stdin), qp)
|
local input = source.chain(source.file(io.stdin), qp)
|
||||||
local out = sink.file(io.stdout)
|
local output = sink.file(io.stdout)
|
||||||
pump.all(in, out)
|
pump.all(input, output)
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
@@ -360,14 +370,14 @@ gives a final destination to the data.
|
|||||||
\subsection{Sources}
|
\subsection{Sources}
|
||||||
|
|
||||||
A source returns the next chunk of data each time it is
|
A source returns the next chunk of data each time it is
|
||||||
invoked. When there is no more data, it simply returns
|
invoked. When there is no more data, it simply returns~\nil.
|
||||||
\texttt{nil}. In the event of an error, the source can inform the
|
In the event of an error, the source can inform the
|
||||||
caller by returning \texttt{nil} followed by an error message.
|
caller by returning \nil\ followed by the error message.
|
||||||
|
|
||||||
Below are two simple source factories. The \texttt{empty} source
|
Below are two simple source factories. The \texttt{empty} source
|
||||||
returns no data, possibly returning an associated error
|
returns no data, possibly returning an associated error
|
||||||
message. The \texttt{file} source works harder, and
|
message. The \texttt{file} source yields the contents of a file
|
||||||
yields the contents of a file in a chunk by chunk fashion:
|
in a chunk by chunk fashion:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
@@ -398,22 +408,26 @@ A filtered source passes its data through the
|
|||||||
associated filter before returning it to the caller.
|
associated filter before returning it to the caller.
|
||||||
Filtered sources are useful when working with
|
Filtered sources are useful when working with
|
||||||
functions that get their input data from a source (such as
|
functions that get their input data from a source (such as
|
||||||
the pump in our first example). By chaining a source with one or
|
the pumps in our examples). By chaining a source with one or
|
||||||
more filters, the function can be transparently provided
|
more filters, such functions can be transparently provided
|
||||||
with filtered data, with no need to change its interface.
|
with filtered data, with no need to change their interfaces.
|
||||||
Here is a factory that does the job:
|
Here is a factory that does the job:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
function source.chain(src, f)
|
function source.chain(src, f)
|
||||||
return source.simplify(function()
|
return function()
|
||||||
if not src then return nil end
|
if not src then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
local chunk, err = src()
|
local chunk, err = src()
|
||||||
if not chunk then
|
if not chunk then
|
||||||
src = nil
|
src = nil
|
||||||
return f(nil)
|
return f(nil)
|
||||||
else return f(chunk) end
|
else
|
||||||
end)
|
return f(chunk)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
@@ -421,20 +435,20 @@ end
|
|||||||
|
|
||||||
\subsection{Sinks}
|
\subsection{Sinks}
|
||||||
|
|
||||||
Just as we defined an interface a data source,
|
Just as we defined an interface for a source of data, we can
|
||||||
we can also define an interface for a data destination.
|
also define an interface for a data destination. We call
|
||||||
We call any function respecting this
|
any function respecting this interface a sink. In our first
|
||||||
interface a \emph{sink}. In our first example, we used a
|
example, we used a file sink connected to the standard
|
||||||
file sink connected to the standard output.
|
output.
|
||||||
|
|
||||||
Sinks receive consecutive chunks of data, until the end of
|
Sinks receive consecutive chunks of data, until the end of
|
||||||
data is signaled by a \texttt{nil} chunk. A sink can be
|
data is signaled by a \nil\ input chunk. A sink can be
|
||||||
notified of an error with an optional extra argument that
|
notified of an error with an optional extra argument that
|
||||||
contains the error message, following a \texttt{nil} chunk.
|
contains the error message, following a \nil\ chunk.
|
||||||
If a sink detects an error itself, and
|
If a sink detects an error itself, and
|
||||||
wishes not to be called again, it can return \texttt{nil},
|
wishes not to be called again, it can return \nil,
|
||||||
followed by an error message. A return value that
|
followed by an error message. A return value that
|
||||||
is not \texttt{nil} means the source will accept more data.
|
is not \nil\ means the sink will accept more data.
|
||||||
|
|
||||||
Below are two useful sink factories.
|
Below are two useful sink factories.
|
||||||
The table factory creates a sink that stores
|
The table factory creates a sink that stores
|
||||||
@@ -469,7 +483,7 @@ end
|
|||||||
|
|
||||||
Naturally, filtered sinks are just as useful as filtered
|
Naturally, filtered sinks are just as useful as filtered
|
||||||
sources. A filtered sink passes each chunk it receives
|
sources. A filtered sink passes each chunk it receives
|
||||||
through the associated filter before handing it to the
|
through the associated filter before handing it down to the
|
||||||
original sink. In the following example, we use a source
|
original sink. In the following example, we use a source
|
||||||
that reads from the standard input. The input chunks are
|
that reads from the standard input. The input chunks are
|
||||||
sent to a table sink, which has been coupled with a
|
sent to a table sink, which has been coupled with a
|
||||||
@@ -479,10 +493,10 @@ standard out:
|
|||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
local in = source.file(io.stdin)
|
local input = source.file(io.stdin)
|
||||||
local out, t = sink.table()
|
local output, t = sink.table()
|
||||||
out = sink.chain(normalize("\r\n"), out)
|
output = sink.chain(normalize(CRLF), output)
|
||||||
pump.all(in, out)
|
pump.all(input, output)
|
||||||
io.write(table.concat(t))
|
io.write(table.concat(t))
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
@@ -490,11 +504,11 @@ io.write(table.concat(t))
|
|||||||
|
|
||||||
\subsection{Pumps}
|
\subsection{Pumps}
|
||||||
|
|
||||||
Adrian Sietsma noticed that, although not on purpose, our
|
Although not on purpose, our interface for sources is
|
||||||
interface for sources is compatible with Lua iterators.
|
compatible with Lua iterators. That is, a source can be
|
||||||
That is, a source can be neatly used in conjunction
|
neatly used in conjunction with \texttt{for} loops. Using
|
||||||
with \texttt{for} loops. Using our file
|
our file source as an iterator, we can write the following
|
||||||
source as an iterator, we can write the following code:
|
code:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
@@ -539,20 +553,22 @@ end
|
|||||||
The \texttt{pump.step} function moves one chunk of data from
|
The \texttt{pump.step} function moves one chunk of data from
|
||||||
the source to the sink. The \texttt{pump.all} function takes
|
the source to the sink. The \texttt{pump.all} function takes
|
||||||
an optional \texttt{step} function and uses it to pump all the
|
an optional \texttt{step} function and uses it to pump all the
|
||||||
data from the source to the sink. We can now use everything
|
data from the source to the sink.
|
||||||
we have to write a program that reads a binary file from
|
Here is an example that uses the Base64 and the
|
||||||
|
line wrapping filters from the \texttt{LuaSocket}
|
||||||
|
distribution. The program reads a binary file from
|
||||||
disk and stores it in another file, after encoding it to the
|
disk and stores it in another file, after encoding it to the
|
||||||
Base64 transfer content encoding:
|
Base64 transfer content encoding:
|
||||||
\begin{quote}
|
\begin{quote}
|
||||||
\begin{lua}
|
\begin{lua}
|
||||||
@stick#
|
@stick#
|
||||||
local in = source.chain(
|
local input = source.chain(
|
||||||
source.file(io.open("input.bin", "rb")),
|
source.file(io.open("input.bin", "rb")),
|
||||||
encode("base64"))
|
encode("base64"))
|
||||||
local out = sink.chain(
|
local output = sink.chain(
|
||||||
wrap(76),
|
wrap(76),
|
||||||
sink.file(io.open("output.b64", "w")))
|
sink.file(io.open("output.b64", "w")))
|
||||||
pump.all(in, out)
|
pump.all(input, output)
|
||||||
%
|
%
|
||||||
\end{lua}
|
\end{lua}
|
||||||
\end{quote}
|
\end{quote}
|
||||||
@@ -561,19 +577,17 @@ The way we split the filters here is not intuitive, on
|
|||||||
purpose. Alternatively, we could have chained the Base64
|
purpose. Alternatively, we could have chained the Base64
|
||||||
encode filter and the line-wrap filter together, and then
|
encode filter and the line-wrap filter together, and then
|
||||||
chain the resulting filter with either the file source or
|
chain the resulting filter with either the file source or
|
||||||
the file sink. It doesn't really matter. The Base64 and the
|
the file sink. It doesn't really matter.
|
||||||
line wrapping filters are part of the \texttt{LuaSocket}
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
\section{Exploding filters}
|
\section{Exploding filters}
|
||||||
|
|
||||||
Our current filter interface has one flagrant shortcoming.
|
Our current filter interface has one serious shortcoming.
|
||||||
When David Burgess was writing his \texttt{gzip} filter, he
|
Consider for example a \texttt{gzip} decompression filter.
|
||||||
noticed that a decompression filter can explode a small
|
During decompression, a small input chunk can be exploded
|
||||||
input chunk into a huge amount of data. To address this
|
into a huge amount of data. To address this problem, we
|
||||||
problem, we decided to change the filter interface and allow
|
decided to change the filter interface and allow exploding
|
||||||
exploding filters to return large quantities of output data
|
filters to return large quantities of output data in a chunk
|
||||||
in a chunk by chunk manner.
|
by chunk manner.
|
||||||
|
|
||||||
More specifically, after passing each chunk of input to
|
More specifically, after passing each chunk of input to
|
||||||
a filter, and collecting the first chunk of output, the
|
a filter, and collecting the first chunk of output, the
|
||||||
@@ -582,11 +596,11 @@ filtered data is left. Within these secondary calls, the
|
|||||||
caller passes an empty string to the filter. The filter
|
caller passes an empty string to the filter. The filter
|
||||||
responds with an empty string when it is ready for the next
|
responds with an empty string when it is ready for the next
|
||||||
input chunk. In the end, after the user passes a
|
input chunk. In the end, after the user passes a
|
||||||
\texttt{nil} chunk notifying the filter that there is no
|
\nil\ chunk notifying the filter that there is no
|
||||||
more input data, the filter might still have to produce too
|
more input data, the filter might still have to produce too
|
||||||
much output data to return in a single chunk. The user has
|
much output data to return in a single chunk. The user has
|
||||||
to loop again, now passing \texttt{nil} to the filter each time,
|
to loop again, now passing \nil\ to the filter each time,
|
||||||
until the filter itself returns \texttt{nil} to notify the
|
until the filter itself returns \nil\ to notify the
|
||||||
user it is finally done.
|
user it is finally done.
|
||||||
|
|
||||||
Fortunately, it is very easy to modify a filter to respect
|
Fortunately, it is very easy to modify a filter to respect
|
||||||
@@ -599,13 +613,13 @@ Interestingly, the modifications do not have a measurable
|
|||||||
negative impact in the performance of filters that do
|
negative impact in the performance of filters that do
|
||||||
not need the added flexibility. On the other hand, for a
|
not need the added flexibility. On the other hand, for a
|
||||||
small price in complexity, the changes make exploding
|
small price in complexity, the changes make exploding
|
||||||
filters practical.
|
filters practical.
|
||||||
|
|
||||||
\section{A complex example}
|
\section{A complex example}
|
||||||
|
|
||||||
The LTN12 module in the \texttt{LuaSocket} distribution
|
The LTN12 module in the \texttt{LuaSocket} distribution
|
||||||
implements the ideas we have described. The MIME
|
implements all the ideas we have described. The MIME
|
||||||
and SMTP modules are especially integrated with LTN12,
|
and SMTP modules are tightly integrated with LTN12,
|
||||||
and can be used to showcase the expressive power of filters,
|
and can be used to showcase the expressive power of filters,
|
||||||
sources, sinks, and pumps. Below is an example
|
sources, sinks, and pumps. Below is an example
|
||||||
of how a user would proceed to define and send a
|
of how a user would proceed to define and send a
|
||||||
@@ -622,9 +636,9 @@ local message = smtp.message{
|
|||||||
to = "Fulano <fulano@example.com>",
|
to = "Fulano <fulano@example.com>",
|
||||||
subject = "A message with an attachment"},
|
subject = "A message with an attachment"},
|
||||||
body = {
|
body = {
|
||||||
preamble = "Hope you can see the attachment\r\n",
|
preamble = "Hope you can see the attachment" .. CRLF,
|
||||||
[1] = {
|
[1] = {
|
||||||
body = "Here is our logo\r\n"},
|
body = "Here is our logo" .. CRLF},
|
||||||
[2] = {
|
[2] = {
|
||||||
headers = {
|
headers = {
|
||||||
["content-type"] = 'image/png; name="luasocket.png"',
|
["content-type"] = 'image/png; name="luasocket.png"',
|
||||||
@@ -652,7 +666,7 @@ SMTP dot-stuffing filter, connects a socket sink
|
|||||||
with the server, and simply pumps the data. The message is never
|
with the server, and simply pumps the data. The message is never
|
||||||
assembled in memory. Everything is produced on demand,
|
assembled in memory. Everything is produced on demand,
|
||||||
transformed in small pieces, and sent to the server in chunks,
|
transformed in small pieces, and sent to the server in chunks,
|
||||||
including the file attachment that is loaded from disk and
|
including the file attachment which is loaded from disk and
|
||||||
encoded on the fly. It just works.
|
encoded on the fly. It just works.
|
||||||
|
|
||||||
\section{Conclusions}
|
\section{Conclusions}
|
||||||
@@ -665,6 +679,17 @@ abstraction for final data destinations. Filters define an
|
|||||||
interface for data transformations. The chaining of
|
interface for data transformations. The chaining of
|
||||||
filters, sources and sinks provides an elegant way to create
|
filters, sources and sinks provides an elegant way to create
|
||||||
arbitrarily complex data transformations from simpler
|
arbitrarily complex data transformations from simpler
|
||||||
components. Pumps simply move the data through.
|
components. Pumps simply push the data through.
|
||||||
|
|
||||||
|
\section{Acknowledgements}
|
||||||
|
|
||||||
|
The concepts described in this text are the result of long
|
||||||
|
discussions with David Burgess. A version of this text has
|
||||||
|
been released on-line as the Lua Technical Note 012, hence
|
||||||
|
the name of the corresponding LuaSocket module, LTN12. Wim
|
||||||
|
Couwenberg contributed to the implementation of the module,
|
||||||
|
and Adrian Sietsma was the first to notice the
|
||||||
|
correspondence between sources and Lua iterators.
|
||||||
|
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
1
linux.cmd
Normal file
1
linux.cmd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/ubuntu/include LUAPREFIX_linux=/home/diego/build/ubuntu
|
||||||
@@ -126,8 +126,9 @@ local function chain2(f1, f2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function filter.chain(...)
|
function filter.chain(...)
|
||||||
|
local arg = {...}
|
||||||
local f = arg[1]
|
local f = arg[1]
|
||||||
for i = 2, table.getn(arg) do
|
for i = 2, #arg do
|
||||||
f = chain2(f, arg[i])
|
f = chain2(f, arg[i])
|
||||||
end
|
end
|
||||||
return f
|
return f
|
||||||
@@ -235,9 +236,10 @@ end
|
|||||||
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
|
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
|
||||||
{{{
|
{{{
|
||||||
function source.cat(...)
|
function source.cat(...)
|
||||||
|
local arg = {...}
|
||||||
local co = coroutine.create(function()
|
local co = coroutine.create(function()
|
||||||
local i = 1
|
local i = 1
|
||||||
while i <= table.getn(arg) do
|
while i <= #arg do
|
||||||
local chunk, err = arg[i]()
|
local chunk, err = arg[i]()
|
||||||
if chunk then coroutine.yield(chunk)
|
if chunk then coroutine.yield(chunk)
|
||||||
elseif err then return nil, err
|
elseif err then return nil, err
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ Fortunately, all these problems are very easy to solve and that's what we do in
|
|||||||
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
|
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
|
||||||
{{{
|
{{{
|
||||||
local function pack(ok, ...)
|
local function pack(ok, ...)
|
||||||
return ok, arg
|
return ok, {...}
|
||||||
end
|
end
|
||||||
|
|
||||||
function protect(f)
|
function protect(f)
|
||||||
return function(...)
|
return function(...)
|
||||||
local ok, ret = pack(pcall(f, unpack(arg)))
|
local ok, ret = pack(pcall(f, ...))
|
||||||
if ok then return unpack(ret)
|
if ok then return unpack(ret)
|
||||||
else return nil, ret[1] end
|
else return nil, ret[1] end
|
||||||
end
|
end
|
||||||
@@ -157,7 +157,7 @@ function newtry(f)
|
|||||||
if f then f() end
|
if f then f() end
|
||||||
error(arg[2], 0)
|
error(arg[2], 0)
|
||||||
else
|
else
|
||||||
return unpack(arg)
|
return ...
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,37 +1,35 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
# Visual Studio 2012
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcxproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcxproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libluasocket", "libluasocket.vcproj", "{599EAD40-60EE-4043-9C14-AE090A8A092D}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfiguration) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug = Debug
|
Debug|Win32 = Debug|Win32
|
||||||
Release = Release
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfiguration) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.ActiveCfg = Debug|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.Build.0 = Debug|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.ActiveCfg = Release|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.Build.0 = Release|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.Build.0 = Debug|x64
|
||||||
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.ActiveCfg = Debug|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.Build.0 = Debug|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.Build.0 = Release|Win32
|
||||||
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.ActiveCfg = Release|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.ActiveCfg = Release|x64
|
||||||
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.Build.0 = Release|Win32
|
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.Build.0 = Release|x64
|
||||||
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.ActiveCfg = Debug|Win32
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.Build.0 = Debug|Win32
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.ActiveCfg = Release|Win32
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.Build.0 = Release|Win32
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
EndGlobalSection
|
HideSolutionNode = FALSE
|
||||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
1
macosx.cmd
Normal file
1
macosx.cmd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/$USER/build/macosx/include LUAPREFIX_macosx=/Users/$USER/build/macosx install-both
|
||||||
84
makefile
Normal file → Executable file
84
makefile
Normal file → Executable file
@@ -1,51 +1,49 @@
|
|||||||
#------
|
# luasocket makefile
|
||||||
# Load configuration
|
|
||||||
#
|
#
|
||||||
include config
|
# see src/makefile for description of how to customize the build
|
||||||
|
|
||||||
#------
|
|
||||||
# Hopefully no need to change anything below this line
|
|
||||||
#
|
#
|
||||||
INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket
|
# Targets:
|
||||||
INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
|
# install install system independent support
|
||||||
INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
|
# install-unix also install unix-only support
|
||||||
INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
|
# install-both install for lua51 lua52 lua53
|
||||||
|
# install-both-unix also install unix-only
|
||||||
|
# print print the build settings
|
||||||
|
|
||||||
all clean:
|
PLAT?= linux
|
||||||
cd src; $(MAKE) $@
|
PLATS= macosx linux win32 win64 mingw freebsd solaris
|
||||||
|
|
||||||
#------
|
all: $(PLAT)
|
||||||
# Files to install
|
|
||||||
#
|
|
||||||
TO_SOCKET_SHARE:= \
|
|
||||||
http.lua \
|
|
||||||
url.lua \
|
|
||||||
tp.lua \
|
|
||||||
ftp.lua \
|
|
||||||
smtp.lua
|
|
||||||
|
|
||||||
TO_TOP_SHARE:= \
|
$(PLATS) none install install-unix local clean:
|
||||||
ltn12.lua \
|
$(MAKE) -C src $@
|
||||||
socket.lua \
|
|
||||||
mime.lua
|
|
||||||
|
|
||||||
TO_MIME_SHARE:=
|
print:
|
||||||
|
$(MAKE) -C src $@
|
||||||
|
|
||||||
#------
|
test:
|
||||||
# Install LuaSocket according to recommendation
|
lua test/hello.lua
|
||||||
#
|
|
||||||
install: all
|
install-both:
|
||||||
cd src; mkdir -p $(INSTALL_TOP_SHARE)
|
$(MAKE) clean
|
||||||
cd src; $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE)
|
@cd src; $(MAKE) $(PLAT) LUAV=5.1
|
||||||
cd src; mkdir -p $(INSTALL_SOCKET_SHARE)
|
@cd src; $(MAKE) install LUAV=5.1
|
||||||
cd src; $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE)
|
$(MAKE) clean
|
||||||
cd src; mkdir -p $(INSTALL_SOCKET_LIB)
|
@cd src; $(MAKE) $(PLAT) LUAV=5.2
|
||||||
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT)
|
@cd src; $(MAKE) install LUAV=5.2
|
||||||
#cd src; mkdir -p $(INSTALL_MIME_SHARE)
|
$(MAKE) clean
|
||||||
#cd src; $(INSTALL_DATA) $(TO_MIME_SHARE) $(INSTALL_MIME_SHARE)
|
@cd src; $(MAKE) $(PLAT) LUAV=5.3
|
||||||
cd src; mkdir -p $(INSTALL_MIME_LIB)
|
@cd src; $(MAKE) install LUAV=5.3
|
||||||
cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
|
|
||||||
|
install-both-unix:
|
||||||
|
$(MAKE) clean
|
||||||
|
@cd src; $(MAKE) $(PLAT) LUAV=5.1
|
||||||
|
@cd src; $(MAKE) install-unix LUAV=5.1
|
||||||
|
$(MAKE) clean
|
||||||
|
@cd src; $(MAKE) $(PLAT) LUAV=5.2
|
||||||
|
@cd src; $(MAKE) install-unix LUAV=5.2
|
||||||
|
$(MAKE) clean
|
||||||
|
@cd src; $(MAKE) $(PLAT) LUAV=5.3
|
||||||
|
@cd src; $(MAKE) install-unix LUAV=5.3
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
#------
|
|
||||||
# End of makefile
|
|
||||||
#
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
# Distribution makefile
|
# Distribution makefile
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
DIST = luasocket-2.0.2
|
DIST = luasocket-3.0-rc1
|
||||||
|
|
||||||
TEST = \
|
TEST = \
|
||||||
test/README \
|
test/README \
|
||||||
|
test/hello.lua \
|
||||||
test/testclnt.lua \
|
test/testclnt.lua \
|
||||||
test/testsrvr.lua \
|
test/testsrvr.lua \
|
||||||
test/testsupport.lua
|
test/testsupport.lua
|
||||||
@@ -15,6 +16,8 @@ SAMPLES = \
|
|||||||
samples/daytimeclnt.lua \
|
samples/daytimeclnt.lua \
|
||||||
samples/echoclnt.lua \
|
samples/echoclnt.lua \
|
||||||
samples/echosrvr.lua \
|
samples/echosrvr.lua \
|
||||||
|
samples/mclisten.lua \
|
||||||
|
samples/mcsend.lua \
|
||||||
samples/listener.lua \
|
samples/listener.lua \
|
||||||
samples/lpr.lua \
|
samples/lpr.lua \
|
||||||
samples/talker.lua \
|
samples/talker.lua \
|
||||||
@@ -62,6 +65,7 @@ SRC = \
|
|||||||
src/udp.c \
|
src/udp.c \
|
||||||
src/udp.h \
|
src/udp.h \
|
||||||
src/unix.c \
|
src/unix.c \
|
||||||
|
src/serial.c \
|
||||||
src/unix.h \
|
src/unix.h \
|
||||||
src/usocket.c \
|
src/usocket.c \
|
||||||
src/usocket.h \
|
src/usocket.h \
|
||||||
@@ -73,20 +77,25 @@ SRC = \
|
|||||||
src/mime.lua \
|
src/mime.lua \
|
||||||
src/smtp.lua \
|
src/smtp.lua \
|
||||||
src/socket.lua \
|
src/socket.lua \
|
||||||
|
src/headers.lua \
|
||||||
src/tp.lua \
|
src/tp.lua \
|
||||||
src/url.lua
|
src/url.lua
|
||||||
|
|
||||||
MAKE = \
|
MAKE = \
|
||||||
makefile \
|
makefile \
|
||||||
config \
|
|
||||||
luasocket.sln \
|
luasocket.sln \
|
||||||
socket.vcproj \
|
luasocket-scm-0.rockspec \
|
||||||
mime.vcproj
|
Lua51.props \
|
||||||
|
Lua52.props \
|
||||||
|
socket.vcxproj.filters \
|
||||||
|
mime.vcxproj.filters \
|
||||||
|
socket.vcxproj \
|
||||||
|
mime.vcxproj
|
||||||
|
|
||||||
DOC = \
|
DOC = \
|
||||||
doc/dns.html \
|
doc/dns.html \
|
||||||
doc/ftp.html \
|
doc/ftp.html \
|
||||||
doc/home.html \
|
doc/index.html \
|
||||||
doc/http.html \
|
doc/http.html \
|
||||||
doc/installation.html \
|
doc/installation.html \
|
||||||
doc/introduction.html \
|
doc/introduction.html \
|
||||||
|
|||||||
141
mime.vcproj
141
mime.vcproj
@@ -1,141 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="7.10"
|
|
||||||
Name="mime"
|
|
||||||
ProjectGUID="{128E8BD0-174A-48F0-8771-92B1E8D18713}"
|
|
||||||
Keyword="Win32Proj">
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"/>
|
|
||||||
</Platforms>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="src"
|
|
||||||
IntermediateDirectory="src"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="h:\include\lua5.1"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;MIME_API=__declspec(dllexport)"
|
|
||||||
MinimalRebuild="TRUE"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
|
||||||
DebugInformationFormat="4"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="$(OutDir)/mime.dll"
|
|
||||||
LinkIncremental="2"
|
|
||||||
AdditionalLibraryDirectories="h:\lib"
|
|
||||||
GenerateDebugInformation="TRUE"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/mime.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
ImportLibrary="$(OutDir)/mime.lib"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory="src"
|
|
||||||
IntermediateDirectory="src"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories="h:\include\lua5.1"
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="4"
|
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
|
||||||
DebugInformationFormat="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="$(OutDir)/mime.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories="h:\lib"
|
|
||||||
GenerateDebugInformation="TRUE"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
ImportLibrary="$(OutDir)/mime.lib"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Source Files"
|
|
||||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
|
||||||
<File
|
|
||||||
RelativePath="src\mime.c">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
|
||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
|
||||||
</Filter>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\lib\lua5.1.dll.lib">
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
204
mime.vcxproj
Executable file
204
mime.vcxproj
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\mime.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<OutDir>$(Configuration)\mime\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<OutDir>$(Configuration)\mime\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<DebugInformationFormat>
|
||||||
|
</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
1
mingw.cmd
Normal file
1
mingw.cmd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
make PLAT=mingw LUAINC_mingw_base=/home/diego/build/mingw/include LUALIB_mingw_base=/home/diego/build/mingw/bin LUAPREFIX_mingw=/home/diego/build/mingw/bin DEBUG=DEBUG install-both
|
||||||
134
rockspec/luasocket-3.0rc2-1.rockspec
Normal file
134
rockspec/luasocket-3.0rc2-1.rockspec
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package = "LuaSocket"
|
||||||
|
version = "3.0rc2-1"
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/diegonehab/luasocket.git",
|
||||||
|
tag = "v3.0-rc2",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "Network support for the Lua language",
|
||||||
|
detailed = [[
|
||||||
|
LuaSocket is a Lua extension library that is composed by two parts: a C core
|
||||||
|
that provides support for the TCP and UDP transport layers, and a set of Lua
|
||||||
|
modules that add support for functionality commonly needed by applications
|
||||||
|
that deal with the Internet.
|
||||||
|
]],
|
||||||
|
homepage = "http://luaforge.net/projects/luasocket/",
|
||||||
|
license = "MIT"
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function make_plat(plat)
|
||||||
|
local defines = {
|
||||||
|
unix = {
|
||||||
|
"LUASOCKET_DEBUG"
|
||||||
|
},
|
||||||
|
macosx = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"UNIX_HAS_SUN_LEN"
|
||||||
|
},
|
||||||
|
win32 = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"NDEBUG"
|
||||||
|
},
|
||||||
|
mingw32 = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"LUASOCKET_INET_PTON",
|
||||||
|
"WINVER=0x0501"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local modules = {
|
||||||
|
["socket.core"] = {
|
||||||
|
sources = {
|
||||||
|
"src/luasocket.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/buffer.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/inet.c"
|
||||||
|
, "src/except.c"
|
||||||
|
, "src/select.c"
|
||||||
|
, "src/tcp.c"
|
||||||
|
, "src/udp.c"
|
||||||
|
, "src/compat.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
},
|
||||||
|
["mime.core"] = {
|
||||||
|
sources = { "src/mime.c", "src/compat.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
},
|
||||||
|
["socket.http"] = "src/http.lua",
|
||||||
|
["socket.url"] = "src/url.lua",
|
||||||
|
["socket.tp"] = "src/tp.lua",
|
||||||
|
["socket.ftp"] = "src/ftp.lua",
|
||||||
|
["socket.headers"] = "src/headers.lua",
|
||||||
|
["socket.smtp"] = "src/smtp.lua",
|
||||||
|
ltn12 = "src/ltn12.lua",
|
||||||
|
socket = "src/socket.lua",
|
||||||
|
mime = "src/mime.lua"
|
||||||
|
}
|
||||||
|
if plat == "unix"
|
||||||
|
or plat == "macosx"
|
||||||
|
or plat == "haiku"
|
||||||
|
then
|
||||||
|
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
|
||||||
|
if plat == "haiku" then
|
||||||
|
modules["socket.core"].libraries = {"network"}
|
||||||
|
end
|
||||||
|
modules["socket.unix"] = {
|
||||||
|
sources = {
|
||||||
|
"src/buffer.c"
|
||||||
|
, "src/compat.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/usocket.c"
|
||||||
|
, "src/unix.c"
|
||||||
|
, "src/unixdgram.c"
|
||||||
|
, "src/unixstream.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
}
|
||||||
|
modules["socket.serial"] = {
|
||||||
|
sources = {
|
||||||
|
"src/buffer.c"
|
||||||
|
, "src/compat.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/usocket.c"
|
||||||
|
, "src/serial.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
if plat == "win32"
|
||||||
|
or plat == "mingw32"
|
||||||
|
then
|
||||||
|
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
|
||||||
|
modules["socket.core"].libraries = { "ws2_32" }
|
||||||
|
end
|
||||||
|
return { modules = modules }
|
||||||
|
end
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
platforms = {
|
||||||
|
unix = make_plat("unix"),
|
||||||
|
macosx = make_plat("macosx"),
|
||||||
|
haiku = make_plat("haiku"),
|
||||||
|
win32 = make_plat("win32"),
|
||||||
|
mingw32 = make_plat("mingw32")
|
||||||
|
},
|
||||||
|
copy_directories = {
|
||||||
|
"doc"
|
||||||
|
, "samples"
|
||||||
|
, "etc"
|
||||||
|
, "test" }
|
||||||
|
}
|
||||||
134
rockspec/luasocket-scm-2.rockspec
Normal file
134
rockspec/luasocket-scm-2.rockspec
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package = "LuaSocket"
|
||||||
|
version = "scm-2"
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/diegonehab/luasocket.git"
|
||||||
|
, branch="master"
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "Network support for the Lua language",
|
||||||
|
detailed = [[
|
||||||
|
LuaSocket is a Lua extension library that is composed by two parts: a C core
|
||||||
|
that provides support for the TCP and UDP transport layers, and a set of Lua
|
||||||
|
modules that add support for functionality commonly needed by applications
|
||||||
|
that deal with the Internet.
|
||||||
|
]],
|
||||||
|
homepage = "http://luaforge.net/projects/luasocket/",
|
||||||
|
license = "MIT"
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function make_plat(plat)
|
||||||
|
local defines = {
|
||||||
|
unix = {
|
||||||
|
"LUASOCKET_DEBUG"
|
||||||
|
},
|
||||||
|
macosx = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"UNIX_HAS_SUN_LEN"
|
||||||
|
},
|
||||||
|
win32 = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"NDEBUG"
|
||||||
|
},
|
||||||
|
mingw32 = {
|
||||||
|
"LUASOCKET_DEBUG",
|
||||||
|
"LUASOCKET_INET_PTON",
|
||||||
|
"WINVER=0x0501"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local modules = {
|
||||||
|
["socket.core"] = {
|
||||||
|
sources = {
|
||||||
|
"src/luasocket.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/buffer.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/inet.c"
|
||||||
|
, "src/except.c"
|
||||||
|
, "src/select.c"
|
||||||
|
, "src/tcp.c"
|
||||||
|
, "src/udp.c"
|
||||||
|
, "src/compat.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
},
|
||||||
|
["mime.core"] = {
|
||||||
|
sources = { "src/mime.c", "src/compat.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
},
|
||||||
|
["socket.http"] = "src/http.lua",
|
||||||
|
["socket.url"] = "src/url.lua",
|
||||||
|
["socket.tp"] = "src/tp.lua",
|
||||||
|
["socket.ftp"] = "src/ftp.lua",
|
||||||
|
["socket.headers"] = "src/headers.lua",
|
||||||
|
["socket.smtp"] = "src/smtp.lua",
|
||||||
|
ltn12 = "src/ltn12.lua",
|
||||||
|
socket = "src/socket.lua",
|
||||||
|
mime = "src/mime.lua"
|
||||||
|
}
|
||||||
|
if plat == "unix"
|
||||||
|
or plat == "macosx"
|
||||||
|
or plat == "haiku"
|
||||||
|
then
|
||||||
|
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
|
||||||
|
if plat == "haiku" then
|
||||||
|
modules["socket.core"].libraries = {"network"}
|
||||||
|
end
|
||||||
|
modules["socket.unix"] = {
|
||||||
|
sources = {
|
||||||
|
"src/buffer.c"
|
||||||
|
, "src/compat.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/usocket.c"
|
||||||
|
, "src/unix.c"
|
||||||
|
, "src/unixdgram.c"
|
||||||
|
, "src/unixstream.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
}
|
||||||
|
modules["socket.serial"] = {
|
||||||
|
sources = {
|
||||||
|
"src/buffer.c"
|
||||||
|
, "src/compat.c"
|
||||||
|
, "src/auxiliar.c"
|
||||||
|
, "src/options.c"
|
||||||
|
, "src/timeout.c"
|
||||||
|
, "src/io.c"
|
||||||
|
, "src/usocket.c"
|
||||||
|
, "src/serial.c" },
|
||||||
|
defines = defines[plat],
|
||||||
|
incdir = "/src"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
if plat == "win32"
|
||||||
|
or plat == "mingw32"
|
||||||
|
then
|
||||||
|
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
|
||||||
|
modules["socket.core"].libraries = { "ws2_32" }
|
||||||
|
end
|
||||||
|
return { modules = modules }
|
||||||
|
end
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
platforms = {
|
||||||
|
unix = make_plat("unix"),
|
||||||
|
macosx = make_plat("macosx"),
|
||||||
|
haiku = make_plat("haiku"),
|
||||||
|
win32 = make_plat("win32"),
|
||||||
|
mingw32 = make_plat("mingw32")
|
||||||
|
},
|
||||||
|
copy_directories = {
|
||||||
|
"doc"
|
||||||
|
, "samples"
|
||||||
|
, "etc"
|
||||||
|
, "test" }
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ end
|
|||||||
local host = socket.dns.gethostname()
|
local host = socket.dns.gethostname()
|
||||||
local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
|
local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
|
||||||
local url = string.format(query, server, arg[1], arg[2], host)
|
local url = string.format(query, server, arg[1], arg[2], host)
|
||||||
local body, headers, code = http.get(url)
|
local body, headers, code = http.request(url)
|
||||||
|
|
||||||
if code == 200 then
|
if code == 200 then
|
||||||
local data, code, error = parse(body)
|
local data, code, error = parse(body)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- UDP sample: daytime protocol client
|
-- UDP sample: daytime protocol client
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require"socket"
|
local socket = require"socket"
|
||||||
host = host or "127.0.0.1"
|
host = host or "127.0.0.1"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- UDP sample: echo protocol client
|
-- UDP sample: echo protocol client
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
host = host or "localhost"
|
host = host or "localhost"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- UDP sample: echo protocol server
|
-- UDP sample: echo protocol server
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
host = host or "127.0.0.1"
|
host = host or "127.0.0.1"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- TCP sample: Little program to dump lines received at a given port
|
-- TCP sample: Little program to dump lines received at a given port
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
host = host or "*"
|
host = host or "*"
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ end
|
|||||||
|
|
||||||
do
|
do
|
||||||
local opt = {}
|
local opt = {}
|
||||||
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)"
|
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]?.?)"
|
||||||
for i = 2, table.getn(arg), 1 do
|
for i = 2, #arg, 1 do
|
||||||
string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
|
string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
|
||||||
end
|
end
|
||||||
if not arg[2] then
|
if not arg[2] then
|
||||||
|
|||||||
18
samples/mclisten.lua
Normal file
18
samples/mclisten.lua
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
local socket = require"socket"
|
||||||
|
local group = "225.0.0.37"
|
||||||
|
local port = 12345
|
||||||
|
local c = assert(socket.udp())
|
||||||
|
print(assert(c:setoption("reuseport", true)))
|
||||||
|
print(assert(c:setsockname("*", port)))
|
||||||
|
--print("loop:", c:getoption("ip-multicast-loop"))
|
||||||
|
--print(assert(c:setoption("ip-multicast-loop", false)))
|
||||||
|
--print("loop:", c:getoption("ip-multicast-loop"))
|
||||||
|
--print("if:", c:getoption("ip-multicast-if"))
|
||||||
|
--print(assert(c:setoption("ip-multicast-if", "127.0.0.1")))
|
||||||
|
--print("if:", c:getoption("ip-multicast-if"))
|
||||||
|
--print(assert(c:setoption("ip-multicast-if", "10.0.1.4")))
|
||||||
|
--print("if:", c:getoption("ip-multicast-if"))
|
||||||
|
print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
|
||||||
|
while 1 do
|
||||||
|
print(c:receivefrom())
|
||||||
|
end
|
||||||
20
samples/mcsend.lua
Normal file
20
samples/mcsend.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
local socket = require"socket"
|
||||||
|
local group = "225.0.0.37"
|
||||||
|
local port = 12345
|
||||||
|
local c = assert(socket.udp())
|
||||||
|
--print(assert(c:setoption("reuseport", true)))
|
||||||
|
--print(assert(c:setsockname("*", port)))
|
||||||
|
--print(assert(c:setoption("ip-multicast-loop", false)))
|
||||||
|
--print(assert(c:setoption("ip-multicast-ttl", 4)))
|
||||||
|
--print(assert(c:setoption("ip-multicast-if", "10.0.1.3")))
|
||||||
|
--print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
|
||||||
|
local i = 0
|
||||||
|
while 1 do
|
||||||
|
local message = string.format("hello all %d!", i)
|
||||||
|
assert(c:sendto(message, group, port))
|
||||||
|
print("sent " .. message)
|
||||||
|
socket.sleep(1)
|
||||||
|
c:settimeout(0.5)
|
||||||
|
print(c:receivefrom())
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
-- TCP sample: Little program to send text lines to a given host/port
|
-- TCP sample: Little program to send text lines to a given host/port
|
||||||
-- LuaSocket sample files
|
-- LuaSocket sample files
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
host = host or "localhost"
|
host = host or "localhost"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- Select sample: simple text line server
|
-- Select sample: simple text line server
|
||||||
-- LuaSocket sample files.
|
-- LuaSocket sample files.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
host = host or "*"
|
host = host or "*"
|
||||||
@@ -32,7 +31,7 @@ function newset()
|
|||||||
insert = function(set, value)
|
insert = function(set, value)
|
||||||
if not reverse[value] then
|
if not reverse[value] then
|
||||||
table.insert(set, value)
|
table.insert(set, value)
|
||||||
reverse[value] = table.getn(set)
|
reverse[value] = #set
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
remove = function(set, value)
|
remove = function(set, value)
|
||||||
|
|||||||
182
socket.vcproj
182
socket.vcproj
@@ -1,182 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="7.10"
|
|
||||||
Name="socket"
|
|
||||||
ProjectGUID="{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
|
||||||
Keyword="Win32Proj">
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"/>
|
|
||||||
</Platforms>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="src"
|
|
||||||
IntermediateDirectory="src"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="h:\include\lua5.1"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport)"
|
|
||||||
MinimalRebuild="TRUE"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
|
||||||
DebugInformationFormat="4"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="ws2_32.lib"
|
|
||||||
OutputFile="$(OutDir)/socket.dll"
|
|
||||||
LinkIncremental="2"
|
|
||||||
AdditionalLibraryDirectories="h:\lib"
|
|
||||||
GenerateDebugInformation="TRUE"
|
|
||||||
ProgramDatabaseFile="$(OutDir)/socket.pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
ImportLibrary="$(OutDir)/socket.lib"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory="./src"
|
|
||||||
IntermediateDirectory="./src"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalIncludeDirectories="h:\include\lua5.1"
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
|
|
||||||
RuntimeLibrary="2"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
WarningLevel="3"
|
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
|
||||||
DebugInformationFormat="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="ws2_32.lib"
|
|
||||||
OutputFile="$(OutDir)/socket.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories="h:\lib"
|
|
||||||
GenerateDebugInformation="TRUE"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
ImportLibrary="$(OutDir)/socket.lib"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Source Files"
|
|
||||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
|
||||||
<File
|
|
||||||
RelativePath="src\auxiliar.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\buffer.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\except.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\inet.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\io.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\luasocket.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\options.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\select.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\tcp.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\timeout.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\udp.c">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="src\wsocket.c">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
GeneratePreprocessedFile="0"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
|
||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
|
||||||
</Filter>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\lib\lua5.1.dll.lib">
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
215
socket.vcxproj
Executable file
215
socket.vcxproj
Executable file
@@ -0,0 +1,215 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\auxiliar.c" />
|
||||||
|
<ClCompile Include="src\buffer.c" />
|
||||||
|
<ClCompile Include="src\except.c" />
|
||||||
|
<ClCompile Include="src\inet.c" />
|
||||||
|
<ClCompile Include="src\io.c" />
|
||||||
|
<ClCompile Include="src\luasocket.c" />
|
||||||
|
<ClCompile Include="src\options.c" />
|
||||||
|
<ClCompile Include="src\select.c" />
|
||||||
|
<ClCompile Include="src\tcp.c" />
|
||||||
|
<ClCompile Include="src\timeout.c" />
|
||||||
|
<ClCompile Include="src\udp.c" />
|
||||||
|
<ClCompile Include="src\wsocket.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
<Import Project="Lua.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<OutDir>$(Configuration)\socket\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<OutDir>$(Configuration)\socket\</OutDir>
|
||||||
|
<IntDir>$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
|
||||||
|
<TargetName>core</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<DebugInformationFormat>
|
||||||
|
</DebugInformationFormat>
|
||||||
|
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
|
||||||
|
<AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,17 +1,12 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Auxiliar routines for class hierarchy manipulation
|
* Auxiliar routines for class hierarchy manipulation
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
#include "luasocket.h"
|
||||||
|
#include "auxiliar.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "auxiliar.h"
|
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* Exported functions
|
|
||||||
\*=========================================================================*/
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes the module
|
* Initializes the module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -24,11 +19,11 @@ int auxiliar_open(lua_State *L) {
|
|||||||
* Creates a new class with given methods
|
* Creates a new class with given methods
|
||||||
* Methods whose names start with __ are passed directly to the metatable.
|
* Methods whose names start with __ are passed directly to the metatable.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func) {
|
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
|
||||||
luaL_newmetatable(L, classname); /* mt */
|
luaL_newmetatable(L, classname); /* mt */
|
||||||
/* create __index table to place methods */
|
/* create __index table to place methods */
|
||||||
lua_pushstring(L, "__index"); /* mt,"__index" */
|
lua_pushstring(L, "__index"); /* mt,"__index" */
|
||||||
lua_newtable(L); /* mt,"__index",it */
|
lua_newtable(L); /* mt,"__index",it */
|
||||||
/* put class name into class metatable */
|
/* put class name into class metatable */
|
||||||
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
|
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
|
||||||
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
|
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
|
||||||
@@ -81,12 +76,12 @@ void auxiliar_add2group(lua_State *L, const char *classname, const char *groupna
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int auxiliar_checkboolean(lua_State *L, int objidx) {
|
int auxiliar_checkboolean(lua_State *L, int objidx) {
|
||||||
if (!lua_isboolean(L, objidx))
|
if (!lua_isboolean(L, objidx))
|
||||||
luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
|
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
|
||||||
return lua_toboolean(L, objidx);
|
return lua_toboolean(L, objidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Return userdata pointer if object belongs to a given class, abort with
|
* Return userdata pointer if object belongs to a given class, abort with
|
||||||
* error otherwise
|
* error otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
|
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
|
||||||
@@ -100,7 +95,7 @@ void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Return userdata pointer if object belongs to a given group, abort with
|
* Return userdata pointer if object belongs to a given group, abort with
|
||||||
* error otherwise
|
* error otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
|
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
|
||||||
@@ -123,7 +118,7 @@ void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Get a userdata pointer if object belongs to a given group. Return NULL
|
* Get a userdata pointer if object belongs to a given group. Return NULL
|
||||||
* otherwise
|
* otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
||||||
@@ -141,9 +136,19 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Get a userdata pointer if object belongs to a given class. Return NULL
|
* Get a userdata pointer if object belongs to a given class. Return NULL
|
||||||
* otherwise
|
* otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
|
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
|
||||||
return luaL_checkudata(L, objidx, classname);
|
return luaL_testudata(L, objidx, classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Throws error when argument does not have correct type.
|
||||||
|
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
|
||||||
|
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
|
||||||
|
luaL_typename(L, narg));
|
||||||
|
return luaL_argerror(L, narg, msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
* Auxiliar routines for class hierarchy manipulation
|
* Auxiliar routines for class hierarchy manipulation
|
||||||
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
|
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
|
||||||
*
|
*
|
||||||
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
|
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
|
||||||
* group is a name associated with a class. A class can belong to any number
|
* group is a name associated with a class. A class can belong to any number
|
||||||
* of groups. This module provides the functionality to:
|
* of groups. This module provides the functionality to:
|
||||||
*
|
*
|
||||||
* - create new classes
|
* - create new classes
|
||||||
* - add classes to groups
|
* - add classes to groups
|
||||||
* - set the class of objects
|
* - set the class of objects
|
||||||
* - check if an object belongs to a given class or group
|
* - check if an object belongs to a given class or group
|
||||||
* - get the userdata associated to objects
|
* - get the userdata associated to objects
|
||||||
@@ -26,23 +26,29 @@
|
|||||||
* "class" with the class name.
|
* "class" with the class name.
|
||||||
*
|
*
|
||||||
* The mapping from class name to the corresponding metatable and the
|
* The mapping from class name to the corresponding metatable and the
|
||||||
* reverse mapping are done using lauxlib.
|
* reverse mapping are done using lauxlib.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
#include "lauxlib.h"
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int auxiliar_open(lua_State *L);
|
int auxiliar_open(lua_State *L);
|
||||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func);
|
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
|
||||||
|
int auxiliar_tostring(lua_State *L);
|
||||||
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
|
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
|
||||||
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
|
int auxiliar_checkboolean(lua_State *L, int objidx);
|
||||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
|
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
|
||||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
|
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
|
||||||
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
|
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
|
||||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
|
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
|
||||||
int auxiliar_checkboolean(lua_State *L, int objidx);
|
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
|
||||||
int auxiliar_tostring(lua_State *L);
|
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* AUXILIAR_H */
|
#endif /* AUXILIAR_H */
|
||||||
|
|||||||
60
src/buffer.c
60
src/buffer.c
@@ -1,12 +1,8 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Input/Output interface for Lua programs
|
* Input/Output interface for Lua programs
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
@@ -39,10 +35,10 @@ int buffer_open(lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes C structure
|
* Initializes C structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
|
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
|
||||||
buf->first = buf->last = 0;
|
buf->first = buf->last = 0;
|
||||||
buf->io = io;
|
buf->io = io;
|
||||||
buf->tm = tm;
|
buf->tm = tm;
|
||||||
buf->received = buf->sent = 0;
|
buf->received = buf->sent = 0;
|
||||||
@@ -53,8 +49,8 @@ void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
|
|||||||
* object:getstats() interface
|
* object:getstats() interface
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
|
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
|
||||||
lua_pushnumber(L, buf->received);
|
lua_pushnumber(L, (lua_Number) buf->received);
|
||||||
lua_pushnumber(L, buf->sent);
|
lua_pushnumber(L, (lua_Number) buf->sent);
|
||||||
lua_pushnumber(L, timeout_gettime() - buf->birthday);
|
lua_pushnumber(L, timeout_gettime() - buf->birthday);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -63,8 +59,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
|
|||||||
* object:setstats() interface
|
* object:setstats() interface
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
|
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
|
||||||
buf->received = (long) luaL_optnumber(L, 2, buf->received);
|
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
|
||||||
buf->sent = (long) luaL_optnumber(L, 3, buf->sent);
|
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
|
||||||
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
|
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
|
||||||
lua_pushnumber(L, 1);
|
lua_pushnumber(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -80,7 +76,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
|
|||||||
const char *data = luaL_checklstring(L, 2, &size);
|
const char *data = luaL_checklstring(L, 2, &size);
|
||||||
long start = (long) luaL_optnumber(L, 3, 1);
|
long start = (long) luaL_optnumber(L, 3, 1);
|
||||||
long end = (long) luaL_optnumber(L, 4, -1);
|
long end = (long) luaL_optnumber(L, 4, -1);
|
||||||
p_timeout tm = timeout_markstart(buf->tm);
|
timeout_markstart(buf->tm);
|
||||||
if (start < 0) start = (long) (size+start+1);
|
if (start < 0) start = (long) (size+start+1);
|
||||||
if (end < 0) end = (long) (size+end+1);
|
if (end < 0) end = (long) (size+end+1);
|
||||||
if (start < 1) start = (long) 1;
|
if (start < 1) start = (long) 1;
|
||||||
@@ -89,16 +85,16 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
|
|||||||
/* check if there was an error */
|
/* check if there was an error */
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||||
lua_pushnumber(L, sent+start-1);
|
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||||
} else {
|
} else {
|
||||||
lua_pushnumber(L, sent+start-1);
|
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
#ifdef LUASOCKET_DEBUG
|
#ifdef LUASOCKET_DEBUG
|
||||||
/* push time elapsed during operation as the last return value */
|
/* push time elapsed during operation as the last return value */
|
||||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@@ -111,8 +107,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
|
|||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
size_t size;
|
size_t size;
|
||||||
const char *part = luaL_optlstring(L, 3, "", &size);
|
const char *part = luaL_optlstring(L, 3, "", &size);
|
||||||
p_timeout tm = timeout_markstart(buf->tm);
|
timeout_markstart(buf->tm);
|
||||||
/* initialize buffer with optional extra prefix
|
/* initialize buffer with optional extra prefix
|
||||||
* (useful for concatenating previous partial results) */
|
* (useful for concatenating previous partial results) */
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
luaL_addlstring(&b, part, size);
|
luaL_addlstring(&b, part, size);
|
||||||
@@ -120,18 +116,24 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
|
|||||||
if (!lua_isnumber(L, 2)) {
|
if (!lua_isnumber(L, 2)) {
|
||||||
const char *p= luaL_optstring(L, 2, "*l");
|
const char *p= luaL_optstring(L, 2, "*l");
|
||||||
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
|
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
|
||||||
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
|
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
|
||||||
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
|
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
|
||||||
/* get a fixed number of bytes (minus what was already partially
|
/* get a fixed number of bytes (minus what was already partially
|
||||||
* received) */
|
* received) */
|
||||||
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
|
} else {
|
||||||
|
double n = lua_tonumber(L, 2);
|
||||||
|
size_t wanted = (size_t) n;
|
||||||
|
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
|
||||||
|
if (size == 0 || wanted > size)
|
||||||
|
err = recvraw(buf, wanted-size, &b);
|
||||||
|
}
|
||||||
/* check if there was an error */
|
/* check if there was an error */
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
/* we can't push anyting in the stack before pushing the
|
/* we can't push anyting in the stack before pushing the
|
||||||
* contents of the buffer. this is the reason for the complication */
|
* contents of the buffer. this is the reason for the complication */
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_replace(L, -4);
|
lua_replace(L, -4);
|
||||||
} else {
|
} else {
|
||||||
@@ -141,7 +143,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
|
|||||||
}
|
}
|
||||||
#ifdef LUASOCKET_DEBUG
|
#ifdef LUASOCKET_DEBUG
|
||||||
/* push time elapsed during operation as the last return value */
|
/* push time elapsed during operation as the last return value */
|
||||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@@ -166,7 +168,7 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
|
|||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
while (total < count && err == IO_DONE) {
|
while (total < count && err == IO_DONE) {
|
||||||
size_t done;
|
size_t done = 0;
|
||||||
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
|
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
|
||||||
err = io->send(io->ctx, data+total, step, &done, tm);
|
err = io->send(io->ctx, data+total, step, &done, tm);
|
||||||
total += done;
|
total += done;
|
||||||
@@ -214,7 +216,7 @@ static int recvall(p_buffer buf, luaL_Buffer *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
||||||
* are not returned by the function and are discarded from the buffer
|
* are not returned by the function and are discarded from the buffer
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int recvline(p_buffer buf, luaL_Buffer *b) {
|
static int recvline(p_buffer buf, luaL_Buffer *b) {
|
||||||
@@ -225,7 +227,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
while (pos < count && data[pos] != '\n') {
|
while (pos < count && data[pos] != '\n') {
|
||||||
/* we ignore all \r's */
|
/* we ignore all \r's */
|
||||||
if (data[pos] != '\r') luaL_putchar(b, data[pos]);
|
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
if (pos < count) { /* found '\n' */
|
if (pos < count) { /* found '\n' */
|
||||||
@@ -244,7 +246,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
|
|||||||
static void buffer_skip(p_buffer buf, size_t count) {
|
static void buffer_skip(p_buffer buf, size_t count) {
|
||||||
buf->received += count;
|
buf->received += count;
|
||||||
buf->first += count;
|
buf->first += count;
|
||||||
if (buffer_isempty(buf))
|
if (buffer_isempty(buf))
|
||||||
buf->first = buf->last = 0;
|
buf->first = buf->last = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
src/buffer.h
21
src/buffer.h
@@ -14,11 +14,8 @@
|
|||||||
*
|
*
|
||||||
* The module is built on top of the I/O abstraction defined in io.h and the
|
* The module is built on top of the I/O abstraction defined in io.h and the
|
||||||
* timeout management is done with the timeout.h interface.
|
* timeout management is done with the timeout.h interface.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
|
|
||||||
@@ -31,17 +28,25 @@ typedef struct t_buffer_ {
|
|||||||
size_t sent, received; /* bytes sent, and bytes received */
|
size_t sent, received; /* bytes sent, and bytes received */
|
||||||
p_io io; /* IO driver used for this buffer */
|
p_io io; /* IO driver used for this buffer */
|
||||||
p_timeout tm; /* timeout management for this buffer */
|
p_timeout tm; /* timeout management for this buffer */
|
||||||
size_t first, last; /* index of first and last bytes of stored data */
|
size_t first, last; /* index of first and last bytes of stored data */
|
||||||
char data[BUF_SIZE]; /* storage space for buffer data */
|
char data[BUF_SIZE]; /* storage space for buffer data */
|
||||||
} t_buffer;
|
} t_buffer;
|
||||||
typedef t_buffer *p_buffer;
|
typedef t_buffer *p_buffer;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int buffer_open(lua_State *L);
|
int buffer_open(lua_State *L);
|
||||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
|
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
|
||||||
int buffer_meth_send(lua_State *L, p_buffer buf);
|
|
||||||
int buffer_meth_receive(lua_State *L, p_buffer buf);
|
|
||||||
int buffer_meth_getstats(lua_State *L, p_buffer buf);
|
int buffer_meth_getstats(lua_State *L, p_buffer buf);
|
||||||
int buffer_meth_setstats(lua_State *L, p_buffer buf);
|
int buffer_meth_setstats(lua_State *L, p_buffer buf);
|
||||||
|
int buffer_meth_send(lua_State *L, p_buffer buf);
|
||||||
|
int buffer_meth_receive(lua_State *L, p_buffer buf);
|
||||||
int buffer_isempty(p_buffer buf);
|
int buffer_isempty(p_buffer buf);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* BUF_H */
|
#endif /* BUF_H */
|
||||||
|
|||||||
39
src/compat.c
Normal file
39
src/compat.c
Normal 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
22
src/compat.h
Normal 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
|
||||||
94
src/except.c
94
src/except.c
@@ -1,15 +1,19 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Simple exception support
|
* Simple exception support
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
#include "luasocket.h"
|
||||||
|
#include "except.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#if LUA_VERSION_NUM < 502
|
||||||
#include "lauxlib.h"
|
#define lua_pcallk(L, na, nr, err, ctx, cont) \
|
||||||
|
(((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "except.h"
|
#if LUA_VERSION_NUM < 503
|
||||||
|
typedef int lua_KContext;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal function prototypes.
|
* Internal function prototypes.
|
||||||
@@ -21,7 +25,7 @@ static int finalize(lua_State *L);
|
|||||||
static int do_nothing(lua_State *L);
|
static int do_nothing(lua_State *L);
|
||||||
|
|
||||||
/* except functions */
|
/* except functions */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"newtry", global_newtry},
|
{"newtry", global_newtry},
|
||||||
{"protect", global_protect},
|
{"protect", global_protect},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
@@ -31,18 +35,17 @@ static luaL_reg func[] = {
|
|||||||
* Try factory
|
* Try factory
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void wrap(lua_State *L) {
|
static void wrap(lua_State *L) {
|
||||||
lua_newtable(L);
|
lua_createtable(L, 1, 0);
|
||||||
lua_pushnumber(L, 1);
|
lua_pushvalue(L, -2);
|
||||||
lua_pushvalue(L, -3);
|
lua_rawseti(L, -2, 1);
|
||||||
lua_settable(L, -3);
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
lua_insert(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finalize(lua_State *L) {
|
static int finalize(lua_State *L) {
|
||||||
if (!lua_toboolean(L, 1)) {
|
if (!lua_toboolean(L, 1)) {
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
lua_pushvalue(L, lua_upvalueindex(2));
|
||||||
lua_pcall(L, 0, 0, 0);
|
lua_call(L, 0, 0);
|
||||||
lua_settop(L, 2);
|
lua_settop(L, 2);
|
||||||
wrap(L);
|
wrap(L);
|
||||||
lua_error(L);
|
lua_error(L);
|
||||||
@@ -50,15 +53,17 @@ static int finalize(lua_State *L) {
|
|||||||
} else return lua_gettop(L);
|
} else return lua_gettop(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_nothing(lua_State *L) {
|
static int do_nothing(lua_State *L) {
|
||||||
(void) L;
|
(void) L;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int global_newtry(lua_State *L) {
|
static int global_newtry(lua_State *L) {
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
|
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
|
||||||
lua_pushcclosure(L, finalize, 1);
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_insert(L, -2);
|
||||||
|
lua_pushcclosure(L, finalize, 2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,27 +71,49 @@ static int global_newtry(lua_State *L) {
|
|||||||
* Protect factory
|
* Protect factory
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int unwrap(lua_State *L) {
|
static int unwrap(lua_State *L) {
|
||||||
if (lua_istable(L, -1)) {
|
if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
|
||||||
lua_pushnumber(L, 1);
|
int r = lua_rawequal(L, -1, lua_upvalueindex(1));
|
||||||
lua_gettable(L, -2);
|
lua_pop(L, 1);
|
||||||
lua_pushnil(L);
|
if (r) {
|
||||||
lua_insert(L, -2);
|
lua_pushnil(L);
|
||||||
return 1;
|
lua_rawgeti(L, -2, 1);
|
||||||
} else return 0;
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int protected_(lua_State *L) {
|
static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
(void)ctx;
|
||||||
lua_insert(L, 1);
|
if (status != 0 && status != LUA_YIELD) {
|
||||||
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
|
|
||||||
if (unwrap(L)) return 2;
|
if (unwrap(L)) return 2;
|
||||||
else lua_error(L);
|
else return lua_error(L);
|
||||||
return 0;
|
|
||||||
} else return lua_gettop(L);
|
} else return lua_gettop(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM == 502
|
||||||
|
static int protected_cont(lua_State *L) {
|
||||||
|
int ctx = 0;
|
||||||
|
int status = lua_getctx(L, &ctx);
|
||||||
|
return protected_finish(L, status, ctx);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define protected_cont protected_finish
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int protected_(lua_State *L) {
|
||||||
|
int status;
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(2));
|
||||||
|
lua_insert(L, 1);
|
||||||
|
status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
|
||||||
|
return protected_finish(L, status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int global_protect(lua_State *L) {
|
static int global_protect(lua_State *L) {
|
||||||
lua_pushcclosure(L, protected_, 1);
|
lua_settop(L, 1);
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_insert(L, 1);
|
||||||
|
lua_pushcclosure(L, protected_, 2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +121,9 @@ static int global_protect(lua_State *L) {
|
|||||||
* Init module
|
* Init module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int except_open(lua_State *L) {
|
int except_open(lua_State *L) {
|
||||||
luaL_openlib(L, NULL, func, 0);
|
lua_newtable(L); /* metatable for wrapped exceptions */
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
lua_setfield(L, -2, "__metatable");
|
||||||
|
luaL_setfuncs(L, func, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/except.h
33
src/except.h
@@ -9,27 +9,38 @@
|
|||||||
* error checking was taking a substantial amount of the coding. These
|
* error checking was taking a substantial amount of the coding. These
|
||||||
* function greatly simplify the task of checking errors.
|
* function greatly simplify the task of checking errors.
|
||||||
*
|
*
|
||||||
* The main idea is that functions should return nil as its first return
|
* The main idea is that functions should return nil as their first return
|
||||||
* value when it finds an error, and return an error message (or value)
|
* values when they find an error, and return an error message (or value)
|
||||||
* following nil. In case of success, as long as the first value is not nil,
|
* following nil. In case of success, as long as the first value is not nil,
|
||||||
* the other values don't matter.
|
* the other values don't matter.
|
||||||
*
|
*
|
||||||
* The idea is to nest function calls with the "try" function. This function
|
* The idea is to nest function calls with the "try" function. This function
|
||||||
* checks the first value, and calls "error" on the second if the first is
|
* checks the first value, and, if it's falsy, wraps the second value in a
|
||||||
* nil. Otherwise, it returns all values it received.
|
* table with metatable and calls "error" on it. Otherwise, it returns all
|
||||||
|
* values it received. Basically, it works like the Lua "assert" function,
|
||||||
|
* but it creates errors targeted specifically at "protect".
|
||||||
*
|
*
|
||||||
* The protect function returns a new function that behaves exactly like the
|
* The "newtry" function is a factory for "try" functions that call a
|
||||||
* function it receives, but the new function doesn't throw exceptions: it
|
* finalizer in protected mode before calling "error".
|
||||||
* returns nil followed by the error message instead.
|
|
||||||
*
|
*
|
||||||
* With these two function, it's easy to write functions that throw
|
* The "protect" function returns a new function that behaves exactly like
|
||||||
* exceptions on error, but that don't interrupt the user script.
|
* the function it receives, but the new function catches exceptions thrown
|
||||||
|
* by "try" functions and returns nil followed by the error message instead.
|
||||||
*
|
*
|
||||||
* RCS ID: $Id$
|
* With these three functions, it's easy to write functions that throw
|
||||||
|
* exceptions on error, but that don't interrupt the user script.
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int except_open(lua_State *L);
|
int except_open(lua_State *L);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
132
src/ftp.lua
132
src/ftp.lua
@@ -2,7 +2,6 @@
|
|||||||
-- FTP support for the Lua language
|
-- FTP support for the Lua language
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -16,27 +15,27 @@ local socket = require("socket")
|
|||||||
local url = require("socket.url")
|
local url = require("socket.url")
|
||||||
local tp = require("socket.tp")
|
local tp = require("socket.tp")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
module("socket.ftp")
|
socket.ftp = {}
|
||||||
|
local _M = socket.ftp
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Program constants
|
-- Program constants
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- timeout in seconds before the program gives up on a connection
|
-- timeout in seconds before the program gives up on a connection
|
||||||
TIMEOUT = 60
|
_M.TIMEOUT = 60
|
||||||
-- default port for ftp service
|
-- default port for ftp service
|
||||||
PORT = 21
|
local PORT = 21
|
||||||
-- this is the default anonymous password. used when no password is
|
-- this is the default anonymous password. used when no password is
|
||||||
-- provided in url. should be changed to your e-mail.
|
-- provided in url. should be changed to your e-mail.
|
||||||
USER = "ftp"
|
_M.USER = "ftp"
|
||||||
PASSWORD = "anonymous@anonymous.org"
|
_M.PASSWORD = "anonymous@anonymous.org"
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Low level FTP API
|
-- Low level FTP API
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local metat = { __index = {} }
|
local metat = { __index = {} }
|
||||||
|
|
||||||
function open(server, port, create)
|
function _M.open(server, port, create)
|
||||||
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
|
local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
|
||||||
local f = base.setmetatable({ tp = tp }, metat)
|
local f = base.setmetatable({ tp = tp }, metat)
|
||||||
-- make sure everything gets closed in an exception
|
-- make sure everything gets closed in an exception
|
||||||
f.try = socket.newtry(function() f:close() end)
|
f.try = socket.newtry(function() f:close() end)
|
||||||
@@ -44,22 +43,22 @@ function open(server, port, create)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:portconnect()
|
function metat.__index:portconnect()
|
||||||
self.try(self.server:settimeout(TIMEOUT))
|
self.try(self.server:settimeout(_M.TIMEOUT))
|
||||||
self.data = self.try(self.server:accept())
|
self.data = self.try(self.server:accept())
|
||||||
self.try(self.data:settimeout(TIMEOUT))
|
self.try(self.data:settimeout(_M.TIMEOUT))
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:pasvconnect()
|
function metat.__index:pasvconnect()
|
||||||
self.data = self.try(socket.tcp())
|
self.data = self.try(socket.tcp())
|
||||||
self.try(self.data:settimeout(TIMEOUT))
|
self.try(self.data:settimeout(_M.TIMEOUT))
|
||||||
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
|
self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:login(user, password)
|
function metat.__index:login(user, password)
|
||||||
self.try(self.tp:command("user", user or USER))
|
self.try(self.tp:command("user", user or _M.USER))
|
||||||
local code, reply = self.try(self.tp:check{"2..", 331})
|
local code, reply = self.try(self.tp:check{"2..", 331})
|
||||||
if code == 331 then
|
if code == 331 then
|
||||||
self.try(self.tp:command("pass", password or PASSWORD))
|
self.try(self.tp:command("pass", password or _M.PASSWORD))
|
||||||
self.try(self.tp:check("2.."))
|
self.try(self.tp:check("2.."))
|
||||||
end
|
end
|
||||||
return 1
|
return 1
|
||||||
@@ -72,32 +71,65 @@ function metat.__index:pasv()
|
|||||||
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
|
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
|
||||||
self.try(a and b and c and d and p1 and p2, reply)
|
self.try(a and b and c and d and p1 and p2, reply)
|
||||||
self.pasvt = {
|
self.pasvt = {
|
||||||
ip = string.format("%d.%d.%d.%d", a, b, c, d),
|
address = string.format("%d.%d.%d.%d", a, b, c, d),
|
||||||
port = p1*256 + p2
|
port = p1*256 + p2
|
||||||
}
|
}
|
||||||
if self.server then
|
if self.server then
|
||||||
self.server:close()
|
self.server:close()
|
||||||
self.server = nil
|
self.server = nil
|
||||||
end
|
end
|
||||||
return self.pasvt.ip, self.pasvt.port
|
return self.pasvt.address, self.pasvt.port
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:port(ip, port)
|
function metat.__index:epsv()
|
||||||
|
self.try(self.tp:command("epsv"))
|
||||||
|
local code, reply = self.try(self.tp:check("229"))
|
||||||
|
local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
|
||||||
|
local d, prt, address, port = string.match(reply, pattern)
|
||||||
|
self.try(port, "invalid epsv response")
|
||||||
|
self.pasvt = {
|
||||||
|
address = self.tp:getpeername(),
|
||||||
|
port = port
|
||||||
|
}
|
||||||
|
if self.server then
|
||||||
|
self.server:close()
|
||||||
|
self.server = nil
|
||||||
|
end
|
||||||
|
return self.pasvt.address, self.pasvt.port
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function metat.__index:port(address, port)
|
||||||
self.pasvt = nil
|
self.pasvt = nil
|
||||||
if not ip then
|
if not address then
|
||||||
ip, port = self.try(self.tp:getcontrol():getsockname())
|
address, port = self.try(self.tp:getsockname())
|
||||||
self.server = self.try(socket.bind(ip, 0))
|
self.server = self.try(socket.bind(address, 0))
|
||||||
ip, port = self.try(self.server:getsockname())
|
address, port = self.try(self.server:getsockname())
|
||||||
self.try(self.server:settimeout(TIMEOUT))
|
self.try(self.server:settimeout(_M.TIMEOUT))
|
||||||
end
|
end
|
||||||
local pl = math.mod(port, 256)
|
local pl = math.mod(port, 256)
|
||||||
local ph = (port - pl)/256
|
local ph = (port - pl)/256
|
||||||
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
|
local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",")
|
||||||
self.try(self.tp:command("port", arg))
|
self.try(self.tp:command("port", arg))
|
||||||
self.try(self.tp:check("2.."))
|
self.try(self.tp:check("2.."))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function metat.__index:eprt(family, address, port)
|
||||||
|
self.pasvt = nil
|
||||||
|
if not address then
|
||||||
|
address, port = self.try(self.tp:getsockname())
|
||||||
|
self.server = self.try(socket.bind(address, 0))
|
||||||
|
address, port = self.try(self.server:getsockname())
|
||||||
|
self.try(self.server:settimeout(_M.TIMEOUT))
|
||||||
|
end
|
||||||
|
local arg = string.format("|%s|%s|%d|", family, address, port)
|
||||||
|
self.try(self.tp:command("eprt", arg))
|
||||||
|
self.try(self.tp:check("2.."))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function metat.__index:send(sendt)
|
function metat.__index:send(sendt)
|
||||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
self.try(self.pasvt or self.server, "need port or pasv first")
|
||||||
-- if there is a pasvt table, we already sent a PASV command
|
-- if there is a pasvt table, we already sent a PASV command
|
||||||
@@ -111,12 +143,12 @@ function metat.__index:send(sendt)
|
|||||||
-- send the transfer command and check the reply
|
-- send the transfer command and check the reply
|
||||||
self.try(self.tp:command(command, argument))
|
self.try(self.tp:command(command, argument))
|
||||||
local code, reply = self.try(self.tp:check{"2..", "1.."})
|
local code, reply = self.try(self.tp:check{"2..", "1.."})
|
||||||
-- if there is not a a pasvt table, then there is a server
|
-- if there is not a pasvt table, then there is a server
|
||||||
-- and we already sent a PORT command
|
-- and we already sent a PORT command
|
||||||
if not self.pasvt then self:portconnect() end
|
if not self.pasvt then self:portconnect() end
|
||||||
-- get the sink, source and step for the transfer
|
-- get the sink, source and step for the transfer
|
||||||
local step = sendt.step or ltn12.pump.step
|
local step = sendt.step or ltn12.pump.step
|
||||||
local readt = {self.tp.c}
|
local readt = { self.tp }
|
||||||
local checkstep = function(src, snk)
|
local checkstep = function(src, snk)
|
||||||
-- check status in control connection while downloading
|
-- check status in control connection while downloading
|
||||||
local readyt = socket.select(readt, nil, 0)
|
local readyt = socket.select(readt, nil, 0)
|
||||||
@@ -143,7 +175,11 @@ function metat.__index:receive(recvt)
|
|||||||
if argument == "" then argument = nil end
|
if argument == "" then argument = nil end
|
||||||
local command = recvt.command or "retr"
|
local command = recvt.command or "retr"
|
||||||
self.try(self.tp:command(command, argument))
|
self.try(self.tp:command(command, argument))
|
||||||
local code = self.try(self.tp:check{"1..", "2.."})
|
local code,reply = self.try(self.tp:check{"1..", "2.."})
|
||||||
|
if (code >= 200) and (code <= 299) then
|
||||||
|
recvt.sink(reply)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
if not self.pasvt then self:portconnect() end
|
if not self.pasvt then self:portconnect() end
|
||||||
local source = socket.source("until-closed", self.data)
|
local source = socket.source("until-closed", self.data)
|
||||||
local step = recvt.step or ltn12.pump.step
|
local step = recvt.step or ltn12.pump.step
|
||||||
@@ -200,11 +236,11 @@ end
|
|||||||
local function tput(putt)
|
local function tput(putt)
|
||||||
putt = override(putt)
|
putt = override(putt)
|
||||||
socket.try(putt.host, "missing hostname")
|
socket.try(putt.host, "missing hostname")
|
||||||
local f = open(putt.host, putt.port, putt.create)
|
local f = _M.open(putt.host, putt.port, putt.create)
|
||||||
f:greet()
|
f:greet()
|
||||||
f:login(putt.user, putt.password)
|
f:login(putt.user, putt.password)
|
||||||
if putt.type then f:type(putt.type) end
|
if putt.type then f:type(putt.type) end
|
||||||
f:pasv()
|
f:epsv()
|
||||||
local sent = f:send(putt)
|
local sent = f:send(putt)
|
||||||
f:quit()
|
f:quit()
|
||||||
f:close()
|
f:close()
|
||||||
@@ -212,11 +248,11 @@ local function tput(putt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local default = {
|
local default = {
|
||||||
path = "/",
|
path = "/",
|
||||||
scheme = "ftp"
|
scheme = "ftp"
|
||||||
}
|
}
|
||||||
|
|
||||||
local function parse(u)
|
local function genericform(u)
|
||||||
local t = socket.try(url.parse(u, default))
|
local t = socket.try(url.parse(u, default))
|
||||||
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
|
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
|
||||||
socket.try(t.host, "missing hostname")
|
socket.try(t.host, "missing hostname")
|
||||||
@@ -229,13 +265,15 @@ local function parse(u)
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
_M.genericform = genericform
|
||||||
|
|
||||||
local function sput(u, body)
|
local function sput(u, body)
|
||||||
local putt = parse(u)
|
local putt = genericform(u)
|
||||||
putt.source = ltn12.source.string(body)
|
putt.source = ltn12.source.string(body)
|
||||||
return tput(putt)
|
return tput(putt)
|
||||||
end
|
end
|
||||||
|
|
||||||
put = socket.protect(function(putt, body)
|
_M.put = socket.protect(function(putt, body)
|
||||||
if base.type(putt) == "string" then return sput(putt, body)
|
if base.type(putt) == "string" then return sput(putt, body)
|
||||||
else return tput(putt) end
|
else return tput(putt) end
|
||||||
end)
|
end)
|
||||||
@@ -243,39 +281,49 @@ end)
|
|||||||
local function tget(gett)
|
local function tget(gett)
|
||||||
gett = override(gett)
|
gett = override(gett)
|
||||||
socket.try(gett.host, "missing hostname")
|
socket.try(gett.host, "missing hostname")
|
||||||
local f = open(gett.host, gett.port, gett.create)
|
local f = _M.open(gett.host, gett.port, gett.create)
|
||||||
f:greet()
|
f:greet()
|
||||||
f:login(gett.user, gett.password)
|
f:login(gett.user, gett.password)
|
||||||
if gett.type then f:type(gett.type) end
|
if gett.type then f:type(gett.type) end
|
||||||
f:pasv()
|
f:epsv()
|
||||||
f:receive(gett)
|
f:receive(gett)
|
||||||
f:quit()
|
f:quit()
|
||||||
return f:close()
|
return f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sget(u)
|
local function sget(u)
|
||||||
local gett = parse(u)
|
local gett = genericform(u)
|
||||||
local t = {}
|
local t = {}
|
||||||
gett.sink = ltn12.sink.table(t)
|
gett.sink = ltn12.sink.table(t)
|
||||||
tget(gett)
|
tget(gett)
|
||||||
return table.concat(t)
|
return table.concat(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
command = socket.protect(function(cmdt)
|
_M.command = socket.protect(function(cmdt)
|
||||||
cmdt = override(cmdt)
|
cmdt = override(cmdt)
|
||||||
socket.try(cmdt.host, "missing hostname")
|
socket.try(cmdt.host, "missing hostname")
|
||||||
socket.try(cmdt.command, "missing command")
|
socket.try(cmdt.command, "missing command")
|
||||||
local f = open(cmdt.host, cmdt.port, cmdt.create)
|
local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
|
||||||
f:greet()
|
f:greet()
|
||||||
f:login(cmdt.user, cmdt.password)
|
f:login(cmdt.user, cmdt.password)
|
||||||
f.try(f.tp:command(cmdt.command, cmdt.argument))
|
if type(cmdt.command) == "table" then
|
||||||
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
|
local argument = cmdt.argument or {}
|
||||||
|
local check = cmdt.check or {}
|
||||||
|
for i,cmd in ipairs(cmdt.command) do
|
||||||
|
f.try(f.tp:command(cmd, argument[i]))
|
||||||
|
if check[i] then f.try(f.tp:check(check[i])) end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
f.try(f.tp:command(cmdt.command, cmdt.argument))
|
||||||
|
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
|
||||||
|
end
|
||||||
f:quit()
|
f:quit()
|
||||||
return f:close()
|
return f:close()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
get = socket.protect(function(gett)
|
_M.get = socket.protect(function(gett)
|
||||||
if base.type(gett) == "string" then return sget(gett)
|
if base.type(gett) == "string" then return sget(gett)
|
||||||
else return tget(gett) end
|
else return tget(gett) end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
104
src/headers.lua
Normal file
104
src/headers.lua
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Canonic header field capitalization
|
||||||
|
-- LuaSocket toolkit.
|
||||||
|
-- Author: Diego Nehab
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
local socket = require("socket")
|
||||||
|
socket.headers = {}
|
||||||
|
local _M = socket.headers
|
||||||
|
|
||||||
|
_M.canonic = {
|
||||||
|
["accept"] = "Accept",
|
||||||
|
["accept-charset"] = "Accept-Charset",
|
||||||
|
["accept-encoding"] = "Accept-Encoding",
|
||||||
|
["accept-language"] = "Accept-Language",
|
||||||
|
["accept-ranges"] = "Accept-Ranges",
|
||||||
|
["action"] = "Action",
|
||||||
|
["alternate-recipient"] = "Alternate-Recipient",
|
||||||
|
["age"] = "Age",
|
||||||
|
["allow"] = "Allow",
|
||||||
|
["arrival-date"] = "Arrival-Date",
|
||||||
|
["authorization"] = "Authorization",
|
||||||
|
["bcc"] = "Bcc",
|
||||||
|
["cache-control"] = "Cache-Control",
|
||||||
|
["cc"] = "Cc",
|
||||||
|
["comments"] = "Comments",
|
||||||
|
["connection"] = "Connection",
|
||||||
|
["content-description"] = "Content-Description",
|
||||||
|
["content-disposition"] = "Content-Disposition",
|
||||||
|
["content-encoding"] = "Content-Encoding",
|
||||||
|
["content-id"] = "Content-ID",
|
||||||
|
["content-language"] = "Content-Language",
|
||||||
|
["content-length"] = "Content-Length",
|
||||||
|
["content-location"] = "Content-Location",
|
||||||
|
["content-md5"] = "Content-MD5",
|
||||||
|
["content-range"] = "Content-Range",
|
||||||
|
["content-transfer-encoding"] = "Content-Transfer-Encoding",
|
||||||
|
["content-type"] = "Content-Type",
|
||||||
|
["cookie"] = "Cookie",
|
||||||
|
["date"] = "Date",
|
||||||
|
["diagnostic-code"] = "Diagnostic-Code",
|
||||||
|
["dsn-gateway"] = "DSN-Gateway",
|
||||||
|
["etag"] = "ETag",
|
||||||
|
["expect"] = "Expect",
|
||||||
|
["expires"] = "Expires",
|
||||||
|
["final-log-id"] = "Final-Log-ID",
|
||||||
|
["final-recipient"] = "Final-Recipient",
|
||||||
|
["from"] = "From",
|
||||||
|
["host"] = "Host",
|
||||||
|
["if-match"] = "If-Match",
|
||||||
|
["if-modified-since"] = "If-Modified-Since",
|
||||||
|
["if-none-match"] = "If-None-Match",
|
||||||
|
["if-range"] = "If-Range",
|
||||||
|
["if-unmodified-since"] = "If-Unmodified-Since",
|
||||||
|
["in-reply-to"] = "In-Reply-To",
|
||||||
|
["keywords"] = "Keywords",
|
||||||
|
["last-attempt-date"] = "Last-Attempt-Date",
|
||||||
|
["last-modified"] = "Last-Modified",
|
||||||
|
["location"] = "Location",
|
||||||
|
["max-forwards"] = "Max-Forwards",
|
||||||
|
["message-id"] = "Message-ID",
|
||||||
|
["mime-version"] = "MIME-Version",
|
||||||
|
["original-envelope-id"] = "Original-Envelope-ID",
|
||||||
|
["original-recipient"] = "Original-Recipient",
|
||||||
|
["pragma"] = "Pragma",
|
||||||
|
["proxy-authenticate"] = "Proxy-Authenticate",
|
||||||
|
["proxy-authorization"] = "Proxy-Authorization",
|
||||||
|
["range"] = "Range",
|
||||||
|
["received"] = "Received",
|
||||||
|
["received-from-mta"] = "Received-From-MTA",
|
||||||
|
["references"] = "References",
|
||||||
|
["referer"] = "Referer",
|
||||||
|
["remote-mta"] = "Remote-MTA",
|
||||||
|
["reply-to"] = "Reply-To",
|
||||||
|
["reporting-mta"] = "Reporting-MTA",
|
||||||
|
["resent-bcc"] = "Resent-Bcc",
|
||||||
|
["resent-cc"] = "Resent-Cc",
|
||||||
|
["resent-date"] = "Resent-Date",
|
||||||
|
["resent-from"] = "Resent-From",
|
||||||
|
["resent-message-id"] = "Resent-Message-ID",
|
||||||
|
["resent-reply-to"] = "Resent-Reply-To",
|
||||||
|
["resent-sender"] = "Resent-Sender",
|
||||||
|
["resent-to"] = "Resent-To",
|
||||||
|
["retry-after"] = "Retry-After",
|
||||||
|
["return-path"] = "Return-Path",
|
||||||
|
["sender"] = "Sender",
|
||||||
|
["server"] = "Server",
|
||||||
|
["smtp-remote-recipient"] = "SMTP-Remote-Recipient",
|
||||||
|
["status"] = "Status",
|
||||||
|
["subject"] = "Subject",
|
||||||
|
["te"] = "TE",
|
||||||
|
["to"] = "To",
|
||||||
|
["trailer"] = "Trailer",
|
||||||
|
["transfer-encoding"] = "Transfer-Encoding",
|
||||||
|
["upgrade"] = "Upgrade",
|
||||||
|
["user-agent"] = "User-Agent",
|
||||||
|
["vary"] = "Vary",
|
||||||
|
["via"] = "Via",
|
||||||
|
["warning"] = "Warning",
|
||||||
|
["will-retry-until"] = "Will-Retry-Until",
|
||||||
|
["www-authenticate"] = "WWW-Authenticate",
|
||||||
|
["x-mailer"] = "X-Mailer",
|
||||||
|
}
|
||||||
|
|
||||||
|
return _M
|
||||||
196
src/http.lua
196
src/http.lua
@@ -2,7 +2,6 @@
|
|||||||
-- HTTP/1.1 client support for the Lua language.
|
-- HTTP/1.1 client support for the Lua language.
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -13,20 +12,38 @@ local url = require("socket.url")
|
|||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
local string = require("string")
|
local string = require("string")
|
||||||
|
local headers = require("socket.headers")
|
||||||
local base = _G
|
local base = _G
|
||||||
local table = require("table")
|
local table = require("table")
|
||||||
module("socket.http")
|
socket.http = {}
|
||||||
|
local _M = socket.http
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Program constants
|
-- Program constants
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- connection timeout in seconds
|
-- connection timeout in seconds
|
||||||
TIMEOUT = 60
|
_M.TIMEOUT = 60
|
||||||
-- default port for document retrieval
|
|
||||||
PORT = 80
|
|
||||||
-- user agent field sent in request
|
-- user agent field sent in request
|
||||||
USERAGENT = socket._VERSION
|
_M.USERAGENT = socket._VERSION
|
||||||
|
|
||||||
|
-- supported schemes and their particulars
|
||||||
|
local SCHEMES = {
|
||||||
|
http = {
|
||||||
|
port = 80
|
||||||
|
, create = function(t)
|
||||||
|
return socket.tcp end }
|
||||||
|
, https = {
|
||||||
|
port = 443
|
||||||
|
, create = function(t)
|
||||||
|
local https = assert(
|
||||||
|
require("ssl.https"), 'LuaSocket: LuaSec not found')
|
||||||
|
local tcp = assert(
|
||||||
|
https.tcp, 'LuaSocket: Function tcp() not available from LuaSec')
|
||||||
|
return tcp(t) end }}
|
||||||
|
|
||||||
|
-- default scheme and port for document retrieval
|
||||||
|
local SCHEME = 'http'
|
||||||
|
local PORT = SCHEMES[SCHEME].port
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Reads MIME headers from a connection, unfolding where needed
|
-- Reads MIME headers from a connection, unfolding where needed
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -105,15 +122,15 @@ end
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local metat = { __index = {} }
|
local metat = { __index = {} }
|
||||||
|
|
||||||
function open(host, port, create)
|
function _M.open(host, port, create)
|
||||||
-- create socket with user connect function, or with default
|
-- create socket with user connect function, or with default
|
||||||
local c = socket.try((create or socket.tcp)())
|
local c = socket.try(create())
|
||||||
local h = base.setmetatable({ c = c }, metat)
|
local h = base.setmetatable({ c = c }, metat)
|
||||||
-- create finalized try
|
-- create finalized try
|
||||||
h.try = socket.newtry(function() h:close() end)
|
h.try = socket.newtry(function() h:close() end)
|
||||||
-- set timeout before connecting
|
-- set timeout before connecting
|
||||||
h.try(c:settimeout(TIMEOUT))
|
h.try(c:settimeout(_M.TIMEOUT))
|
||||||
h.try(c:connect(host, port or PORT))
|
h.try(c:connect(host, port))
|
||||||
-- here everything worked
|
-- here everything worked
|
||||||
return h
|
return h
|
||||||
end
|
end
|
||||||
@@ -123,10 +140,11 @@ function metat.__index:sendrequestline(method, uri)
|
|||||||
return self.try(self.c:send(reqline))
|
return self.try(self.c:send(reqline))
|
||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:sendheaders(headers)
|
function metat.__index:sendheaders(tosend)
|
||||||
|
local canonic = headers.canonic
|
||||||
local h = "\r\n"
|
local h = "\r\n"
|
||||||
for i, v in base.pairs(headers) do
|
for f, v in base.pairs(tosend) do
|
||||||
h = i .. ": " .. v .. "\r\n" .. h
|
h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
|
||||||
end
|
end
|
||||||
self.try(self.c:send(h))
|
self.try(self.c:send(h))
|
||||||
return 1
|
return 1
|
||||||
@@ -142,7 +160,17 @@ function metat.__index:sendbody(headers, source, step)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:receivestatusline()
|
function metat.__index:receivestatusline()
|
||||||
local status = self.try(self.c:receive())
|
local status,ec = self.try(self.c:receive(5))
|
||||||
|
-- identify HTTP/0.9 responses, which do not contain a status line
|
||||||
|
-- this is just a heuristic, but is what the RFC recommends
|
||||||
|
if status ~= "HTTP/" then
|
||||||
|
if ec == "timeout" then
|
||||||
|
return 408
|
||||||
|
end
|
||||||
|
return nil, status
|
||||||
|
end
|
||||||
|
-- otherwise proceed reading a status line
|
||||||
|
status = self.try(self.c:receive("*l", status))
|
||||||
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
||||||
return self.try(base.tonumber(code), status)
|
return self.try(base.tonumber(code), status)
|
||||||
end
|
end
|
||||||
@@ -163,6 +191,12 @@ function metat.__index:receivebody(headers, sink, step)
|
|||||||
sink, step))
|
sink, step))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function metat.__index:receive09body(status, sink, step)
|
||||||
|
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
|
||||||
|
source(status)
|
||||||
|
return self.try(ltn12.pump.all(source, sink, step))
|
||||||
|
end
|
||||||
|
|
||||||
function metat.__index:close()
|
function metat.__index:close()
|
||||||
return self.c:close()
|
return self.c:close()
|
||||||
end
|
end
|
||||||
@@ -173,7 +207,7 @@ end
|
|||||||
local function adjusturi(reqt)
|
local function adjusturi(reqt)
|
||||||
local u = reqt
|
local u = reqt
|
||||||
-- if there is a proxy, we need the full url. otherwise, just a part.
|
-- if there is a proxy, we need the full url. otherwise, just a part.
|
||||||
if not reqt.proxy and not PROXY then
|
if not reqt.proxy and not _M.PROXY then
|
||||||
u = {
|
u = {
|
||||||
path = socket.try(reqt.path, "invalid path 'nil'"),
|
path = socket.try(reqt.path, "invalid path 'nil'"),
|
||||||
params = reqt.params,
|
params = reqt.params,
|
||||||
@@ -185,7 +219,7 @@ local function adjusturi(reqt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function adjustproxy(reqt)
|
local function adjustproxy(reqt)
|
||||||
local proxy = reqt.proxy or PROXY
|
local proxy = reqt.proxy or _M.PROXY
|
||||||
if proxy then
|
if proxy then
|
||||||
proxy = url.parse(proxy)
|
proxy = url.parse(proxy)
|
||||||
return proxy.host, proxy.port or 3128
|
return proxy.host, proxy.port or 3128
|
||||||
@@ -196,16 +230,30 @@ end
|
|||||||
|
|
||||||
local function adjustheaders(reqt)
|
local function adjustheaders(reqt)
|
||||||
-- default headers
|
-- default headers
|
||||||
|
local host = reqt.host
|
||||||
|
local port = tostring(reqt.port)
|
||||||
|
if port ~= tostring(SCHEMES[reqt.scheme].port) then
|
||||||
|
host = host .. ':' .. port end
|
||||||
local lower = {
|
local lower = {
|
||||||
["user-agent"] = USERAGENT,
|
["user-agent"] = _M.USERAGENT,
|
||||||
["host"] = reqt.host,
|
["host"] = host,
|
||||||
["connection"] = "close, TE",
|
["connection"] = "close, TE",
|
||||||
["te"] = "trailers"
|
["te"] = "trailers"
|
||||||
}
|
}
|
||||||
-- if we have authentication information, pass it along
|
-- if we have authentication information, pass it along
|
||||||
if reqt.user and reqt.password then
|
if reqt.user and reqt.password then
|
||||||
lower["authorization"] =
|
lower["authorization"] =
|
||||||
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
|
"Basic " .. (mime.b64(reqt.user .. ":" ..
|
||||||
|
url.unescape(reqt.password)))
|
||||||
|
end
|
||||||
|
-- if we have proxy authentication information, pass it along
|
||||||
|
local proxy = reqt.proxy or _M.PROXY
|
||||||
|
if proxy then
|
||||||
|
proxy = url.parse(proxy)
|
||||||
|
if proxy.user and proxy.password then
|
||||||
|
lower["proxy-authorization"] =
|
||||||
|
"Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- override with user headers
|
-- override with user headers
|
||||||
for i,v in base.pairs(reqt.headers or lower) do
|
for i,v in base.pairs(reqt.headers or lower) do
|
||||||
@@ -216,10 +264,8 @@ end
|
|||||||
|
|
||||||
-- default url parts
|
-- default url parts
|
||||||
local default = {
|
local default = {
|
||||||
host = "",
|
path ="/"
|
||||||
port = PORT,
|
, scheme = "http"
|
||||||
path ="/",
|
|
||||||
scheme = "http"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local function adjustrequest(reqt)
|
local function adjustrequest(reqt)
|
||||||
@@ -227,25 +273,39 @@ local function adjustrequest(reqt)
|
|||||||
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
||||||
-- explicit components override url
|
-- explicit components override url
|
||||||
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
||||||
if nreqt.port == "" then nreqt.port = 80 end
|
-- default to scheme particulars
|
||||||
socket.try(nreqt.host and nreqt.host ~= "",
|
local schemedefs, host, port, method
|
||||||
"invalid host '" .. base.tostring(nreqt.host) .. "'")
|
= SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method
|
||||||
|
if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end
|
||||||
|
if not (port and port ~= '') then nreqt.port = schemedefs.port end
|
||||||
|
if not (method and method ~= '') then nreqt.method = 'GET' end
|
||||||
|
if not (host and host ~= "") then
|
||||||
|
socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
|
||||||
|
end
|
||||||
-- compute uri if user hasn't overriden
|
-- compute uri if user hasn't overriden
|
||||||
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
||||||
-- ajust host and port if there is a proxy
|
|
||||||
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
|
||||||
-- adjust headers in request
|
-- adjust headers in request
|
||||||
nreqt.headers = adjustheaders(nreqt)
|
nreqt.headers = adjustheaders(nreqt)
|
||||||
|
-- ajust host and port if there is a proxy
|
||||||
|
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
||||||
return nreqt
|
return nreqt
|
||||||
end
|
end
|
||||||
|
|
||||||
local function shouldredirect(reqt, code, headers)
|
local function shouldredirect(reqt, code, headers)
|
||||||
return headers.location and
|
local location = headers.location
|
||||||
string.gsub(headers.location, "%s", "") ~= "" and
|
if not location then return false end
|
||||||
(reqt.redirect ~= false) and
|
location = string.gsub(location, "%s", "")
|
||||||
(code == 301 or code == 302) and
|
if location == "" then return false end
|
||||||
|
local scheme = url.parse(location).scheme
|
||||||
|
if scheme and (not SCHEMES[scheme]) then return false end
|
||||||
|
-- avoid https downgrades
|
||||||
|
if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end
|
||||||
|
return (reqt.redirect ~= false) and
|
||||||
|
(code == 301 or code == 302 or code == 303 or code == 307) and
|
||||||
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
||||||
and (not reqt.nredirects or reqt.nredirects < 5)
|
and ((false == reqt.maxredirects)
|
||||||
|
or ((reqt.nredirects or 0)
|
||||||
|
< (reqt.maxredirects or 5)))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function shouldreceivebody(reqt, code)
|
local function shouldreceivebody(reqt, code)
|
||||||
@@ -258,44 +318,60 @@ end
|
|||||||
-- forward declarations
|
-- forward declarations
|
||||||
local trequest, tredirect
|
local trequest, tredirect
|
||||||
|
|
||||||
function tredirect(reqt, location)
|
--[[local]] function tredirect(reqt, location)
|
||||||
|
-- the RFC says the redirect URL has to be absolute, but some
|
||||||
|
-- servers do not respect that
|
||||||
|
local newurl = url.absolute(reqt.url, location)
|
||||||
|
-- if switching schemes, reset port and create function
|
||||||
|
if url.parse(newurl).scheme ~= reqt.scheme then
|
||||||
|
reqt.port = nil
|
||||||
|
reqt.create = nil end
|
||||||
|
-- make new request
|
||||||
local result, code, headers, status = trequest {
|
local result, code, headers, status = trequest {
|
||||||
-- the RFC says the redirect URL has to be absolute, but some
|
url = newurl,
|
||||||
-- servers do not respect that
|
|
||||||
url = url.absolute(reqt.url, location),
|
|
||||||
source = reqt.source,
|
source = reqt.source,
|
||||||
sink = reqt.sink,
|
sink = reqt.sink,
|
||||||
headers = reqt.headers,
|
headers = reqt.headers,
|
||||||
proxy = reqt.proxy,
|
proxy = reqt.proxy,
|
||||||
|
maxredirects = reqt.maxredirects,
|
||||||
nredirects = (reqt.nredirects or 0) + 1,
|
nredirects = (reqt.nredirects or 0) + 1,
|
||||||
create = reqt.create
|
create = reqt.create
|
||||||
}
|
}
|
||||||
-- pass location header back as a hint we redirected
|
-- pass location header back as a hint we redirected
|
||||||
|
headers = headers or {}
|
||||||
headers.location = headers.location or location
|
headers.location = headers.location or location
|
||||||
return result, code, headers, status
|
return result, code, headers, status
|
||||||
end
|
end
|
||||||
|
|
||||||
function trequest(reqt)
|
--[[local]] function trequest(reqt)
|
||||||
-- we loop until we get what we want, or
|
-- we loop until we get what we want, or
|
||||||
-- until we are sure there is no way to get it
|
-- until we are sure there is no way to get it
|
||||||
local nreqt = adjustrequest(reqt)
|
local nreqt = adjustrequest(reqt)
|
||||||
local h = open(nreqt.host, nreqt.port, nreqt.create)
|
local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
|
||||||
-- send request line and headers
|
-- send request line and headers
|
||||||
h:sendrequestline(nreqt.method, nreqt.uri)
|
h:sendrequestline(nreqt.method, nreqt.uri)
|
||||||
h:sendheaders(nreqt.headers)
|
h:sendheaders(nreqt.headers)
|
||||||
local code = 100
|
-- if there is a body, send it
|
||||||
local headers, status
|
|
||||||
-- if there is a body, check for server status
|
|
||||||
if nreqt.source then
|
if nreqt.source then
|
||||||
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
|
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
|
||||||
end
|
end
|
||||||
|
local code, status = h:receivestatusline()
|
||||||
|
-- if it is an HTTP/0.9 server, simply get the body and we are done
|
||||||
|
if not code then
|
||||||
|
h:receive09body(status, nreqt.sink, nreqt.step)
|
||||||
|
return 1, 200
|
||||||
|
elseif code == 408 then
|
||||||
|
return 1, code
|
||||||
|
end
|
||||||
|
local headers
|
||||||
-- ignore any 100-continue messages
|
-- ignore any 100-continue messages
|
||||||
while code == 100 do
|
while code == 100 do
|
||||||
code, status = h:receivestatusline()
|
|
||||||
headers = h:receiveheaders()
|
headers = h:receiveheaders()
|
||||||
|
code, status = h:receivestatusline()
|
||||||
end
|
end
|
||||||
|
headers = h:receiveheaders()
|
||||||
-- at this point we should have a honest reply from the server
|
-- at this point we should have a honest reply from the server
|
||||||
-- we can't redirect if we already used the source, so we report the error
|
-- we can't redirect if we already used the source, so we report the error
|
||||||
if shouldredirect(nreqt, code, headers) and not nreqt.source then
|
if shouldredirect(nreqt, code, headers) and not nreqt.source then
|
||||||
h:close()
|
h:close()
|
||||||
return tredirect(reqt, headers.location)
|
return tredirect(reqt, headers.location)
|
||||||
@@ -308,11 +384,13 @@ function trequest(reqt)
|
|||||||
return 1, code, headers, status
|
return 1, code, headers, status
|
||||||
end
|
end
|
||||||
|
|
||||||
local function srequest(u, b)
|
-- turns an url and a body into a generic request
|
||||||
|
local function genericform(u, b)
|
||||||
local t = {}
|
local t = {}
|
||||||
local reqt = {
|
local reqt = {
|
||||||
url = u,
|
url = u,
|
||||||
sink = ltn12.sink.table(t)
|
sink = ltn12.sink.table(t),
|
||||||
|
target = t
|
||||||
}
|
}
|
||||||
if b then
|
if b then
|
||||||
reqt.source = ltn12.source.string(b)
|
reqt.source = ltn12.source.string(b)
|
||||||
@@ -322,11 +400,21 @@ local function srequest(u, b)
|
|||||||
}
|
}
|
||||||
reqt.method = "POST"
|
reqt.method = "POST"
|
||||||
end
|
end
|
||||||
local code, headers, status = socket.skip(1, trequest(reqt))
|
return reqt
|
||||||
return table.concat(t), code, headers, status
|
|
||||||
end
|
end
|
||||||
|
|
||||||
request = socket.protect(function(reqt, body)
|
_M.genericform = genericform
|
||||||
|
|
||||||
|
local function srequest(u, b)
|
||||||
|
local reqt = genericform(u, b)
|
||||||
|
local _, code, headers, status = trequest(reqt)
|
||||||
|
return table.concat(reqt.target), code, headers, status
|
||||||
|
end
|
||||||
|
|
||||||
|
_M.request = socket.protect(function(reqt, body)
|
||||||
if base.type(reqt) == "string" then return srequest(reqt, body)
|
if base.type(reqt) == "string" then return srequest(reqt, body)
|
||||||
else return trequest(reqt) end
|
else return trequest(reqt) end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
_M.schemes = SCHEMES
|
||||||
|
return _M
|
||||||
|
|||||||
414
src/inet.c
414
src/inet.c
@@ -1,36 +1,34 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internet domain functions
|
* Internet domain functions
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <stdio.h>
|
#include "luasocket.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "inet.h"
|
#include "inet.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal function prototypes.
|
* Internal function prototypes.
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int inet_global_toip(lua_State *L);
|
static int inet_global_toip(lua_State *L);
|
||||||
|
static int inet_global_getaddrinfo(lua_State *L);
|
||||||
static int inet_global_tohostname(lua_State *L);
|
static int inet_global_tohostname(lua_State *L);
|
||||||
|
static int inet_global_getnameinfo(lua_State *L);
|
||||||
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
||||||
static int inet_global_gethostname(lua_State *L);
|
static int inet_global_gethostname(lua_State *L);
|
||||||
|
|
||||||
/* DNS functions */
|
/* DNS functions */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{ "toip", inet_global_toip },
|
{ "toip", inet_global_toip},
|
||||||
{ "tohostname", inet_global_tohostname },
|
{ "getaddrinfo", inet_global_getaddrinfo},
|
||||||
|
{ "tohostname", inet_global_tohostname},
|
||||||
|
{ "getnameinfo", inet_global_getnameinfo},
|
||||||
{ "gethostname", inet_global_gethostname},
|
{ "gethostname", inet_global_gethostname},
|
||||||
{ NULL, NULL}
|
{ NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* Exported functions
|
|
||||||
\*=========================================================================*/
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -38,7 +36,7 @@ int inet_open(lua_State *L)
|
|||||||
{
|
{
|
||||||
lua_pushstring(L, "dns");
|
lua_pushstring(L, "dns");
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
luaL_openlib(L, NULL, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
lua_settable(L, -3);
|
lua_settable(L, -3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -54,7 +52,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
|
|||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
if (inet_aton(address, &addr))
|
if (inet_aton(address, &addr))
|
||||||
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
|
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
|
||||||
else
|
else
|
||||||
return socket_gethostbyname(address, hp);
|
return socket_gethostbyname(address, hp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +62,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int inet_global_tohostname(lua_State *L) {
|
static int inet_global_tohostname(lua_State *L) {
|
||||||
const char *address = luaL_checkstring(L, 1);
|
const char *address = luaL_checkstring(L, 1);
|
||||||
struct hostent *hp = NULL;
|
struct hostent *hp = NULL;
|
||||||
int err = inet_gethost(address, &hp);
|
int err = inet_gethost(address, &hp);
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@@ -76,6 +74,50 @@ static int inet_global_tohostname(lua_State *L) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int inet_global_getnameinfo(lua_State *L) {
|
||||||
|
char hbuf[NI_MAXHOST];
|
||||||
|
char sbuf[NI_MAXSERV];
|
||||||
|
int i, ret;
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *resolved, *iter;
|
||||||
|
const char *host = luaL_optstring(L, 1, NULL);
|
||||||
|
const char *serv = luaL_optstring(L, 2, NULL);
|
||||||
|
|
||||||
|
if (!(host || serv))
|
||||||
|
luaL_error(L, "host and serv cannot be both nil");
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
|
||||||
|
ret = getaddrinfo(host, serv, &hints, &resolved);
|
||||||
|
if (ret != 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, socket_gaistrerror(ret));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
|
||||||
|
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
|
||||||
|
hbuf, host? (socklen_t) sizeof(hbuf): 0,
|
||||||
|
sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
|
||||||
|
if (host) {
|
||||||
|
lua_pushnumber(L, i);
|
||||||
|
lua_pushstring(L, hbuf);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(resolved);
|
||||||
|
|
||||||
|
if (serv) {
|
||||||
|
lua_pushstring(L, sbuf);
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Returns all information provided by the resolver given a host name
|
* Returns all information provided by the resolver given a host name
|
||||||
* or ip address
|
* or ip address
|
||||||
@@ -83,7 +125,7 @@ static int inet_global_tohostname(lua_State *L) {
|
|||||||
static int inet_global_toip(lua_State *L)
|
static int inet_global_toip(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *address = luaL_checkstring(L, 1);
|
const char *address = luaL_checkstring(L, 1);
|
||||||
struct hostent *hp = NULL;
|
struct hostent *hp = NULL;
|
||||||
int err = inet_gethost(address, &hp);
|
int err = inet_gethost(address, &hp);
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@@ -95,6 +137,81 @@ static int inet_global_toip(lua_State *L)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int inet_optfamily(lua_State* L, int narg, const char* def)
|
||||||
|
{
|
||||||
|
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
|
||||||
|
static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
|
||||||
|
|
||||||
|
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||||
|
}
|
||||||
|
|
||||||
|
int inet_optsocktype(lua_State* L, int narg, const char* def)
|
||||||
|
{
|
||||||
|
static const char* optname[] = { "stream", "dgram", NULL };
|
||||||
|
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
|
||||||
|
|
||||||
|
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int inet_global_getaddrinfo(lua_State *L)
|
||||||
|
{
|
||||||
|
const char *hostname = luaL_checkstring(L, 1);
|
||||||
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||||
|
struct addrinfo hints;
|
||||||
|
int i = 1, ret = 0;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
|
||||||
|
if (ret != 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, socket_gaistrerror(ret));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_newtable(L);
|
||||||
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||||
|
char hbuf[NI_MAXHOST];
|
||||||
|
ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
|
||||||
|
hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
|
||||||
|
if (ret){
|
||||||
|
freeaddrinfo(resolved);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, socket_gaistrerror(ret));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushnumber(L, i);
|
||||||
|
lua_newtable(L);
|
||||||
|
switch (iterator->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
lua_pushliteral(L, "family");
|
||||||
|
lua_pushliteral(L, "inet");
|
||||||
|
lua_settable(L, -3);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
lua_pushliteral(L, "family");
|
||||||
|
lua_pushliteral(L, "inet6");
|
||||||
|
lua_settable(L, -3);
|
||||||
|
break;
|
||||||
|
case AF_UNSPEC:
|
||||||
|
lua_pushliteral(L, "family");
|
||||||
|
lua_pushliteral(L, "unspec");
|
||||||
|
lua_settable(L, -3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lua_pushliteral(L, "family");
|
||||||
|
lua_pushliteral(L, "unknown");
|
||||||
|
lua_settable(L, -3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lua_pushliteral(L, "addr");
|
||||||
|
lua_pushstring(L, hbuf);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
freeaddrinfo(resolved);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Gets the host name
|
* Gets the host name
|
||||||
@@ -105,7 +222,7 @@ static int inet_global_gethostname(lua_State *L)
|
|||||||
name[256] = '\0';
|
name[256] = '\0';
|
||||||
if (gethostname(name, 256) < 0) {
|
if (gethostname(name, 256) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "gethostname failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
lua_pushstring(L, name);
|
lua_pushstring(L, name);
|
||||||
@@ -113,43 +230,74 @@ static int inet_global_gethostname(lua_State *L)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Lua methods
|
* Lua methods
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Retrieves socket peer name
|
* Retrieves socket peer name
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int inet_meth_getpeername(lua_State *L, p_socket ps)
|
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
||||||
{
|
{
|
||||||
struct sockaddr_in peer;
|
int err;
|
||||||
|
struct sockaddr_storage peer;
|
||||||
socklen_t peer_len = sizeof(peer);
|
socklen_t peer_len = sizeof(peer);
|
||||||
|
char name[INET6_ADDRSTRLEN];
|
||||||
|
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
|
||||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getpeername failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
} else {
|
return 2;
|
||||||
lua_pushstring(L, inet_ntoa(peer.sin_addr));
|
|
||||||
lua_pushnumber(L, ntohs(peer.sin_port));
|
|
||||||
}
|
}
|
||||||
return 2;
|
err = getnameinfo((struct sockaddr *) &peer, peer_len,
|
||||||
|
name, INET6_ADDRSTRLEN,
|
||||||
|
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, gai_strerror(err));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushstring(L, name);
|
||||||
|
lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET: lua_pushliteral(L, "inet"); break;
|
||||||
|
case AF_INET6: lua_pushliteral(L, "inet6"); break;
|
||||||
|
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
|
||||||
|
default: lua_pushliteral(L, "unknown"); break;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Retrieves socket local name
|
* Retrieves socket local name
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int inet_meth_getsockname(lua_State *L, p_socket ps)
|
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
||||||
{
|
{
|
||||||
struct sockaddr_in local;
|
int err;
|
||||||
socklen_t local_len = sizeof(local);
|
struct sockaddr_storage peer;
|
||||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
socklen_t peer_len = sizeof(peer);
|
||||||
|
char name[INET6_ADDRSTRLEN];
|
||||||
|
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
|
||||||
|
if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getsockname failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
} else {
|
return 2;
|
||||||
lua_pushstring(L, inet_ntoa(local.sin_addr));
|
|
||||||
lua_pushnumber(L, ntohs(local.sin_port));
|
|
||||||
}
|
}
|
||||||
return 2;
|
err=getnameinfo((struct sockaddr *)&peer, peer_len,
|
||||||
|
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, gai_strerror(err));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushstring(L, name);
|
||||||
|
lua_pushstring(L, port);
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET: lua_pushliteral(L, "inet"); break;
|
||||||
|
case AF_INET6: lua_pushliteral(L, "inet6"); break;
|
||||||
|
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
|
||||||
|
default: lua_pushliteral(L, "unknown"); break;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
@@ -198,65 +346,151 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to create a new inet socket
|
* Tries to create a new inet socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_trycreate(p_socket ps, int type) {
|
const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
|
||||||
return socket_strerror(socket_create(ps, AF_INET, type, 0));
|
const char *err = socket_strerror(socket_create(ps, family, type, protocol));
|
||||||
|
if (err == NULL && family == AF_INET6) {
|
||||||
|
int yes = 1;
|
||||||
|
setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* "Disconnects" a DGRAM socket
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
|
||||||
|
{
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
memset((char *) &sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_UNSPEC;
|
||||||
|
sin.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
return socket_strerror(socket_connect(ps, (SA *) &sin,
|
||||||
|
sizeof(sin), tm));
|
||||||
|
}
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
struct in6_addr addrany = IN6ADDR_ANY_INIT;
|
||||||
|
memset((char *) &sin6, 0, sizeof(sin6));
|
||||||
|
sin6.sin6_family = AF_UNSPEC;
|
||||||
|
sin6.sin6_addr = addrany;
|
||||||
|
return socket_strerror(socket_connect(ps, (SA *) &sin6,
|
||||||
|
sizeof(sin6), tm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to connect to remote address (address, port)
|
* Tries to connect to remote address (address, port)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
|
||||||
unsigned short port, p_timeout tm)
|
const char *serv, p_timeout tm, struct addrinfo *connecthints)
|
||||||
{
|
{
|
||||||
struct sockaddr_in remote;
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||||
int err;
|
const char *err = NULL;
|
||||||
memset(&remote, 0, sizeof(remote));
|
int current_family = *family;
|
||||||
remote.sin_family = AF_INET;
|
/* try resolving */
|
||||||
remote.sin_port = htons(port);
|
err = socket_gaistrerror(getaddrinfo(address, serv,
|
||||||
if (strcmp(address, "*")) {
|
connecthints, &resolved));
|
||||||
if (!inet_aton(address, &remote.sin_addr)) {
|
if (err != NULL) {
|
||||||
struct hostent *hp = NULL;
|
if (resolved) freeaddrinfo(resolved);
|
||||||
struct in_addr **addr;
|
return err;
|
||||||
err = socket_gethostbyname(address, &hp);
|
}
|
||||||
if (err != IO_DONE) return socket_hoststrerror(err);
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||||
addr = (struct in_addr **) hp->h_addr_list;
|
timeout_markstart(tm);
|
||||||
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
|
/* create new socket if necessary. if there was no
|
||||||
|
* bind, we need to create one for every new family
|
||||||
|
* that shows up while iterating. if there was a
|
||||||
|
* bind, all families will be the same and we will
|
||||||
|
* not enter this branch. */
|
||||||
|
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
|
||||||
|
socket_destroy(ps);
|
||||||
|
err = inet_trycreate(ps, iterator->ai_family,
|
||||||
|
iterator->ai_socktype, iterator->ai_protocol);
|
||||||
|
if (err) continue;
|
||||||
|
current_family = iterator->ai_family;
|
||||||
|
/* set non-blocking before connect */
|
||||||
|
socket_setnonblocking(ps);
|
||||||
}
|
}
|
||||||
} else remote.sin_family = AF_UNSPEC;
|
/* try connecting to remote address */
|
||||||
err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
|
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
|
||||||
return socket_strerror(err);
|
(socklen_t) iterator->ai_addrlen, tm));
|
||||||
|
/* if success or timeout is zero, break out of loop */
|
||||||
|
if (err == NULL || timeout_iszero(tm)) {
|
||||||
|
*family = current_family;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(resolved);
|
||||||
|
/* here, if err is set, we failed */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Tries to accept a socket
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
const char *inet_tryaccept(p_socket server, int family, p_socket client,
|
||||||
|
p_timeout tm) {
|
||||||
|
socklen_t len;
|
||||||
|
t_sockaddr_storage addr;
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET6: len = sizeof(struct sockaddr_in6); break;
|
||||||
|
case AF_INET: len = sizeof(struct sockaddr_in); break;
|
||||||
|
default: len = sizeof(addr); break;
|
||||||
|
}
|
||||||
|
return socket_strerror(socket_accept(server, client, (SA *) &addr,
|
||||||
|
&len, tm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to bind socket to (address, port)
|
* Tries to bind socket to (address, port)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
|
const char *inet_trybind(p_socket ps, int *family, const char *address,
|
||||||
{
|
const char *serv, struct addrinfo *bindhints) {
|
||||||
struct sockaddr_in local;
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||||
int err;
|
const char *err = NULL;
|
||||||
memset(&local, 0, sizeof(local));
|
int current_family = *family;
|
||||||
/* address is either wildcard or a valid ip address */
|
/* translate luasocket special values to C */
|
||||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
if (strcmp(address, "*") == 0) address = NULL;
|
||||||
local.sin_port = htons(port);
|
if (!serv) serv = "0";
|
||||||
local.sin_family = AF_INET;
|
/* try resolving */
|
||||||
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
|
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
|
||||||
struct hostent *hp = NULL;
|
if (err) {
|
||||||
struct in_addr **addr;
|
if (resolved) freeaddrinfo(resolved);
|
||||||
err = socket_gethostbyname(address, &hp);
|
return err;
|
||||||
if (err != IO_DONE) return socket_hoststrerror(err);
|
|
||||||
addr = (struct in_addr **) hp->h_addr_list;
|
|
||||||
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
|
||||||
}
|
}
|
||||||
err = socket_bind(ps, (SA *) &local, sizeof(local));
|
/* iterate over resolved addresses until one is good */
|
||||||
if (err != IO_DONE) socket_destroy(ps);
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||||
return socket_strerror(err);
|
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
|
||||||
|
socket_destroy(ps);
|
||||||
|
err = inet_trycreate(ps, iterator->ai_family,
|
||||||
|
iterator->ai_socktype, iterator->ai_protocol);
|
||||||
|
if (err) continue;
|
||||||
|
current_family = iterator->ai_family;
|
||||||
|
}
|
||||||
|
/* try binding to local address */
|
||||||
|
err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
|
||||||
|
(socklen_t) iterator->ai_addrlen));
|
||||||
|
/* keep trying unless bind succeeded */
|
||||||
|
if (err == NULL) {
|
||||||
|
*family = current_family;
|
||||||
|
/* set to non-blocking after bind */
|
||||||
|
socket_setnonblocking(ps);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* cleanup and return error */
|
||||||
|
freeaddrinfo(resolved);
|
||||||
|
/* here, if err is set, we failed */
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Some systems do not provide this so that we provide our own. It's not
|
* Some systems do not provide these so that we provide our own.
|
||||||
* marvelously fast, but it works just fine.
|
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#ifdef INET_ATON
|
#ifdef LUASOCKET_INET_ATON
|
||||||
int inet_aton(const char *cp, struct in_addr *inp)
|
int inet_aton(const char *cp, struct in_addr *inp)
|
||||||
{
|
{
|
||||||
unsigned int a = 0, b = 0, c = 0, d = 0;
|
unsigned int a = 0, b = 0, c = 0, d = 0;
|
||||||
@@ -278,4 +512,26 @@ int inet_aton(const char *cp, struct in_addr *inp)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LUASOCKET_INET_PTON
|
||||||
|
int inet_pton(int af, const char *src, void *dst)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int ret = 1;
|
||||||
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
|
hints.ai_family = af;
|
||||||
|
hints.ai_flags = AI_NUMERICHOST;
|
||||||
|
if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
|
||||||
|
if (af == AF_INET) {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
|
||||||
|
memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
|
||||||
|
} else if (af == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
|
||||||
|
memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
|
||||||
|
} else {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
44
src/inet.h
44
src/inet.h
@@ -1,42 +1,56 @@
|
|||||||
#ifndef INET_H
|
#ifndef INET_H
|
||||||
#define INET_H
|
#define INET_H
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internet domain functions
|
* Internet domain functions
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
*
|
||||||
* This module implements the creation and connection of internet domain
|
* This module implements the creation and connection of internet domain
|
||||||
* sockets, on top of the socket.h interface, and the interface of with the
|
* sockets, on top of the socket.h interface, and the interface of with the
|
||||||
* resolver.
|
* resolver.
|
||||||
*
|
*
|
||||||
* The function inet_aton is provided for the platforms where it is not
|
* The function inet_aton is provided for the platforms where it is not
|
||||||
* available. The module also implements the interface of the internet
|
* available. The module also implements the interface of the internet
|
||||||
* getpeername and getsockname functions as seen by Lua programs.
|
* getpeername and getsockname functions as seen by Lua programs.
|
||||||
*
|
*
|
||||||
* The Lua functions toip and tohostname are also implemented here.
|
* The Lua functions toip and tohostname are also implemented here.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define INET_ATON
|
#define LUASOCKET_INET_ATON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int inet_open(lua_State *L);
|
int inet_open(lua_State *L);
|
||||||
|
|
||||||
const char *inet_trycreate(p_socket ps, int type);
|
int inet_optfamily(lua_State* L, int narg, const char* def);
|
||||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
int inet_optsocktype(lua_State* L, int narg, const char* def);
|
||||||
unsigned short port, p_timeout tm);
|
|
||||||
const char *inet_trybind(p_socket ps, const char *address,
|
|
||||||
unsigned short port);
|
|
||||||
|
|
||||||
int inet_meth_getpeername(lua_State *L, p_socket ps);
|
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
|
||||||
int inet_meth_getsockname(lua_State *L, p_socket ps);
|
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
|
||||||
|
|
||||||
#ifdef INET_ATON
|
const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
|
||||||
|
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
|
||||||
|
const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints);
|
||||||
|
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
|
||||||
|
const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints);
|
||||||
|
|
||||||
|
#ifdef LUASOCKET_INET_ATON
|
||||||
int inet_aton(const char *cp, struct in_addr *inp);
|
int inet_aton(const char *cp, struct in_addr *inp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LUASOCKET_INET_PTON
|
||||||
|
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
|
||||||
|
int inet_pton(int af, const char *src, void *dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* INET_H */
|
#endif /* INET_H */
|
||||||
|
|||||||
8
src/io.c
8
src/io.c
@@ -1,14 +1,10 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Input/Output abstraction
|
* Input/Output abstraction
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
#include "luasocket.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* Exported functions
|
|
||||||
\*=========================================================================*/
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes C structure
|
* Initializes C structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -27,6 +23,6 @@ const char *io_strerror(int err) {
|
|||||||
case IO_DONE: return NULL;
|
case IO_DONE: return NULL;
|
||||||
case IO_CLOSED: return "closed";
|
case IO_CLOSED: return "closed";
|
||||||
case IO_TIMEOUT: return "timeout";
|
case IO_TIMEOUT: return "timeout";
|
||||||
default: return "unknown error";
|
default: return "unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/io.h
15
src/io.h
@@ -11,12 +11,8 @@
|
|||||||
*
|
*
|
||||||
* The module socket.h implements this interface, and thus the module tcp.h
|
* The module socket.h implements this interface, and thus the module tcp.h
|
||||||
* is very simple.
|
* is very simple.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <stdio.h>
|
#include "luasocket.h"
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
|
|
||||||
/* IO error codes */
|
/* IO error codes */
|
||||||
@@ -60,8 +56,15 @@ typedef struct t_io_ {
|
|||||||
} t_io;
|
} t_io;
|
||||||
typedef t_io *p_io;
|
typedef t_io *p_io;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
|
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
|
||||||
const char *io_strerror(int err);
|
const char *io_strerror(int err);
|
||||||
|
|
||||||
#endif /* IO_H */
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* IO_H */
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
-- LTN12 - Filters, sources, sinks and pumps.
|
-- LTN12 - Filters, sources, sinks and pumps.
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -10,17 +9,25 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local string = require("string")
|
local string = require("string")
|
||||||
local table = require("table")
|
local table = require("table")
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
local base = _G
|
local base = _G
|
||||||
module("ltn12")
|
local _M = {}
|
||||||
|
if module then -- heuristic for exporting a global package table
|
||||||
|
ltn12 = _M
|
||||||
|
end
|
||||||
|
local filter,source,sink,pump = {},{},{},{}
|
||||||
|
|
||||||
filter = {}
|
_M.filter = filter
|
||||||
source = {}
|
_M.source = source
|
||||||
sink = {}
|
_M.sink = sink
|
||||||
pump = {}
|
_M.pump = pump
|
||||||
|
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
|
local select = base.select
|
||||||
|
|
||||||
-- 2048 seems to be better in windows...
|
-- 2048 seems to be better in windows...
|
||||||
BLOCKSIZE = 2048
|
_M.BLOCKSIZE = 2048
|
||||||
_VERSION = "LTN12 1.0.1"
|
_M._VERSION = "LTN12 1.0.3"
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Filter stuff
|
-- Filter stuff
|
||||||
@@ -38,7 +45,8 @@ end
|
|||||||
-- chains a bunch of filters together
|
-- chains a bunch of filters together
|
||||||
-- (thanks to Wim Couwenberg)
|
-- (thanks to Wim Couwenberg)
|
||||||
function filter.chain(...)
|
function filter.chain(...)
|
||||||
local n = table.getn(arg)
|
local arg = {...}
|
||||||
|
local n = base.select('#',...)
|
||||||
local top, index = 1, 1
|
local top, index = 1, 1
|
||||||
local retry = ""
|
local retry = ""
|
||||||
return function(chunk)
|
return function(chunk)
|
||||||
@@ -89,7 +97,7 @@ end
|
|||||||
function source.file(handle, io_err)
|
function source.file(handle, io_err)
|
||||||
if handle then
|
if handle then
|
||||||
return function()
|
return function()
|
||||||
local chunk = handle:read(BLOCKSIZE)
|
local chunk = handle:read(_M.BLOCKSIZE)
|
||||||
if not chunk then handle:close() end
|
if not chunk then handle:close() end
|
||||||
return chunk
|
return chunk
|
||||||
end
|
end
|
||||||
@@ -112,14 +120,24 @@ function source.string(s)
|
|||||||
if s then
|
if s then
|
||||||
local i = 1
|
local i = 1
|
||||||
return function()
|
return function()
|
||||||
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
|
local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
|
||||||
i = i + BLOCKSIZE
|
i = i + _M.BLOCKSIZE
|
||||||
if chunk ~= "" then return chunk
|
if chunk ~= "" then return chunk
|
||||||
else return nil end
|
else return nil end
|
||||||
end
|
end
|
||||||
else return source.empty() end
|
else return source.empty() end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- creates table source
|
||||||
|
function source.table(t)
|
||||||
|
base.assert('table' == type(t))
|
||||||
|
local i = 0
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
return t[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- creates rewindable source
|
-- creates rewindable source
|
||||||
function source.rewind(src)
|
function source.rewind(src)
|
||||||
base.assert(src)
|
base.assert(src)
|
||||||
@@ -135,7 +153,9 @@ function source.rewind(src)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function source.chain(src, f)
|
-- chains a source with one or several filter(s)
|
||||||
|
function source.chain(src, f, ...)
|
||||||
|
if ... then f=filter.chain(f, ...) end
|
||||||
base.assert(src and f)
|
base.assert(src and f)
|
||||||
local last_in, last_out = "", ""
|
local last_in, last_out = "", ""
|
||||||
local state = "feeding"
|
local state = "feeding"
|
||||||
@@ -186,6 +206,7 @@ end
|
|||||||
-- other, as if they were concatenated
|
-- other, as if they were concatenated
|
||||||
-- (thanks to Wim Couwenberg)
|
-- (thanks to Wim Couwenberg)
|
||||||
function source.cat(...)
|
function source.cat(...)
|
||||||
|
local arg = {...}
|
||||||
local src = table.remove(arg, 1)
|
local src = table.remove(arg, 1)
|
||||||
return function()
|
return function()
|
||||||
while src do
|
while src do
|
||||||
@@ -249,8 +270,13 @@ function sink.error(err)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- chains a sink with a filter
|
-- chains a sink with one or several filter(s)
|
||||||
function sink.chain(f, snk)
|
function sink.chain(f, snk, ...)
|
||||||
|
if ... then
|
||||||
|
local args = { f, snk, ... }
|
||||||
|
snk = table.remove(args, #args)
|
||||||
|
f = filter.chain(unpack(args))
|
||||||
|
end
|
||||||
base.assert(f and snk)
|
base.assert(f and snk)
|
||||||
return function(chunk, err)
|
return function(chunk, err)
|
||||||
if chunk ~= "" then
|
if chunk ~= "" then
|
||||||
@@ -290,3 +316,4 @@ function pump.all(src, snk, step)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
24
src/luasocket.c
Normal file → Executable file
24
src/luasocket.c
Normal file → Executable file
@@ -10,23 +10,8 @@
|
|||||||
* involved in setting up both client and server connections. The provided
|
* involved in setting up both client and server connections. The provided
|
||||||
* IO routines, however, follow the Lua style, being very similar to the
|
* IO routines, however, follow the Lua style, being very similar to the
|
||||||
* standard Lua read and write functions.
|
* standard Lua read and write functions.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* Standard include files
|
|
||||||
\*=========================================================================*/
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
|
||||||
#include "compat-5.1.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* LuaSocket includes
|
|
||||||
\*=========================================================================*/
|
|
||||||
#include "luasocket.h"
|
#include "luasocket.h"
|
||||||
#include "auxiliar.h"
|
#include "auxiliar.h"
|
||||||
#include "except.h"
|
#include "except.h"
|
||||||
@@ -47,7 +32,7 @@ static int base_open(lua_State *L);
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Modules and functions
|
* Modules and functions
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static const luaL_reg mod[] = {
|
static const luaL_Reg mod[] = {
|
||||||
{"auxiliar", auxiliar_open},
|
{"auxiliar", auxiliar_open},
|
||||||
{"except", except_open},
|
{"except", except_open},
|
||||||
{"timeout", timeout_open},
|
{"timeout", timeout_open},
|
||||||
@@ -59,7 +44,7 @@ static const luaL_reg mod[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"skip", global_skip},
|
{"skip", global_skip},
|
||||||
{"__unload", global_unload},
|
{"__unload", global_unload},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
@@ -69,7 +54,7 @@ static luaL_reg func[] = {
|
|||||||
* Skip a few arguments
|
* Skip a few arguments
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_skip(lua_State *L) {
|
static int global_skip(lua_State *L) {
|
||||||
int amount = luaL_checkint(L, 1);
|
int amount = (int) luaL_checkinteger(L, 1);
|
||||||
int ret = lua_gettop(L) - amount - 1;
|
int ret = lua_gettop(L) - amount - 1;
|
||||||
return ret >= 0 ? ret : 0;
|
return ret >= 0 ? ret : 0;
|
||||||
}
|
}
|
||||||
@@ -89,7 +74,8 @@ static int global_unload(lua_State *L) {
|
|||||||
static int base_open(lua_State *L) {
|
static int base_open(lua_State *L) {
|
||||||
if (socket_open()) {
|
if (socket_open()) {
|
||||||
/* export functions (and leave namespace table on top of stack) */
|
/* export functions (and leave namespace table on top of stack) */
|
||||||
luaL_openlib(L, "socket", func, 0);
|
lua_newtable(L);
|
||||||
|
luaL_setfuncs(L, func, 0);
|
||||||
#ifdef LUASOCKET_DEBUG
|
#ifdef LUASOCKET_DEBUG
|
||||||
lua_pushstring(L, "_DEBUG");
|
lua_pushstring(L, "_DEBUG");
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
|
|||||||
@@ -5,24 +5,28 @@
|
|||||||
* Networking support for the Lua language
|
* Networking support for the Lua language
|
||||||
* Diego Nehab
|
* Diego Nehab
|
||||||
* 9/11/1999
|
* 9/11/1999
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------* \
|
||||||
* Current socket library version
|
* Current socket library version
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#define LUASOCKET_VERSION "LuaSocket 2.0.2"
|
#define LUASOCKET_VERSION "LuaSocket 3.0-rc1"
|
||||||
#define LUASOCKET_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab"
|
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
|
||||||
#define LUASOCKET_AUTHORS "Diego Nehab"
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* This macro prefixes all exported API functions
|
* This macro prefixes all exported API functions
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#ifndef LUASOCKET_API
|
#ifndef LUASOCKET_API
|
||||||
#define LUASOCKET_API extern
|
#ifdef _WIN32
|
||||||
|
#define LUASOCKET_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define LUASOCKET_API __attribute__ ((visibility ("default")))
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes the library.
|
* Initializes the library.
|
||||||
|
|||||||
497
src/makefile
Normal file → Executable file
497
src/makefile
Normal file → Executable file
@@ -1,90 +1,461 @@
|
|||||||
#------
|
# luasocket src/makefile
|
||||||
# Load configuration
|
|
||||||
#
|
#
|
||||||
include ../config
|
# Definitions in this section can be overriden on the command line or in the
|
||||||
|
# environment.
|
||||||
|
#
|
||||||
|
# These are equivalent:
|
||||||
|
#
|
||||||
|
# export PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
|
||||||
|
# make
|
||||||
|
#
|
||||||
|
# and
|
||||||
|
#
|
||||||
|
# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
|
||||||
|
|
||||||
|
# PLAT: linux macosx win32 win64 mingw
|
||||||
|
# platform to build for
|
||||||
|
PLAT?=linux
|
||||||
|
|
||||||
|
# LUAV: 5.1 5.2
|
||||||
|
# lua version to build against
|
||||||
|
LUAV?=5.1
|
||||||
|
|
||||||
|
# MYCFLAGS: to be set by user if needed
|
||||||
|
MYCFLAGS?=
|
||||||
|
|
||||||
|
# MYLDFLAGS: to be set by user if needed
|
||||||
|
MYLDFLAGS?=
|
||||||
|
|
||||||
|
# DEBUG: NODEBUG DEBUG
|
||||||
|
# debug mode causes luasocket to collect and returns timing information useful
|
||||||
|
# for testing and debugging luasocket itself
|
||||||
|
DEBUG?=NODEBUG
|
||||||
|
|
||||||
|
# where lua headers are found for macosx builds
|
||||||
|
# LUAINC_macosx:
|
||||||
|
# /opt/local/include
|
||||||
|
LUAINC_macosx_base?=/opt/local/include
|
||||||
|
LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) $(LUAINC_macosx_base)/lua$(LUAV) $(LUAINC_macosx_base)/lua-$(LUAV)
|
||||||
|
|
||||||
|
# FIXME default should this default to fink or to macports?
|
||||||
|
# What happens when more than one Lua version is installed?
|
||||||
|
LUAPREFIX_macosx?=/opt/local
|
||||||
|
CDIR_macosx?=lib/lua/$(LUAV)
|
||||||
|
LDIR_macosx?=share/lua/$(LUAV)
|
||||||
|
|
||||||
|
# LUAINC_linux:
|
||||||
|
# /usr/include/lua$(LUAV)
|
||||||
|
# /usr/local/include
|
||||||
|
# /usr/local/include/lua$(LUAV)
|
||||||
|
# where lua headers are found for linux builds
|
||||||
|
LUAINC_linux_base?=/usr/include
|
||||||
|
LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) $(LUAINC_linux_base)/lua$(LUAV)
|
||||||
|
LUAPREFIX_linux?=/usr/local
|
||||||
|
CDIR_linux?=lib/lua/$(LUAV)
|
||||||
|
LDIR_linux?=share/lua/$(LUAV)
|
||||||
|
|
||||||
|
# LUAINC_freebsd:
|
||||||
|
# /usr/local/include/lua$(LUAV)
|
||||||
|
# where lua headers are found for freebsd builds
|
||||||
|
LUAINC_freebsd_base?=/usr/local/include/
|
||||||
|
LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua/$(LUAV) $(LUAINC_freebsd_base)/lua$(LUAV)
|
||||||
|
LUAPREFIX_freebsd?=/usr/local/
|
||||||
|
CDIR_freebsd?=lib/lua/$(LUAV)
|
||||||
|
LDIR_freebsd?=share/lua/$(LUAV)
|
||||||
|
|
||||||
|
# where lua headers are found for mingw builds
|
||||||
|
# LUAINC_mingw:
|
||||||
|
# /opt/local/include
|
||||||
|
LUAINC_mingw_base?=/usr/include
|
||||||
|
LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) $(LUAINC_mingw_base)/lua$(LUAV)
|
||||||
|
LUALIB_mingw_base?=/usr/bin
|
||||||
|
LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll
|
||||||
|
LUAPREFIX_mingw?=/usr
|
||||||
|
CDIR_mingw?=lua/$(LUAV)
|
||||||
|
LDIR_mingw?=lua/$(LUAV)/lua
|
||||||
|
|
||||||
|
|
||||||
|
# LUAINC_win32:
|
||||||
|
# LUALIB_win32:
|
||||||
|
# where lua headers and libraries are found for win32 builds
|
||||||
|
LUAPREFIX_win32?=
|
||||||
|
LUAINC_win32?=$(LUAPREFIX_win32)/include/lua/$(LUAV) $(LUAPREFIX_win32)/include/lua$(LUAV)
|
||||||
|
PLATFORM_win32?=Release
|
||||||
|
CDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)
|
||||||
|
LDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)/lua
|
||||||
|
LUALIB_win32?=$(LUAPREFIX_win32)/lib/lua/$(LUAV)/$(PLATFORM_win32)
|
||||||
|
LUALIBNAME_win32?=lua$(subst .,,$(LUAV)).lib
|
||||||
|
|
||||||
|
# LUAINC_win64:
|
||||||
|
# LUALIB_win64:
|
||||||
|
# where lua headers and libraries are found for win64 builds
|
||||||
|
LUAPREFIX_win64?=
|
||||||
|
LUAINC_win64?=$(LUAPREFIX_win64)/include/lua/$(LUAV) $(LUAPREFIX_win64)/include/lua$(LUAV)
|
||||||
|
PLATFORM_win64?=x64/Release
|
||||||
|
CDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)
|
||||||
|
LDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)/lua
|
||||||
|
LUALIB_win64?=$(LUAPREFIX_win64)/lib/lua/$(LUAV)/$(PLATFORM_win64)
|
||||||
|
LUALIBNAME_win64?=lua$(subst .,,$(LUAV)).lib
|
||||||
|
|
||||||
|
|
||||||
|
# LUAINC_solaris:
|
||||||
|
LUAINC_solaris_base?=/usr/include
|
||||||
|
LUAINC_solaris?=$(LUAINC_solaris_base)/lua/$(LUAV) $(LUAINC_solaris_base)/lua$(LUAV)
|
||||||
|
LUAPREFIX_solaris?=/usr/local
|
||||||
|
CDIR_solaris?=lib/lua/$(LUAV)
|
||||||
|
LDIR_solaris?=share/lua/$(LUAV)
|
||||||
|
|
||||||
|
# prefix: /usr/local /usr /opt/local /sw
|
||||||
|
# the top of the default install tree
|
||||||
|
prefix?=$(LUAPREFIX_$(PLAT))
|
||||||
|
|
||||||
|
CDIR?=$(CDIR_$(PLAT))
|
||||||
|
LDIR?=$(LDIR_$(PLAT))
|
||||||
|
|
||||||
|
# DESTDIR: (no default)
|
||||||
|
# used by package managers to install into a temporary destination
|
||||||
|
DESTDIR?=
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Hopefully no need to change anything below this line
|
# Definitions below can be overridden on the make command line, but
|
||||||
|
# shouldn't have to be.
|
||||||
|
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Install directories
|
||||||
#
|
#
|
||||||
|
|
||||||
|
INSTALL_DIR=install -d
|
||||||
|
INSTALL_DATA=install -m644
|
||||||
|
INSTALL_EXEC=install
|
||||||
|
INSTALL_TOP=$(DESTDIR)$(prefix)
|
||||||
|
|
||||||
|
INSTALL_TOP_LDIR=$(INSTALL_TOP)/$(LDIR)
|
||||||
|
INSTALL_TOP_CDIR=$(INSTALL_TOP)/$(CDIR)
|
||||||
|
|
||||||
|
INSTALL_SOCKET_LDIR=$(INSTALL_TOP_LDIR)/socket
|
||||||
|
INSTALL_SOCKET_CDIR=$(INSTALL_TOP_CDIR)/socket
|
||||||
|
INSTALL_MIME_LDIR=$(INSTALL_TOP_LDIR)/mime
|
||||||
|
INSTALL_MIME_CDIR=$(INSTALL_TOP_CDIR)/mime
|
||||||
|
|
||||||
|
print:
|
||||||
|
@echo PLAT=$(PLAT)
|
||||||
|
@echo LUAV=$(LUAV)
|
||||||
|
@echo DEBUG=$(DEBUG)
|
||||||
|
@echo prefix=$(prefix)
|
||||||
|
@echo LUAINC_$(PLAT)=$(LUAINC_$(PLAT))
|
||||||
|
@echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT))
|
||||||
|
@echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR)
|
||||||
|
@echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR)
|
||||||
|
@echo CFLAGS=$(CFLAGS)
|
||||||
|
@echo LDFLAGS=$(LDFLAGS)
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Supported platforms
|
||||||
|
#
|
||||||
|
PLATS= macosx linux win32 win64 mingw solaris
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for Mac OS X
|
||||||
|
SO_macosx=so
|
||||||
|
O_macosx=o
|
||||||
|
CC_macosx=gcc
|
||||||
|
DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
|
||||||
|
CFLAGS_macosx=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
|
||||||
|
LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
|
||||||
|
LD_macosx=gcc
|
||||||
|
SOCKET_macosx=usocket.o
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for Linux
|
||||||
|
SO_linux=so
|
||||||
|
O_linux=o
|
||||||
|
CC_linux=gcc
|
||||||
|
DEF_linux=-DLUASOCKET_$(DEBUG)
|
||||||
|
CFLAGS_linux=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
|
||||||
|
-Wimplicit -O2 -ggdb3 -fpic
|
||||||
|
LDFLAGS_linux=-O -shared -fpic -o
|
||||||
|
LD_linux=gcc
|
||||||
|
SOCKET_linux=usocket.o
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for FreeBSD
|
||||||
|
SO_freebsd=so
|
||||||
|
O_freebsd=o
|
||||||
|
CC_freebsd=gcc
|
||||||
|
DEF_freebsd=-DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
|
||||||
|
CFLAGS_freebsd=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
|
||||||
|
-Wimplicit -O2 -ggdb3 -fpic
|
||||||
|
LDFLAGS_freebsd=-O -shared -fpic -o
|
||||||
|
LD_freebsd=gcc
|
||||||
|
SOCKET_freebsd=usocket.o
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for Solaris
|
||||||
|
SO_solaris=so
|
||||||
|
O_solaris=o
|
||||||
|
CC_solaris=gcc
|
||||||
|
DEF_solaris=-DLUASOCKET_$(DEBUG)
|
||||||
|
CFLAGS_solaris=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
|
||||||
|
-Wimplicit -O2 -ggdb3 -fpic
|
||||||
|
LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o
|
||||||
|
LD_solaris=gcc
|
||||||
|
SOCKET_solaris=usocket.o
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for MingW
|
||||||
|
SO_mingw=dll
|
||||||
|
O_mingw=o
|
||||||
|
CC_mingw=gcc
|
||||||
|
DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) \
|
||||||
|
-DWINVER=0x0501
|
||||||
|
CFLAGS_mingw=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
|
||||||
|
LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
|
||||||
|
LD_mingw=gcc
|
||||||
|
SOCKET_mingw=wsocket.o
|
||||||
|
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for Win32
|
||||||
|
SO_win32=dll
|
||||||
|
O_win32=obj
|
||||||
|
CC_win32=cl
|
||||||
|
DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
|
||||||
|
//D "_CRT_SECURE_NO_WARNINGS" \
|
||||||
|
//D "_WINDLL" \
|
||||||
|
//D "LUASOCKET_$(DEBUG)"
|
||||||
|
CFLAGS_win32=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
|
||||||
|
LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
|
||||||
|
//MANIFEST //MANIFESTFILE:"intermediate.manifest" \
|
||||||
|
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
|
||||||
|
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
|
||||||
|
//MACHINE:X86 /LIBPATH:"$(LUALIB)" \
|
||||||
|
$(LUALIBNAME_win32) ws2_32.lib //OUT:
|
||||||
|
|
||||||
|
LD_win32=cl
|
||||||
|
SOCKET_win32=wsocket.obj
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Compiler and linker settings
|
||||||
|
# for Win64
|
||||||
|
SO_win64=dll
|
||||||
|
O_win64=obj
|
||||||
|
CC_win64=cl
|
||||||
|
DEF_win64= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
|
||||||
|
//D "_CRT_SECURE_NO_WARNINGS" \
|
||||||
|
//D "_WINDLL" \
|
||||||
|
//D "LUASOCKET_$(DEBUG)"
|
||||||
|
CFLAGS_win64=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
|
||||||
|
LDFLAGS_win64= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
|
||||||
|
//MANIFEST //MANIFESTFILE:"intermediate.manifest" \
|
||||||
|
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
|
||||||
|
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
|
||||||
|
/LIBPATH:"$(LUALIB)" \
|
||||||
|
$(LUALIBNAME_win64) ws2_32.lib //OUT:
|
||||||
|
|
||||||
|
LD_win64=cl
|
||||||
|
SOCKET_win64=wsocket.obj
|
||||||
|
|
||||||
|
.SUFFIXES: .obj
|
||||||
|
|
||||||
|
.c.obj:
|
||||||
|
$(CC) $(CFLAGS) //Fo"$@" //c $<
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Output file names
|
||||||
|
#
|
||||||
|
SO=$(SO_$(PLAT))
|
||||||
|
O=$(O_$(PLAT))
|
||||||
|
SOCKET_V=3.0-rc1
|
||||||
|
MIME_V=1.0.3
|
||||||
|
SOCKET_SO=socket-$(SOCKET_V).$(SO)
|
||||||
|
MIME_SO=mime-$(MIME_V).$(SO)
|
||||||
|
UNIX_SO=unix.$(SO)
|
||||||
|
SERIAL_SO=serial.$(SO)
|
||||||
|
SOCKET=$(SOCKET_$(PLAT))
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Settings selected for platform
|
||||||
|
#
|
||||||
|
CC=$(CC_$(PLAT))
|
||||||
|
DEF=$(DEF_$(PLAT))
|
||||||
|
CFLAGS=$(MYCFLAGS) $(CFLAGS_$(PLAT))
|
||||||
|
LDFLAGS=$(MYLDFLAGS) $(LDFLAGS_$(PLAT))
|
||||||
|
LD=$(LD_$(PLAT))
|
||||||
|
LUAINC= $(LUAINC_$(PLAT))
|
||||||
|
LUALIB= $(LUALIB_$(PLAT))
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Modules belonging to socket-core
|
# Modules belonging to socket-core
|
||||||
#
|
#
|
||||||
|
SOCKET_OBJS= \
|
||||||
#$(COMPAT)/compat-5.1.o \
|
luasocket.$(O) \
|
||||||
|
timeout.$(O) \
|
||||||
SOCKET_OBJS:= \
|
buffer.$(O) \
|
||||||
luasocket.o \
|
io.$(O) \
|
||||||
timeout.o \
|
auxiliar.$(O) \
|
||||||
buffer.o \
|
compat.$(O) \
|
||||||
io.o \
|
options.$(O) \
|
||||||
auxiliar.o \
|
inet.$(O) \
|
||||||
options.o \
|
$(SOCKET) \
|
||||||
inet.o \
|
except.$(O) \
|
||||||
tcp.o \
|
select.$(O) \
|
||||||
udp.o \
|
tcp.$(O) \
|
||||||
except.o \
|
udp.$(O)
|
||||||
select.o \
|
|
||||||
usocket.o
|
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Modules belonging mime-core
|
# Modules belonging mime-core
|
||||||
#
|
#
|
||||||
#$(COMPAT)/compat-5.1.o \
|
MIME_OBJS= \
|
||||||
|
mime.$(O) \
|
||||||
MIME_OBJS:=\
|
compat.$(O)
|
||||||
mime.o
|
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Modules belonging unix (local domain sockets)
|
# Modules belonging unix (local domain sockets)
|
||||||
#
|
#
|
||||||
UNIX_OBJS:=\
|
UNIX_OBJS=\
|
||||||
buffer.o \
|
buffer.$(O) \
|
||||||
auxiliar.o \
|
auxiliar.$(O) \
|
||||||
options.o \
|
options.$(O) \
|
||||||
timeout.o \
|
timeout.$(O) \
|
||||||
io.o \
|
io.$(O) \
|
||||||
usocket.o \
|
usocket.$(O) \
|
||||||
unix.o
|
unixstream.$(O) \
|
||||||
|
unixdgram.$(O) \
|
||||||
|
compat.$(O) \
|
||||||
|
unix.$(O)
|
||||||
|
|
||||||
all: $(SOCKET_SO) $(MIME_SO)
|
#------
|
||||||
|
# Modules belonging to serial (device streams)
|
||||||
|
#
|
||||||
|
SERIAL_OBJS=\
|
||||||
|
buffer.$(O) \
|
||||||
|
compat.$(O) \
|
||||||
|
auxiliar.$(O) \
|
||||||
|
options.$(O) \
|
||||||
|
timeout.$(O) \
|
||||||
|
io.$(O) \
|
||||||
|
usocket.$(O) \
|
||||||
|
serial.$(O)
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Files to install
|
||||||
|
#
|
||||||
|
TO_SOCKET_LDIR= \
|
||||||
|
http.lua \
|
||||||
|
url.lua \
|
||||||
|
tp.lua \
|
||||||
|
ftp.lua \
|
||||||
|
headers.lua \
|
||||||
|
smtp.lua
|
||||||
|
|
||||||
|
TO_TOP_LDIR= \
|
||||||
|
ltn12.lua \
|
||||||
|
socket.lua \
|
||||||
|
mime.lua
|
||||||
|
|
||||||
|
#------
|
||||||
|
# Targets
|
||||||
|
#
|
||||||
|
default: $(PLAT)
|
||||||
|
|
||||||
|
|
||||||
|
freebsd:
|
||||||
|
$(MAKE) all-unix PLAT=freebsd
|
||||||
|
|
||||||
|
macosx:
|
||||||
|
$(MAKE) all-unix PLAT=macosx
|
||||||
|
|
||||||
|
win32:
|
||||||
|
$(MAKE) all PLAT=win32
|
||||||
|
|
||||||
|
win64:
|
||||||
|
$(MAKE) all PLAT=win64
|
||||||
|
|
||||||
|
linux:
|
||||||
|
$(MAKE) all-unix PLAT=linux
|
||||||
|
|
||||||
|
mingw:
|
||||||
|
$(MAKE) all PLAT=mingw
|
||||||
|
|
||||||
|
solaris:
|
||||||
|
$(MAKE) all-unix PLAT=solaris
|
||||||
|
|
||||||
|
none:
|
||||||
|
@echo "Please run"
|
||||||
|
@echo " make PLATFORM"
|
||||||
|
@echo "where PLATFORM is one of these:"
|
||||||
|
@echo " $(PLATS)"
|
||||||
|
|
||||||
|
all: $(SOCKET_SO) $(MIME_SO)
|
||||||
|
|
||||||
$(SOCKET_SO): $(SOCKET_OBJS)
|
$(SOCKET_SO): $(SOCKET_OBJS)
|
||||||
$(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS)
|
$(LD) $(SOCKET_OBJS) $(LDFLAGS)$@
|
||||||
|
|
||||||
$(MIME_SO): $(MIME_OBJS)
|
$(MIME_SO): $(MIME_OBJS)
|
||||||
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
|
$(LD) $(MIME_OBJS) $(LDFLAGS)$@
|
||||||
|
|
||||||
|
all-unix: all $(UNIX_SO) $(SERIAL_SO)
|
||||||
|
|
||||||
$(UNIX_SO): $(UNIX_OBJS)
|
$(UNIX_SO): $(UNIX_OBJS)
|
||||||
$(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)
|
$(LD) $(UNIX_OBJS) $(LDFLAGS)$@
|
||||||
|
|
||||||
|
$(SERIAL_SO): $(SERIAL_OBJS)
|
||||||
|
$(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(INSTALL_DIR) $(INSTALL_TOP_LDIR)
|
||||||
|
$(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
|
||||||
|
$(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
|
||||||
|
$(INSTALL_DATA) $(TO_SOCKET_LDIR) $(INSTALL_SOCKET_LDIR)
|
||||||
|
$(INSTALL_DIR) $(INSTALL_SOCKET_CDIR)
|
||||||
|
$(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_CDIR)/core.$(SO)
|
||||||
|
$(INSTALL_DIR) $(INSTALL_MIME_CDIR)
|
||||||
|
$(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_CDIR)/core.$(SO)
|
||||||
|
|
||||||
|
install-unix: install
|
||||||
|
$(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_CDIR)/$(UNIX_SO)
|
||||||
|
$(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_CDIR)/$(SERIAL_SO)
|
||||||
|
|
||||||
|
local:
|
||||||
|
$(MAKE) install INSTALL_TOP_CDIR=.. INSTALL_TOP_LDIR=..
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(SOCKET_SO) $(SOCKET_OBJS) $(SERIAL_OBJS)
|
||||||
|
rm -f $(MIME_SO) $(UNIX_SO) $(SERIAL_SO) $(MIME_OBJS) $(UNIX_OBJS)
|
||||||
|
|
||||||
|
.PHONY: all $(PLATS) default clean echo none
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# List of dependencies
|
# List of dependencies
|
||||||
#
|
#
|
||||||
auxiliar.o: auxiliar.c auxiliar.h
|
compat.$(O): compat.c compat.h
|
||||||
buffer.o: buffer.c buffer.h io.h timeout.h
|
auxiliar.$(O): auxiliar.c auxiliar.h
|
||||||
except.o: except.c except.h
|
buffer.$(O): buffer.c buffer.h io.h timeout.h
|
||||||
inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h
|
except.$(O): except.c except.h
|
||||||
io.o: io.c io.h timeout.h
|
inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
|
||||||
luasocket.o: luasocket.c luasocket.h auxiliar.h except.h timeout.h \
|
io.$(O): io.c io.h timeout.h
|
||||||
buffer.h io.h inet.h socket.h usocket.h tcp.h udp.h select.h
|
luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
|
||||||
mime.o: mime.c mime.h
|
timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
|
||||||
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
|
udp.h select.h
|
||||||
usocket.h inet.h
|
mime.$(O): mime.c mime.h
|
||||||
select.o: select.c socket.h io.h timeout.h usocket.h select.h
|
options.$(O): options.c auxiliar.h options.h socket.h io.h \
|
||||||
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
|
timeout.h usocket.h inet.h
|
||||||
options.h tcp.h buffer.h
|
select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
|
||||||
timeout.o: timeout.c auxiliar.h timeout.h
|
serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
|
||||||
udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
|
options.h unix.h buffer.h
|
||||||
options.h udp.h
|
tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
|
||||||
unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h options.h \
|
inet.h options.h tcp.h buffer.h
|
||||||
unix.h buffer.h
|
timeout.$(O): timeout.c auxiliar.h timeout.h
|
||||||
usocket.o: usocket.c socket.h io.h timeout.h usocket.h
|
udp.$(O): udp.c auxiliar.h socket.h io.h timeout.h usocket.h \
|
||||||
|
inet.h options.h udp.h
|
||||||
clean:
|
unix.$(O): unix.c auxiliar.h socket.h io.h timeout.h usocket.h \
|
||||||
rm -f $(SOCKET_SO) $(SOCKET_OBJS)
|
options.h unix.h buffer.h
|
||||||
rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS)
|
usocket.$(O): usocket.c socket.h io.h timeout.h usocket.h
|
||||||
|
wsocket.$(O): wsocket.c socket.h io.h timeout.h usocket.h
|
||||||
#------
|
|
||||||
# End of makefile configuration
|
|
||||||
#
|
|
||||||
|
|||||||
74
src/mbox.lua
74
src/mbox.lua
@@ -1,14 +1,16 @@
|
|||||||
local Public = {}
|
local _M = {}
|
||||||
|
|
||||||
mbox = Public
|
if module then
|
||||||
|
mbox = _M
|
||||||
|
end
|
||||||
|
|
||||||
function Public.split_message(message_s)
|
function _M.split_message(message_s)
|
||||||
local message = {}
|
local message = {}
|
||||||
message_s = string.gsub(message_s, "\r\n", "\n")
|
message_s = string.gsub(message_s, "\r\n", "\n")
|
||||||
string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
|
string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
|
||||||
string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
|
string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
|
||||||
if not message.body then
|
if not message.body then
|
||||||
string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
|
string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
|
||||||
end
|
end
|
||||||
if not message.headers and not message.body then
|
if not message.headers and not message.body then
|
||||||
message.headers = message_s
|
message.headers = message_s
|
||||||
@@ -16,7 +18,7 @@ function Public.split_message(message_s)
|
|||||||
return message.headers or "", message.body or ""
|
return message.headers or "", message.body or ""
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.split_headers(headers_s)
|
function _M.split_headers(headers_s)
|
||||||
local headers = {}
|
local headers = {}
|
||||||
headers_s = string.gsub(headers_s, "\r\n", "\n")
|
headers_s = string.gsub(headers_s, "\r\n", "\n")
|
||||||
headers_s = string.gsub(headers_s, "\n[ ]+", " ")
|
headers_s = string.gsub(headers_s, "\n[ ]+", " ")
|
||||||
@@ -24,18 +26,18 @@ function Public.split_headers(headers_s)
|
|||||||
return headers
|
return headers
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.parse_header(header_s)
|
function _M.parse_header(header_s)
|
||||||
header_s = string.gsub(header_s, "\n[ ]+", " ")
|
header_s = string.gsub(header_s, "\n[ ]+", " ")
|
||||||
header_s = string.gsub(header_s, "\n+", "")
|
header_s = string.gsub(header_s, "\n+", "")
|
||||||
local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
|
local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
|
||||||
return name, value
|
return name, value
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.parse_headers(headers_s)
|
function _M.parse_headers(headers_s)
|
||||||
local headers_t = Public.split_headers(headers_s)
|
local headers_t = _M.split_headers(headers_s)
|
||||||
local headers = {}
|
local headers = {}
|
||||||
for i = 1, table.getn(headers_t) do
|
for i = 1, #headers_t do
|
||||||
local name, value = Public.parse_header(headers_t[i])
|
local name, value = _M.parse_header(headers_t[i])
|
||||||
if name then
|
if name then
|
||||||
name = string.lower(name)
|
name = string.lower(name)
|
||||||
if headers[name] then
|
if headers[name] then
|
||||||
@@ -46,7 +48,7 @@ function Public.parse_headers(headers_s)
|
|||||||
return headers
|
return headers
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.parse_from(from)
|
function _M.parse_from(from)
|
||||||
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
|
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
|
||||||
if not address then
|
if not address then
|
||||||
_, __, address = string.find(from, "%s*(.+)%s*")
|
_, __, address = string.find(from, "%s*(.+)%s*")
|
||||||
@@ -54,35 +56,37 @@ function Public.parse_from(from)
|
|||||||
name = name or ""
|
name = name or ""
|
||||||
address = address or ""
|
address = address or ""
|
||||||
if name == "" then name = address end
|
if name == "" then name = address end
|
||||||
name = string.gsub(name, '"', "")
|
name = string.gsub(name, '"', "")
|
||||||
return name, address
|
return name, address
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.split_mbox(mbox_s)
|
function _M.split_mbox(mbox_s)
|
||||||
mbox = {}
|
local mbox = {}
|
||||||
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
|
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
|
||||||
local nj, i, j = 1, 1, 1
|
local nj, i, j = 1, 1, 1
|
||||||
while 1 do
|
while 1 do
|
||||||
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
|
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
|
||||||
if not i then break end
|
if not i then break end
|
||||||
local message = string.sub(mbox_s, j, i-1)
|
local message = string.sub(mbox_s, j, i-1)
|
||||||
table.insert(mbox, message)
|
table.insert(mbox, message)
|
||||||
j = nj+1
|
j = nj+1
|
||||||
end
|
end
|
||||||
return mbox
|
return mbox
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.parse(mbox_s)
|
function _M.parse(mbox_s)
|
||||||
local mbox = Public.split_mbox(mbox_s)
|
local mbox = _M.split_mbox(mbox_s)
|
||||||
for i = 1, table.getn(mbox) do
|
for i = 1, #mbox do
|
||||||
mbox[i] = Public.parse_message(mbox[i])
|
mbox[i] = _M.parse_message(mbox[i])
|
||||||
end
|
end
|
||||||
return mbox
|
return mbox
|
||||||
end
|
end
|
||||||
|
|
||||||
function Public.parse_message(message_s)
|
function _M.parse_message(message_s)
|
||||||
local message = {}
|
local message = {}
|
||||||
message.headers, message.body = Public.split_message(message_s)
|
message.headers, message.body = _M.split_message(message_s)
|
||||||
message.headers = Public.parse_headers(message.headers)
|
message.headers = _M.parse_headers(message.headers)
|
||||||
return message
|
return message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
379
src/mime.c
Normal file → Executable file
379
src/mime.c
Normal file → Executable file
@@ -1,19 +1,11 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* MIME support functions
|
* MIME support functions
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <string.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
|
||||||
#include "compat-5.1.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mime.h"
|
#include "mime.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Don't want to trust escape character constants
|
* Don't want to trust escape character constants
|
||||||
@@ -35,20 +27,20 @@ static int mime_global_eol(lua_State *L);
|
|||||||
static int mime_global_dot(lua_State *L);
|
static int mime_global_dot(lua_State *L);
|
||||||
|
|
||||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
|
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
|
||||||
static void b64setup(UC *b64unbase);
|
//static void b64setup(UC *base);
|
||||||
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||||
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
|
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
|
||||||
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||||
|
|
||||||
static void qpsetup(UC *qpclass, UC *qpunbase);
|
//static void qpsetup(UC *class, UC *unbase);
|
||||||
static void qpquote(UC c, luaL_Buffer *buffer);
|
static void qpquote(UC c, luaL_Buffer *buffer);
|
||||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||||
static size_t qpencode(UC c, UC *input, size_t size,
|
static size_t qpencode(UC c, UC *input, size_t size,
|
||||||
const char *marker, luaL_Buffer *buffer);
|
const char *marker, luaL_Buffer *buffer);
|
||||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
|
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
|
||||||
|
|
||||||
/* code support functions */
|
/* code support functions */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{ "dot", mime_global_dot },
|
{ "dot", mime_global_dot },
|
||||||
{ "b64", mime_global_b64 },
|
{ "b64", mime_global_b64 },
|
||||||
{ "eol", mime_global_eol },
|
{ "eol", mime_global_eol },
|
||||||
@@ -63,17 +55,111 @@ static luaL_reg func[] = {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Quoted-printable globals
|
* Quoted-printable globals
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static UC qpclass[256];
|
|
||||||
static UC qpbase[] = "0123456789ABCDEF";
|
|
||||||
static UC qpunbase[256];
|
|
||||||
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
|
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
|
||||||
|
|
||||||
|
static const UC qpclass[] = {
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
|
||||||
|
QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
|
||||||
|
QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
|
||||||
|
};
|
||||||
|
|
||||||
|
static const UC qpbase[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
static const UC qpunbase[] = {
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255
|
||||||
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Base64 globals
|
* Base64 globals
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static const UC b64base[] =
|
static const UC b64base[] =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
static UC b64unbase[256];
|
|
||||||
|
static const UC b64unbase[] = {
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
|
||||||
|
255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
|
||||||
|
255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||||
|
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||||
|
51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255
|
||||||
|
};
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Exported functions
|
* Exported functions
|
||||||
@@ -81,16 +167,17 @@ static UC b64unbase[256];
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
MIME_API int luaopen_mime_core(lua_State *L)
|
LUASOCKET_API int luaopen_mime_core(lua_State *L)
|
||||||
{
|
{
|
||||||
luaL_openlib(L, "mime", func, 0);
|
lua_newtable(L);
|
||||||
|
luaL_setfuncs(L, func, 0);
|
||||||
/* make version string available to scripts */
|
/* make version string available to scripts */
|
||||||
lua_pushstring(L, "_VERSION");
|
lua_pushstring(L, "_VERSION");
|
||||||
lua_pushstring(L, MIME_VERSION);
|
lua_pushstring(L, MIME_VERSION);
|
||||||
lua_rawset(L, -3);
|
lua_rawset(L, -3);
|
||||||
/* initialize lookup tables */
|
/* initialize lookup tables */
|
||||||
qpsetup(qpclass, qpunbase);
|
// qpsetup(qpclass, qpunbase);
|
||||||
b64setup(b64unbase);
|
// b64setup(b64unbase);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,15 +187,15 @@ MIME_API int luaopen_mime_core(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
|
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
|
||||||
* A, n = wrp(l, B, length)
|
* A, n = wrp(l, B, length)
|
||||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||||
* 'l' is how many bytes are left for the first line of B.
|
* 'l' is how many bytes are left for the first line of B.
|
||||||
* 'n' is the number of bytes left in the last line of A.
|
* 'n' is the number of bytes left in the last line of A.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int mime_global_wrp(lua_State *L)
|
static int mime_global_wrp(lua_State *L)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int left = (int) luaL_checknumber(L, 1);
|
int left = (int) luaL_checknumber(L, 1);
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||||
const UC *last = input + size;
|
const UC *last = input + size;
|
||||||
int length = (int) luaL_optnumber(L, 3, 76);
|
int length = (int) luaL_optnumber(L, 3, 76);
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
@@ -120,7 +207,7 @@ static int mime_global_wrp(lua_State *L)
|
|||||||
else lua_pushnil(L);
|
else lua_pushnil(L);
|
||||||
lua_pushnumber(L, length);
|
lua_pushnumber(L, length);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last) {
|
while (input < last) {
|
||||||
switch (*input) {
|
switch (*input) {
|
||||||
@@ -135,7 +222,7 @@ static int mime_global_wrp(lua_State *L)
|
|||||||
left = length;
|
left = length;
|
||||||
luaL_addstring(&buffer, CRLF);
|
luaL_addstring(&buffer, CRLF);
|
||||||
}
|
}
|
||||||
luaL_putchar(&buffer, *input);
|
luaL_addchar(&buffer, *input);
|
||||||
left--;
|
left--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -146,23 +233,31 @@ static int mime_global_wrp(lua_State *L)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Fill base64 decode map.
|
* Fill base64 decode map.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void b64setup(UC *b64unbase)
|
static void b64setup(UC *unbase)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255;
|
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
|
||||||
for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i;
|
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
|
||||||
b64unbase['='] = 0;
|
unbase['='] = 0;
|
||||||
|
|
||||||
|
printf("static const UC b64unbase[] = {\n");
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
printf("%d, ", unbase[i]);
|
||||||
|
}
|
||||||
|
printf("\n}\n;");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Acumulates bytes in input buffer until 3 bytes are available.
|
* Acumulates bytes in input buffer until 3 bytes are available.
|
||||||
* Translate the 3 bytes into Base64 form and append to buffer.
|
* Translate the 3 bytes into Base64 form and append to buffer.
|
||||||
* Returns new number of bytes in buffer.
|
* Returns new number of bytes in buffer.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t b64encode(UC c, UC *input, size_t size,
|
static size_t b64encode(UC c, UC *input, size_t size,
|
||||||
luaL_Buffer *buffer)
|
luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
input[size++] = c;
|
input[size++] = c;
|
||||||
@@ -171,7 +266,7 @@ static size_t b64encode(UC c, UC *input, size_t size,
|
|||||||
unsigned long value = 0;
|
unsigned long value = 0;
|
||||||
value += input[0]; value <<= 8;
|
value += input[0]; value <<= 8;
|
||||||
value += input[1]; value <<= 8;
|
value += input[1]; value <<= 8;
|
||||||
value += input[2];
|
value += input[2];
|
||||||
code[3] = b64base[value & 0x3f]; value >>= 6;
|
code[3] = b64base[value & 0x3f]; value >>= 6;
|
||||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||||
@@ -183,11 +278,11 @@ static size_t b64encode(UC c, UC *input, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
|
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
|
||||||
* Result, if any, is appended to buffer.
|
* Result, if any, is appended to buffer.
|
||||||
* Returns 0.
|
* Returns 0.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t b64pad(const UC *input, size_t size,
|
static size_t b64pad(const UC *input, size_t size,
|
||||||
luaL_Buffer *buffer)
|
luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
unsigned long value = 0;
|
unsigned long value = 0;
|
||||||
@@ -200,7 +295,7 @@ static size_t b64pad(const UC *input, size_t size,
|
|||||||
luaL_addlstring(buffer, (char *) code, 4);
|
luaL_addlstring(buffer, (char *) code, 4);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
value = input[0]; value <<= 8;
|
value = input[0]; value <<= 8;
|
||||||
value |= input[1]; value <<= 2;
|
value |= input[1]; value <<= 2;
|
||||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||||
@@ -214,11 +309,11 @@ static size_t b64pad(const UC *input, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Acumulates bytes in input buffer until 4 bytes are available.
|
* Acumulates bytes in input buffer until 4 bytes are available.
|
||||||
* Translate the 4 bytes from Base64 form and append to buffer.
|
* Translate the 4 bytes from Base64 form and append to buffer.
|
||||||
* Returns new number of bytes in buffer.
|
* Returns new number of bytes in buffer.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t b64decode(UC c, UC *input, size_t size,
|
static size_t b64decode(UC c, UC *input, size_t size,
|
||||||
luaL_Buffer *buffer)
|
luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
/* ignore invalid characters */
|
/* ignore invalid characters */
|
||||||
@@ -236,7 +331,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
|
|||||||
decoded[1] = (UC) (value & 0xff); value >>= 8;
|
decoded[1] = (UC) (value & 0xff); value >>= 8;
|
||||||
decoded[0] = (UC) value;
|
decoded[0] = (UC) value;
|
||||||
/* take care of paddding */
|
/* take care of paddding */
|
||||||
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
|
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
|
||||||
luaL_addlstring(buffer, (char *) decoded, valid);
|
luaL_addlstring(buffer, (char *) decoded, valid);
|
||||||
return 0;
|
return 0;
|
||||||
/* need more data */
|
/* need more data */
|
||||||
@@ -248,7 +343,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
|
|||||||
* A, B = b64(C, D)
|
* A, B = b64(C, D)
|
||||||
* A is the encoded version of the largest prefix of C .. D that is
|
* A is the encoded version of the largest prefix of C .. D that is
|
||||||
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
|
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
|
||||||
* The easiest thing would be to concatenate the two strings and
|
* The easiest thing would be to concatenate the two strings and
|
||||||
* encode the result, but we can't afford that or Lua would dupplicate
|
* encode the result, but we can't afford that or Lua would dupplicate
|
||||||
* every chunk we received.
|
* every chunk we received.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -256,7 +351,7 @@ static int mime_global_b64(lua_State *L)
|
|||||||
{
|
{
|
||||||
UC atom[3];
|
UC atom[3];
|
||||||
size_t isize = 0, asize = 0;
|
size_t isize = 0, asize = 0;
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||||
const UC *last = input + isize;
|
const UC *last = input + isize;
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
/* end-of-input blackhole */
|
/* end-of-input blackhole */
|
||||||
@@ -265,22 +360,27 @@ static int mime_global_b64(lua_State *L)
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
/* make sure we don't confuse buffer stuff with arguments */
|
||||||
|
lua_settop(L, 2);
|
||||||
/* process first part of the input */
|
/* process first part of the input */
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = b64encode(*input++, atom, asize, &buffer);
|
asize = b64encode(*input++, atom, asize, &buffer);
|
||||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||||
/* if second part is nil, we are done */
|
/* if second part is nil, we are done */
|
||||||
if (!input) {
|
if (!input) {
|
||||||
|
size_t osize = 0;
|
||||||
asize = b64pad(atom, asize, &buffer);
|
asize = b64pad(atom, asize, &buffer);
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
/* if the output is empty and the input is nil, return nil */
|
||||||
|
lua_tolstring(L, -1, &osize);
|
||||||
|
if (osize == 0) lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* otherwise process the second part */
|
/* otherwise process the second part */
|
||||||
last = input + isize;
|
last = input + isize;
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = b64encode(*input++, atom, asize, &buffer);
|
asize = b64encode(*input++, atom, asize, &buffer);
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
lua_pushlstring(L, (char *) atom, asize);
|
lua_pushlstring(L, (char *) atom, asize);
|
||||||
@@ -297,7 +397,7 @@ static int mime_global_unb64(lua_State *L)
|
|||||||
{
|
{
|
||||||
UC atom[4];
|
UC atom[4];
|
||||||
size_t isize = 0, asize = 0;
|
size_t isize = 0, asize = 0;
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||||
const UC *last = input + isize;
|
const UC *last = input + isize;
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
/* end-of-input blackhole */
|
/* end-of-input blackhole */
|
||||||
@@ -306,21 +406,26 @@ static int mime_global_unb64(lua_State *L)
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
/* make sure we don't confuse buffer stuff with arguments */
|
||||||
|
lua_settop(L, 2);
|
||||||
/* process first part of the input */
|
/* process first part of the input */
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = b64decode(*input++, atom, asize, &buffer);
|
asize = b64decode(*input++, atom, asize, &buffer);
|
||||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||||
/* if second is nil, we are done */
|
/* if second is nil, we are done */
|
||||||
if (!input) {
|
if (!input) {
|
||||||
|
size_t osize = 0;
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
/* if the output is empty and the input is nil, return nil */
|
||||||
|
lua_tolstring(L, -1, &osize);
|
||||||
|
if (osize == 0) lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* otherwise, process the rest of the input */
|
/* otherwise, process the rest of the input */
|
||||||
last = input + isize;
|
last = input + isize;
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = b64decode(*input++, atom, asize, &buffer);
|
asize = b64decode(*input++, atom, asize, &buffer);
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
lua_pushlstring(L, (char *) atom, asize);
|
lua_pushlstring(L, (char *) atom, asize);
|
||||||
@@ -336,48 +441,80 @@ static int mime_global_unb64(lua_State *L)
|
|||||||
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
|
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
|
||||||
* encoded lines must be no longer than 76 not counting CRLF
|
* encoded lines must be no longer than 76 not counting CRLF
|
||||||
* soft line-break are =CRLF
|
* soft line-break are =CRLF
|
||||||
* To encode one byte, we need to see the next two.
|
* To encode one byte, we need to see the next two.
|
||||||
* Worst case is when we see a space, and wonder if a CRLF is comming
|
* Worst case is when we see a space, and wonder if a CRLF is comming
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
|
#if 0
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Split quoted-printable characters into classes
|
* Split quoted-printable characters into classes
|
||||||
* Precompute reverse map for encoding
|
* Precompute reverse map for encoding
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void qpsetup(UC *qpclass, UC *qpunbase)
|
static void qpsetup(UC *cl, UC *unbase)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED;
|
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
|
||||||
for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN;
|
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
|
||||||
for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN;
|
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
|
||||||
qpclass['\t'] = QP_IF_LAST;
|
cl['\t'] = QP_IF_LAST;
|
||||||
qpclass[' '] = QP_IF_LAST;
|
cl[' '] = QP_IF_LAST;
|
||||||
qpclass['\r'] = QP_CR;
|
cl['\r'] = QP_CR;
|
||||||
for (i = 0; i < 256; i++) qpunbase[i] = 255;
|
for (i = 0; i < 256; i++) unbase[i] = 255;
|
||||||
qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2;
|
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
|
||||||
qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5;
|
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
|
||||||
qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8;
|
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
|
||||||
qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10;
|
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
|
||||||
qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12;
|
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
|
||||||
qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13;
|
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
|
||||||
qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15;
|
unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
|
||||||
qpunbase['f'] = 15;
|
unbase['f'] = 15;
|
||||||
|
|
||||||
|
printf("static UC qpclass[] = {");
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
if (i % 6 == 0) {
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
switch(cl[i]) {
|
||||||
|
case QP_QUOTED:
|
||||||
|
printf("QP_QUOTED, ");
|
||||||
|
break;
|
||||||
|
case QP_PLAIN:
|
||||||
|
printf("QP_PLAIN, ");
|
||||||
|
break;
|
||||||
|
case QP_CR:
|
||||||
|
printf("QP_CR, ");
|
||||||
|
break;
|
||||||
|
case QP_IF_LAST:
|
||||||
|
printf("QP_IF_LAST, ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n};\n");
|
||||||
|
|
||||||
|
printf("static const UC qpunbase[] = {");
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
int c = qpunbase[i];
|
||||||
|
printf("%d, ", c);
|
||||||
|
}
|
||||||
|
printf("\";\n");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Output one character in form =XX
|
* Output one character in form =XX
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void qpquote(UC c, luaL_Buffer *buffer)
|
static void qpquote(UC c, luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
luaL_putchar(buffer, '=');
|
luaL_addchar(buffer, '=');
|
||||||
luaL_putchar(buffer, qpbase[c >> 4]);
|
luaL_addchar(buffer, qpbase[c >> 4]);
|
||||||
luaL_putchar(buffer, qpbase[c & 0x0F]);
|
luaL_addchar(buffer, qpbase[c & 0x0F]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Accumulate characters until we are sure about how to deal with them.
|
* Accumulate characters until we are sure about how to deal with them.
|
||||||
* Once we are sure, output to the buffer, in the correct form.
|
* Once we are sure, output to the buffer, in the correct form.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t qpencode(UC c, UC *input, size_t size,
|
static size_t qpencode(UC c, UC *input, size_t size,
|
||||||
const char *marker, luaL_Buffer *buffer)
|
const char *marker, luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
input[size++] = c;
|
input[size++] = c;
|
||||||
@@ -400,7 +537,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
|
|||||||
qpquote(input[0], buffer);
|
qpquote(input[0], buffer);
|
||||||
luaL_addstring(buffer, marker);
|
luaL_addstring(buffer, marker);
|
||||||
return 0;
|
return 0;
|
||||||
} else luaL_putchar(buffer, input[0]);
|
} else luaL_addchar(buffer, input[0]);
|
||||||
break;
|
break;
|
||||||
/* might have to be quoted always */
|
/* might have to be quoted always */
|
||||||
case QP_QUOTED:
|
case QP_QUOTED:
|
||||||
@@ -408,7 +545,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
|
|||||||
break;
|
break;
|
||||||
/* might never have to be quoted */
|
/* might never have to be quoted */
|
||||||
default:
|
default:
|
||||||
luaL_putchar(buffer, input[0]);
|
luaL_addchar(buffer, input[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input[0] = input[1]; input[1] = input[2];
|
input[0] = input[1]; input[1] = input[2];
|
||||||
@@ -418,13 +555,13 @@ static size_t qpencode(UC c, UC *input, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Deal with the final characters
|
* Deal with the final characters
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
|
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]);
|
if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
|
||||||
else qpquote(input[i], buffer);
|
else qpquote(input[i], buffer);
|
||||||
}
|
}
|
||||||
if (size > 0) luaL_addstring(buffer, EQCRLF);
|
if (size > 0) luaL_addstring(buffer, EQCRLF);
|
||||||
@@ -435,16 +572,15 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
|
|||||||
* Incrementally converts a string to quoted-printable
|
* Incrementally converts a string to quoted-printable
|
||||||
* A, B = qp(C, D, marker)
|
* A, B = qp(C, D, marker)
|
||||||
* Marker is the text to be used to replace CRLF sequences found in A.
|
* Marker is the text to be used to replace CRLF sequences found in A.
|
||||||
* A is the encoded version of the largest prefix of C .. D that
|
* A is the encoded version of the largest prefix of C .. D that
|
||||||
* can be encoded without doubts.
|
* can be encoded without doubts.
|
||||||
* B has the remaining bytes of C .. D, *without* encoding.
|
* B has the remaining bytes of C .. D, *without* encoding.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int mime_global_qp(lua_State *L)
|
static int mime_global_qp(lua_State *L)
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t asize = 0, isize = 0;
|
size_t asize = 0, isize = 0;
|
||||||
UC atom[3];
|
UC atom[3];
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||||
const UC *last = input + isize;
|
const UC *last = input + isize;
|
||||||
const char *marker = luaL_optstring(L, 3, CRLF);
|
const char *marker = luaL_optstring(L, 3, CRLF);
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
@@ -454,11 +590,13 @@ static int mime_global_qp(lua_State *L)
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
/* make sure we don't confuse buffer stuff with arguments */
|
||||||
|
lua_settop(L, 3);
|
||||||
/* process first part of input */
|
/* process first part of input */
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
||||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||||
/* if second part is nil, we are done */
|
/* if second part is nil, we are done */
|
||||||
if (!input) {
|
if (!input) {
|
||||||
asize = qppad(atom, asize, &buffer);
|
asize = qppad(atom, asize, &buffer);
|
||||||
@@ -478,7 +616,7 @@ static int mime_global_qp(lua_State *L)
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Accumulate characters until we are sure about how to deal with them.
|
* Accumulate characters until we are sure about how to deal with them.
|
||||||
* Once we are sure, output the to the buffer, in the correct form.
|
* Once we are sure, output the to the buffer, in the correct form.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
||||||
int d;
|
int d;
|
||||||
@@ -486,23 +624,23 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
|||||||
/* deal with all characters we can deal */
|
/* deal with all characters we can deal */
|
||||||
switch (input[0]) {
|
switch (input[0]) {
|
||||||
/* if we have an escape character */
|
/* if we have an escape character */
|
||||||
case '=':
|
case '=':
|
||||||
if (size < 3) return size;
|
if (size < 3) return size;
|
||||||
/* eliminate soft line break */
|
/* eliminate soft line break */
|
||||||
if (input[1] == '\r' && input[2] == '\n') return 0;
|
if (input[1] == '\r' && input[2] == '\n') return 0;
|
||||||
/* decode quoted representation */
|
/* decode quoted representation */
|
||||||
c = qpunbase[input[1]]; d = qpunbase[input[2]];
|
c = qpunbase[input[1]]; d = qpunbase[input[2]];
|
||||||
/* if it is an invalid, do not decode */
|
/* if it is an invalid, do not decode */
|
||||||
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
|
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
|
||||||
else luaL_putchar(buffer, (c << 4) + d);
|
else luaL_addchar(buffer, (char) ((c << 4) + d));
|
||||||
return 0;
|
return 0;
|
||||||
case '\r':
|
case '\r':
|
||||||
if (size < 2) return size;
|
if (size < 2) return size;
|
||||||
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
|
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
|
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
|
||||||
luaL_putchar(buffer, input[0]);
|
luaL_addchar(buffer, input[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,15 +648,15 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Incrementally decodes a string in quoted-printable
|
* Incrementally decodes a string in quoted-printable
|
||||||
* A, B = qp(C, D)
|
* A, B = qp(C, D)
|
||||||
* A is the decoded version of the largest prefix of C .. D that
|
* A is the decoded version of the largest prefix of C .. D that
|
||||||
* can be decoded without doubts.
|
* can be decoded without doubts.
|
||||||
* B has the remaining bytes of C .. D, *without* decoding.
|
* B has the remaining bytes of C .. D, *without* decoding.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int mime_global_unqp(lua_State *L)
|
static int mime_global_unqp(lua_State *L)
|
||||||
{
|
{
|
||||||
size_t asize = 0, isize = 0;
|
size_t asize = 0, isize = 0;
|
||||||
UC atom[3];
|
UC atom[3];
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||||
const UC *last = input + isize;
|
const UC *last = input + isize;
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
/* end-of-input blackhole */
|
/* end-of-input blackhole */
|
||||||
@@ -527,18 +665,20 @@ static int mime_global_unqp(lua_State *L)
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
/* make sure we don't confuse buffer stuff with arguments */
|
||||||
|
lua_settop(L, 2);
|
||||||
/* process first part of input */
|
/* process first part of input */
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last)
|
while (input < last)
|
||||||
asize = qpdecode(*input++, atom, asize, &buffer);
|
asize = qpdecode(*input++, atom, asize, &buffer);
|
||||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||||
/* if second part is nil, we are done */
|
/* if second part is nil, we are done */
|
||||||
if (!input) {
|
if (!input) {
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* otherwise process rest of input */
|
/* otherwise process rest of input */
|
||||||
last = input + isize;
|
last = input + isize;
|
||||||
while (input < last)
|
while (input < last)
|
||||||
@@ -551,9 +691,9 @@ static int mime_global_unqp(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Incrementally breaks a quoted-printed string into lines
|
* Incrementally breaks a quoted-printed string into lines
|
||||||
* A, n = qpwrp(l, B, length)
|
* A, n = qpwrp(l, B, length)
|
||||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||||
* 'l' is how many bytes are left for the first line of B.
|
* 'l' is how many bytes are left for the first line of B.
|
||||||
* 'n' is the number of bytes left in the last line of A.
|
* 'n' is the number of bytes left in the last line of A.
|
||||||
* There are two complications: lines can't be broken in the middle
|
* There are two complications: lines can't be broken in the middle
|
||||||
* of an encoded =XX, and there might be line breaks already
|
* of an encoded =XX, and there might be line breaks already
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -561,7 +701,7 @@ static int mime_global_qpwrp(lua_State *L)
|
|||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int left = (int) luaL_checknumber(L, 1);
|
int left = (int) luaL_checknumber(L, 1);
|
||||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||||
const UC *last = input + size;
|
const UC *last = input + size;
|
||||||
int length = (int) luaL_optnumber(L, 3, 76);
|
int length = (int) luaL_optnumber(L, 3, 76);
|
||||||
luaL_Buffer buffer;
|
luaL_Buffer buffer;
|
||||||
@@ -586,16 +726,16 @@ static int mime_global_qpwrp(lua_State *L)
|
|||||||
if (left <= 3) {
|
if (left <= 3) {
|
||||||
left = length;
|
left = length;
|
||||||
luaL_addstring(&buffer, EQCRLF);
|
luaL_addstring(&buffer, EQCRLF);
|
||||||
}
|
}
|
||||||
luaL_putchar(&buffer, *input);
|
luaL_addchar(&buffer, *input);
|
||||||
left--;
|
left--;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (left <= 1) {
|
if (left <= 1) {
|
||||||
left = length;
|
left = length;
|
||||||
luaL_addstring(&buffer, EQCRLF);
|
luaL_addstring(&buffer, EQCRLF);
|
||||||
}
|
}
|
||||||
luaL_putchar(&buffer, *input);
|
luaL_addchar(&buffer, *input);
|
||||||
left--;
|
left--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -618,7 +758,7 @@ static int mime_global_qpwrp(lua_State *L)
|
|||||||
* last is the previous character
|
* last is the previous character
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#define eolcandidate(c) (c == '\r' || c == '\n')
|
#define eolcandidate(c) (c == '\r' || c == '\n')
|
||||||
static int eolprocess(int c, int last, const char *marker,
|
static int eolprocess(int c, int last, const char *marker,
|
||||||
luaL_Buffer *buffer)
|
luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
if (eolcandidate(c)) {
|
if (eolcandidate(c)) {
|
||||||
@@ -630,21 +770,21 @@ static int eolprocess(int c, int last, const char *marker,
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
luaL_putchar(buffer, c);
|
luaL_addchar(buffer, (char) c);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Converts a string to uniform EOL convention.
|
* Converts a string to uniform EOL convention.
|
||||||
* A, n = eol(o, B, marker)
|
* A, n = eol(o, B, marker)
|
||||||
* A is the converted version of the largest prefix of B that can be
|
* A is the converted version of the largest prefix of B that can be
|
||||||
* converted unambiguously. 'o' is the context returned by the previous
|
* converted unambiguously. 'o' is the context returned by the previous
|
||||||
* call. 'n' is the new context.
|
* call. 'n' is the new context.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int mime_global_eol(lua_State *L)
|
static int mime_global_eol(lua_State *L)
|
||||||
{
|
{
|
||||||
int ctx = luaL_checkint(L, 1);
|
int ctx = (int) luaL_checkinteger(L, 1);
|
||||||
size_t isize = 0;
|
size_t isize = 0;
|
||||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||||
const char *last = input + isize;
|
const char *last = input + isize;
|
||||||
@@ -666,19 +806,20 @@ static int mime_global_eol(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Takes one byte and stuff it if needed.
|
* Takes one byte and stuff it if needed.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
|
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
|
||||||
{
|
{
|
||||||
luaL_putchar(buffer, c);
|
luaL_addchar(buffer, (char) c);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\r':
|
case '\r':
|
||||||
return 1;
|
return 1;
|
||||||
case '\n':
|
case '\n':
|
||||||
return (state == 1)? 2: 0;
|
return (state == 1)? 2: 0;
|
||||||
case '.':
|
case '.':
|
||||||
if (state == 2)
|
if (state == 2)
|
||||||
luaL_putchar(buffer, '.');
|
luaL_addchar(buffer, '.');
|
||||||
|
/* Falls through. */
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -702,10 +843,10 @@ static int mime_global_dot(lua_State *L)
|
|||||||
}
|
}
|
||||||
/* process all input */
|
/* process all input */
|
||||||
luaL_buffinit(L, &buffer);
|
luaL_buffinit(L, &buffer);
|
||||||
while (input < last)
|
while (input < last)
|
||||||
state = dot(*input++, state, &buffer);
|
state = dot(*input++, state, &buffer);
|
||||||
luaL_pushresult(&buffer);
|
luaL_pushresult(&buffer);
|
||||||
lua_pushnumber(L, state);
|
lua_pushnumber(L, (lua_Number) state);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
src/mime.h
17
src/mime.h
@@ -7,25 +7,16 @@
|
|||||||
* This module provides functions to implement transfer content encodings
|
* This module provides functions to implement transfer content encodings
|
||||||
* and formatting conforming to RFC 2045. It is used by mime.lua, which
|
* and formatting conforming to RFC 2045. It is used by mime.lua, which
|
||||||
* provide a higher level interface to this functionality.
|
* provide a higher level interface to this functionality.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Current MIME library version
|
* Current MIME library version
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#define MIME_VERSION "MIME 1.0.2"
|
#define MIME_VERSION "MIME 1.0.3"
|
||||||
#define MIME_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab"
|
#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab"
|
||||||
#define MIME_AUTHORS "Diego Nehab"
|
#define MIME_AUTHORS "Diego Nehab"
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
LUASOCKET_API int luaopen_mime_core(lua_State *L);
|
||||||
* This macro prefixes all exported API functions
|
|
||||||
\*-------------------------------------------------------------------------*/
|
|
||||||
#ifndef MIME_API
|
|
||||||
#define MIME_API extern
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MIME_API int luaopen_mime_core(lua_State *L);
|
|
||||||
|
|
||||||
#endif /* MIME_H */
|
#endif /* MIME_H */
|
||||||
|
|||||||
40
src/mime.lua
40
src/mime.lua
@@ -2,7 +2,6 @@
|
|||||||
-- MIME support for the Lua language.
|
-- MIME support for the Lua language.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- Conforming to RFCs 2045-2049
|
-- Conforming to RFCs 2045-2049
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -11,14 +10,15 @@
|
|||||||
local base = _G
|
local base = _G
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
local mime = require("mime.core")
|
local mime = require("mime.core")
|
||||||
local io = require("io")
|
|
||||||
local string = require("string")
|
local string = require("string")
|
||||||
module("mime")
|
local _M = mime
|
||||||
|
|
||||||
-- encode, decode and wrap algorithm tables
|
-- encode, decode and wrap algorithm tables
|
||||||
encodet = {}
|
local encodet, decodet, wrapt = {},{},{}
|
||||||
decodet = {}
|
|
||||||
wrapt = {}
|
_M.encodet = encodet
|
||||||
|
_M.decodet = decodet
|
||||||
|
_M.wrapt = wrapt
|
||||||
|
|
||||||
-- creates a function that chooses a filter by name from a given table
|
-- creates a function that chooses a filter by name from a given table
|
||||||
local function choose(table)
|
local function choose(table)
|
||||||
@@ -35,21 +35,21 @@ end
|
|||||||
|
|
||||||
-- define the encoding filters
|
-- define the encoding filters
|
||||||
encodet['base64'] = function()
|
encodet['base64'] = function()
|
||||||
return ltn12.filter.cycle(b64, "")
|
return ltn12.filter.cycle(_M.b64, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
encodet['quoted-printable'] = function(mode)
|
encodet['quoted-printable'] = function(mode)
|
||||||
return ltn12.filter.cycle(qp, "",
|
return ltn12.filter.cycle(_M.qp, "",
|
||||||
(mode == "binary") and "=0D=0A" or "\r\n")
|
(mode == "binary") and "=0D=0A" or "\r\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- define the decoding filters
|
-- define the decoding filters
|
||||||
decodet['base64'] = function()
|
decodet['base64'] = function()
|
||||||
return ltn12.filter.cycle(unb64, "")
|
return ltn12.filter.cycle(_M.unb64, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
decodet['quoted-printable'] = function()
|
decodet['quoted-printable'] = function()
|
||||||
return ltn12.filter.cycle(unqp, "")
|
return ltn12.filter.cycle(_M.unqp, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function format(chunk)
|
local function format(chunk)
|
||||||
@@ -62,26 +62,28 @@ end
|
|||||||
-- define the line-wrap filters
|
-- define the line-wrap filters
|
||||||
wrapt['text'] = function(length)
|
wrapt['text'] = function(length)
|
||||||
length = length or 76
|
length = length or 76
|
||||||
return ltn12.filter.cycle(wrp, length, length)
|
return ltn12.filter.cycle(_M.wrp, length, length)
|
||||||
end
|
end
|
||||||
wrapt['base64'] = wrapt['text']
|
wrapt['base64'] = wrapt['text']
|
||||||
wrapt['default'] = wrapt['text']
|
wrapt['default'] = wrapt['text']
|
||||||
|
|
||||||
wrapt['quoted-printable'] = function()
|
wrapt['quoted-printable'] = function()
|
||||||
return ltn12.filter.cycle(qpwrp, 76, 76)
|
return ltn12.filter.cycle(_M.qpwrp, 76, 76)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- function that choose the encoding, decoding or wrap algorithm
|
-- function that choose the encoding, decoding or wrap algorithm
|
||||||
encode = choose(encodet)
|
_M.encode = choose(encodet)
|
||||||
decode = choose(decodet)
|
_M.decode = choose(decodet)
|
||||||
wrap = choose(wrapt)
|
_M.wrap = choose(wrapt)
|
||||||
|
|
||||||
-- define the end-of-line normalization filter
|
-- define the end-of-line normalization filter
|
||||||
function normalize(marker)
|
function _M.normalize(marker)
|
||||||
return ltn12.filter.cycle(eol, 0, marker)
|
return ltn12.filter.cycle(_M.eol, 0, marker)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- high level stuffing filter
|
-- high level stuffing filter
|
||||||
function stuff()
|
function _M.stuff()
|
||||||
return ltn12.filter.cycle(dot, 2)
|
return ltn12.filter.cycle(_M.dot, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
375
src/options.c
375
src/options.c
@@ -1,25 +1,26 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Common option interface
|
* Common option interface
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <string.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "auxiliar.h"
|
#include "auxiliar.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "inet.h"
|
#include "inet.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal functions prototypes
|
* Internal functions prototypes
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
|
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
|
||||||
|
static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name);
|
||||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
|
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
|
||||||
static int opt_set(lua_State *L, p_socket ps, int level, int name,
|
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
|
||||||
|
static int opt_setint(lua_State *L, p_socket ps, int level, int name);
|
||||||
|
static int opt_getint(lua_State *L, p_socket ps, int level, int name);
|
||||||
|
static int opt_set(lua_State *L, p_socket ps, int level, int name,
|
||||||
void *val, int len);
|
void *val, int len);
|
||||||
|
static int opt_get(lua_State *L, p_socket ps, int level, int name,
|
||||||
|
void *val, int* len);
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Exported functions
|
* Exported functions
|
||||||
@@ -33,103 +34,380 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
|
|||||||
while (opt->name && strcmp(name, opt->name))
|
while (opt->name && strcmp(name, opt->name))
|
||||||
opt++;
|
opt++;
|
||||||
if (!opt->func) {
|
if (!opt->func) {
|
||||||
char msg[45];
|
char msg[57];
|
||||||
sprintf(msg, "unsupported option `%.35s'", name);
|
sprintf(msg, "unsupported option `%.35s'", name);
|
||||||
luaL_argerror(L, 2, msg);
|
luaL_argerror(L, 2, msg);
|
||||||
}
|
}
|
||||||
return opt->func(L, ps);
|
return opt->func(L, ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
|
||||||
|
{
|
||||||
|
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||||
|
while (opt->name && strcmp(name, opt->name))
|
||||||
|
opt++;
|
||||||
|
if (!opt->func) {
|
||||||
|
char msg[57];
|
||||||
|
sprintf(msg, "unsupported option `%.35s'", name);
|
||||||
|
luaL_argerror(L, 2, msg);
|
||||||
|
}
|
||||||
|
return opt->func(L, ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
/* enables reuse of local address */
|
/* enables reuse of local address */
|
||||||
int opt_reuseaddr(lua_State *L, p_socket ps)
|
int opt_set_reuseaddr(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disables the Naggle algorithm */
|
int opt_get_reuseaddr(lua_State *L, p_socket ps)
|
||||||
int opt_tcp_nodelay(lua_State *L, p_socket ps)
|
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_keepalive(lua_State *L, p_socket ps)
|
// -------------------------------------------------------
|
||||||
|
/* enables reuse of local port */
|
||||||
|
int opt_set_reuseport(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_dontroute(lua_State *L, p_socket ps)
|
int opt_get_reuseport(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
/* disables the Nagle algorithm */
|
||||||
|
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
#ifdef TCP_KEEPIDLE
|
||||||
|
|
||||||
|
int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
|
||||||
|
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
#ifdef TCP_KEEPINTVL
|
||||||
|
|
||||||
|
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_keepalive(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_keepalive(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_dontroute(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_broadcast(lua_State *L, p_socket ps)
|
int opt_get_dontroute(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_broadcast(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_ip_multicast_loop(lua_State *L, p_socket ps)
|
int opt_get_broadcast(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_recv_buf_size(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_recv_buf_size(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_get_send_buf_size(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_send_buf_size(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_linger(lua_State *L, p_socket ps)
|
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_linger(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
struct linger li; /* obj, name, table */
|
struct linger li; /* obj, name, table */
|
||||||
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
|
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||||
lua_pushstring(L, "on");
|
lua_pushstring(L, "on");
|
||||||
lua_gettable(L, 3);
|
lua_gettable(L, 3);
|
||||||
if (!lua_isboolean(L, -1))
|
if (!lua_isboolean(L, -1))
|
||||||
luaL_argerror(L, 3, "boolean 'on' field expected");
|
luaL_argerror(L, 3, "boolean 'on' field expected");
|
||||||
li.l_onoff = (u_short) lua_toboolean(L, -1);
|
li.l_onoff = (u_short) lua_toboolean(L, -1);
|
||||||
lua_pushstring(L, "timeout");
|
lua_pushstring(L, "timeout");
|
||||||
lua_gettable(L, 3);
|
lua_gettable(L, 3);
|
||||||
if (!lua_isnumber(L, -1))
|
if (!lua_isnumber(L, -1))
|
||||||
luaL_argerror(L, 3, "number 'timeout' field expected");
|
luaL_argerror(L, 3, "number 'timeout' field expected");
|
||||||
li.l_linger = (u_short) lua_tonumber(L, -1);
|
li.l_linger = (u_short) lua_tonumber(L, -1);
|
||||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
|
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_ip_multicast_ttl(lua_State *L, p_socket ps)
|
int opt_get_linger(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
|
struct linger li; /* obj, name */
|
||||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val));
|
int len = sizeof(li);
|
||||||
|
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushboolean(L, li.l_onoff);
|
||||||
|
lua_setfield(L, -2, "on");
|
||||||
|
lua_pushinteger(L, li.l_linger);
|
||||||
|
lua_setfield(L, -2, "timeout");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_ip_add_membership(lua_State *L, p_socket ps)
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
|
||||||
|
struct in_addr val;
|
||||||
|
val.s_addr = htonl(INADDR_ANY);
|
||||||
|
if (strcmp(address, "*") && !inet_aton(address, &val))
|
||||||
|
luaL_argerror(L, 3, "ip expected");
|
||||||
|
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
|
||||||
|
(char *) &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
struct in_addr val;
|
||||||
|
socklen_t len = sizeof(val);
|
||||||
|
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "getsockopt failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushstring(L, inet_ntoa(val));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt_ip_drop_membersip(lua_State *L, p_socket ps)
|
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
|
||||||
{
|
{
|
||||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
|
||||||
|
}
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_get_ip6_v6only(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
int opt_get_error(lua_State *L, p_socket ps)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
socklen_t len = sizeof(val);
|
||||||
|
if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "getsockopt failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushstring(L, socket_strerror(val));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Auxiliar functions
|
* Auxiliar functions
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
|
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
|
||||||
{
|
{
|
||||||
struct ip_mreq val; /* obj, name, table */
|
struct ip_mreq val; /* obj, name, table */
|
||||||
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
|
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||||
lua_pushstring(L, "multiaddr");
|
lua_pushstring(L, "multiaddr");
|
||||||
lua_gettable(L, 3);
|
lua_gettable(L, 3);
|
||||||
if (!lua_isstring(L, -1))
|
if (!lua_isstring(L, -1))
|
||||||
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
||||||
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
||||||
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||||
lua_pushstring(L, "interface");
|
lua_pushstring(L, "interface");
|
||||||
lua_gettable(L, 3);
|
lua_gettable(L, 3);
|
||||||
if (!lua_isstring(L, -1))
|
if (!lua_isstring(L, -1))
|
||||||
luaL_argerror(L, 3, "string 'interface' field expected");
|
luaL_argerror(L, 3, "string 'interface' field expected");
|
||||||
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
if (strcmp(lua_tostring(L, -1), "*") &&
|
if (strcmp(lua_tostring(L, -1), "*") &&
|
||||||
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
||||||
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
||||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
|
||||||
|
{
|
||||||
|
struct ipv6_mreq val; /* obj, opt-name, table */
|
||||||
|
memset(&val, 0, sizeof(val));
|
||||||
|
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||||
|
lua_pushstring(L, "multiaddr");
|
||||||
|
lua_gettable(L, 3);
|
||||||
|
if (!lua_isstring(L, -1))
|
||||||
|
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
||||||
|
if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
|
||||||
|
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||||
|
lua_pushstring(L, "interface");
|
||||||
|
lua_gettable(L, 3);
|
||||||
|
/* By default we listen to interface on default route
|
||||||
|
* (sigh). However, interface= can override it. We should
|
||||||
|
* support either number, or name for it. Waiting for
|
||||||
|
* windows port of if_nametoindex */
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
if (lua_isnumber(L, -1)) {
|
||||||
|
val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1);
|
||||||
|
} else
|
||||||
|
luaL_argerror(L, -1, "number 'interface' field expected");
|
||||||
|
}
|
||||||
|
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
|
||||||
|
{
|
||||||
|
socklen_t socklen = *len;
|
||||||
|
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "getsockopt failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
*len = socklen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
|
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
|
||||||
{
|
{
|
||||||
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
|
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
|
||||||
@@ -141,9 +419,36 @@ int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
int len = sizeof(val);
|
||||||
|
int err = opt_get(L, ps, level, name, (char *) &val, &len);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
lua_pushboolean(L, val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
|
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
|
||||||
{
|
{
|
||||||
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
|
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
|
||||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int opt_getint(lua_State *L, p_socket ps, int level, int name)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
int len = sizeof(val);
|
||||||
|
int err = opt_get(L, ps, level, name, (char *) &val, &len);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
lua_pushnumber(L, val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int opt_setint(lua_State *L, p_socket ps, int level, int name)
|
||||||
|
{
|
||||||
|
int val = (int) lua_tonumber(L, 3); /* obj, name, int */
|
||||||
|
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
*
|
*
|
||||||
* This module provides a common interface to socket options, used mainly by
|
* This module provides a common interface to socket options, used mainly by
|
||||||
* modules UDP and TCP.
|
* modules UDP and TCP.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
/* option registry */
|
/* option registry */
|
||||||
@@ -20,20 +18,85 @@ typedef struct t_opt {
|
|||||||
} t_opt;
|
} t_opt;
|
||||||
typedef t_opt *p_opt;
|
typedef t_opt *p_opt;
|
||||||
|
|
||||||
/* supported options */
|
#ifndef _WIN32
|
||||||
int opt_dontroute(lua_State *L, p_socket ps);
|
#pragma GCC visibility push(hidden)
|
||||||
int opt_broadcast(lua_State *L, p_socket ps);
|
#endif
|
||||||
int opt_reuseaddr(lua_State *L, p_socket ps);
|
|
||||||
int opt_tcp_nodelay(lua_State *L, p_socket ps);
|
|
||||||
int opt_keepalive(lua_State *L, p_socket ps);
|
|
||||||
int opt_linger(lua_State *L, p_socket ps);
|
|
||||||
int opt_reuseaddr(lua_State *L, p_socket ps);
|
|
||||||
int opt_ip_multicast_ttl(lua_State *L, p_socket ps);
|
|
||||||
int opt_ip_multicast_loop(lua_State *L, p_socket ps);
|
|
||||||
int opt_ip_add_membership(lua_State *L, p_socket ps);
|
|
||||||
int opt_ip_drop_membersip(lua_State *L, p_socket ps);
|
|
||||||
|
|
||||||
/* invokes the appropriate option handler */
|
|
||||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
|
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
|
||||||
|
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_reuseaddr(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_reuseaddr(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_reuseport(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_reuseport(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
#ifdef TCP_KEEPIDLE
|
||||||
|
int opt_set_tcp_keepidle(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_tcp_keepidle(lua_State *L, p_socket ps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
int opt_set_tcp_keepcnt(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TCP_KEEPINTVL
|
||||||
|
int opt_set_tcp_keepintvl(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int opt_set_keepalive(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_keepalive(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_dontroute(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_dontroute(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_broadcast(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_broadcast(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_recv_buf_size(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_recv_buf_size(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_send_buf_size(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_send_buf_size(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_linger(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_linger(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
|
||||||
|
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
|
||||||
|
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
|
||||||
|
int opt_get_ip6_v6only(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
int opt_get_error(lua_State *L, p_socket ps);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
28
src/pierror.h
Normal file
28
src/pierror.h
Normal 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
|
||||||
90
src/select.c
90
src/select.c
@@ -1,45 +1,45 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Select implementation
|
* Select implementation
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <string.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
#include "select.h"
|
#include "select.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal function prototypes.
|
* Internal function prototypes.
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static t_socket getfd(lua_State *L);
|
static t_socket getfd(lua_State *L);
|
||||||
static int dirty(lua_State *L);
|
static int dirty(lua_State *L);
|
||||||
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
|
static void collect_fd(lua_State *L, int tab, int itab,
|
||||||
int itab, fd_set *set);
|
fd_set *set, t_socket *max_fd);
|
||||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
|
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
|
||||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||||
int itab, int tab, int start);
|
int itab, int tab, int start);
|
||||||
static void make_assoc(lua_State *L, int tab);
|
static void make_assoc(lua_State *L, int tab);
|
||||||
static int global_select(lua_State *L);
|
static int global_select(lua_State *L);
|
||||||
|
|
||||||
/* functions in library namespace */
|
/* functions in library namespace */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"select", global_select},
|
{"select", global_select},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*=========================================================================*\
|
|
||||||
* Exported functions
|
|
||||||
\*=========================================================================*/
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int select_open(lua_State *L) {
|
int select_open(lua_State *L) {
|
||||||
luaL_openlib(L, NULL, func, 0);
|
lua_pushstring(L, "_SETSIZE");
|
||||||
|
lua_pushinteger(L, FD_SETSIZE);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
lua_pushstring(L, "_SOCKETINVALID");
|
||||||
|
lua_pushinteger(L, SOCKET_INVALID);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
luaL_setfuncs(L, func, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ int select_open(lua_State *L) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_select(lua_State *L) {
|
static int global_select(lua_State *L) {
|
||||||
int rtab, wtab, itab, ret, ndirty;
|
int rtab, wtab, itab, ret, ndirty;
|
||||||
t_socket max_fd;
|
t_socket max_fd = SOCKET_INVALID;
|
||||||
fd_set rset, wset;
|
fd_set rset, wset;
|
||||||
t_timeout tm;
|
t_timeout tm;
|
||||||
double t = luaL_optnumber(L, 3, -1);
|
double t = luaL_optnumber(L, 3, -1);
|
||||||
@@ -60,12 +60,12 @@ static int global_select(lua_State *L) {
|
|||||||
lua_newtable(L); itab = lua_gettop(L);
|
lua_newtable(L); itab = lua_gettop(L);
|
||||||
lua_newtable(L); rtab = lua_gettop(L);
|
lua_newtable(L); rtab = lua_gettop(L);
|
||||||
lua_newtable(L); wtab = lua_gettop(L);
|
lua_newtable(L); wtab = lua_gettop(L);
|
||||||
max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset);
|
collect_fd(L, 1, itab, &rset, &max_fd);
|
||||||
|
collect_fd(L, 2, itab, &wset, &max_fd);
|
||||||
ndirty = check_dirty(L, 1, rtab, &rset);
|
ndirty = check_dirty(L, 1, rtab, &rset);
|
||||||
t = ndirty > 0? 0.0: t;
|
t = ndirty > 0? 0.0: t;
|
||||||
timeout_init(&tm, t, -1);
|
timeout_init(&tm, t, -1);
|
||||||
timeout_markstart(&tm);
|
timeout_markstart(&tm);
|
||||||
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
|
|
||||||
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
|
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
|
||||||
if (ret > 0 || ndirty > 0) {
|
if (ret > 0 || ndirty > 0) {
|
||||||
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
||||||
@@ -77,7 +77,7 @@ static int global_select(lua_State *L) {
|
|||||||
lua_pushstring(L, "timeout");
|
lua_pushstring(L, "timeout");
|
||||||
return 3;
|
return 3;
|
||||||
} else {
|
} else {
|
||||||
lua_pushstring(L, "error");
|
luaL_error(L, "select failed");
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,9 +92,11 @@ static t_socket getfd(lua_State *L) {
|
|||||||
if (!lua_isnil(L, -1)) {
|
if (!lua_isnil(L, -1)) {
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_call(L, 1, 1);
|
lua_call(L, 1, 1);
|
||||||
if (lua_isnumber(L, -1))
|
if (lua_isnumber(L, -1)) {
|
||||||
fd = (t_socket) lua_tonumber(L, -1);
|
double numfd = lua_tonumber(L, -1);
|
||||||
}
|
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
@@ -107,17 +109,19 @@ static int dirty(lua_State *L) {
|
|||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_call(L, 1, 1);
|
lua_call(L, 1, 1);
|
||||||
is = lua_toboolean(L, -1);
|
is = lua_toboolean(L, -1);
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
|
static void collect_fd(lua_State *L, int tab, int itab,
|
||||||
int itab, fd_set *set) {
|
fd_set *set, t_socket *max_fd) {
|
||||||
int i = 1;
|
int i = 1, n = 0;
|
||||||
if (lua_isnil(L, tab))
|
/* nil is the same as an empty table */
|
||||||
return max_fd;
|
if (lua_isnil(L, tab)) return;
|
||||||
while (1) {
|
/* otherwise we need it to be a table */
|
||||||
|
luaL_checktype(L, tab, LUA_TTABLE);
|
||||||
|
for ( ;; ) {
|
||||||
t_socket fd;
|
t_socket fd;
|
||||||
lua_pushnumber(L, i);
|
lua_pushnumber(L, i);
|
||||||
lua_gettable(L, tab);
|
lua_gettable(L, tab);
|
||||||
@@ -125,26 +129,37 @@ static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* getfd figures out if this is a socket */
|
||||||
fd = getfd(L);
|
fd = getfd(L);
|
||||||
if (fd != SOCKET_INVALID) {
|
if (fd != SOCKET_INVALID) {
|
||||||
|
/* make sure we don't overflow the fd_set */
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (n >= FD_SETSIZE)
|
||||||
|
luaL_argerror(L, tab, "too many sockets");
|
||||||
|
#else
|
||||||
|
if (fd >= FD_SETSIZE)
|
||||||
|
luaL_argerror(L, tab, "descriptor too large for set size");
|
||||||
|
#endif
|
||||||
FD_SET(fd, set);
|
FD_SET(fd, set);
|
||||||
if (max_fd == SOCKET_INVALID || max_fd < fd)
|
n++;
|
||||||
max_fd = fd;
|
/* keep track of the largest descriptor so far */
|
||||||
lua_pushnumber(L, fd);
|
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
|
||||||
|
*max_fd = fd;
|
||||||
|
/* make sure we can map back from descriptor to the object */
|
||||||
|
lua_pushnumber(L, (lua_Number) fd);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_settable(L, itab);
|
lua_settable(L, itab);
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
return max_fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
||||||
int ndirty = 0, i = 1;
|
int ndirty = 0, i = 1;
|
||||||
if (lua_isnil(L, tab))
|
if (lua_isnil(L, tab))
|
||||||
return 0;
|
return 0;
|
||||||
while (1) {
|
for ( ;; ) {
|
||||||
t_socket fd;
|
t_socket fd;
|
||||||
lua_pushnumber(L, i);
|
lua_pushnumber(L, i);
|
||||||
lua_gettable(L, tab);
|
lua_gettable(L, tab);
|
||||||
@@ -165,13 +180,13 @@ static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
|||||||
return ndirty;
|
return ndirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||||
int itab, int tab, int start) {
|
int itab, int tab, int start) {
|
||||||
t_socket fd;
|
t_socket fd;
|
||||||
for (fd = 0; fd < max_fd; fd++) {
|
for (fd = 0; fd < max_fd; fd++) {
|
||||||
if (FD_ISSET(fd, set)) {
|
if (FD_ISSET(fd, set)) {
|
||||||
lua_pushnumber(L, ++start);
|
lua_pushnumber(L, ++start);
|
||||||
lua_pushnumber(L, fd);
|
lua_pushnumber(L, (lua_Number) fd);
|
||||||
lua_gettable(L, itab);
|
lua_gettable(L, itab);
|
||||||
lua_settable(L, tab);
|
lua_settable(L, tab);
|
||||||
}
|
}
|
||||||
@@ -181,7 +196,7 @@ static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
|||||||
static void make_assoc(lua_State *L, int tab) {
|
static void make_assoc(lua_State *L, int tab) {
|
||||||
int i = 1, atab;
|
int i = 1, atab;
|
||||||
lua_newtable(L); atab = lua_gettop(L);
|
lua_newtable(L); atab = lua_gettop(L);
|
||||||
while (1) {
|
for ( ;; ) {
|
||||||
lua_pushnumber(L, i);
|
lua_pushnumber(L, i);
|
||||||
lua_gettable(L, tab);
|
lua_gettable(L, tab);
|
||||||
if (!lua_isnil(L, -1)) {
|
if (!lua_isnil(L, -1)) {
|
||||||
@@ -197,4 +212,3 @@ static void make_assoc(lua_State *L, int tab) {
|
|||||||
i = i+1;
|
i = i+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/select.h
10
src/select.h
@@ -8,10 +8,16 @@
|
|||||||
* method getfd() which returns the descriptor to be passed to the
|
* method getfd() which returns the descriptor to be passed to the
|
||||||
* underlying select function. Another method, dirty(), should return
|
* underlying select function. Another method, dirty(), should return
|
||||||
* true if there is data ready for reading (required for buffered input).
|
* true if there is data ready for reading (required for buffered input).
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int select_open(lua_State *L);
|
int select_open(lua_State *L);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* SELECT_H */
|
#endif /* SELECT_H */
|
||||||
|
|||||||
171
src/serial.c
Normal file
171
src/serial.c
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/*=========================================================================*\
|
||||||
|
* Serial stream
|
||||||
|
* LuaSocket toolkit
|
||||||
|
\*=========================================================================*/
|
||||||
|
#include "luasocket.h"
|
||||||
|
|
||||||
|
#include "auxiliar.h"
|
||||||
|
#include "socket.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "unix.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reuses userdata definition from unix.h, since it is useful for all
|
||||||
|
stream-like objects.
|
||||||
|
|
||||||
|
If we stored the serial path for use in error messages or userdata
|
||||||
|
printing, we might need our own userdata definition.
|
||||||
|
|
||||||
|
Group usage is semi-inherited from unix.c, but unnecessary since we
|
||||||
|
have only one object type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Internal function prototypes
|
||||||
|
\*=========================================================================*/
|
||||||
|
static int global_create(lua_State *L);
|
||||||
|
static int meth_send(lua_State *L);
|
||||||
|
static int meth_receive(lua_State *L);
|
||||||
|
static int meth_close(lua_State *L);
|
||||||
|
static int meth_settimeout(lua_State *L);
|
||||||
|
static int meth_getfd(lua_State *L);
|
||||||
|
static int meth_setfd(lua_State *L);
|
||||||
|
static int meth_dirty(lua_State *L);
|
||||||
|
static int meth_getstats(lua_State *L);
|
||||||
|
static int meth_setstats(lua_State *L);
|
||||||
|
|
||||||
|
/* serial object methods */
|
||||||
|
static luaL_Reg serial_methods[] = {
|
||||||
|
{"__gc", meth_close},
|
||||||
|
{"__tostring", auxiliar_tostring},
|
||||||
|
{"close", meth_close},
|
||||||
|
{"dirty", meth_dirty},
|
||||||
|
{"getfd", meth_getfd},
|
||||||
|
{"getstats", meth_getstats},
|
||||||
|
{"setstats", meth_setstats},
|
||||||
|
{"receive", meth_receive},
|
||||||
|
{"send", meth_send},
|
||||||
|
{"setfd", meth_setfd},
|
||||||
|
{"settimeout", meth_settimeout},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Initializes module
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
|
||||||
|
/* create classes */
|
||||||
|
auxiliar_newclass(L, "serial{client}", serial_methods);
|
||||||
|
/* create class groups */
|
||||||
|
auxiliar_add2group(L, "serial{client}", "serial{any}");
|
||||||
|
lua_pushcfunction(L, global_create);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Lua methods
|
||||||
|
\*=========================================================================*/
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Just call buffered IO methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_send(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_send(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_receive(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_receive(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_getstats(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_getstats(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_setstats(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||||
|
return buffer_meth_setstats(L, &un->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Select support methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getfd(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
lua_pushnumber(L, (int) un->sock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||||
|
static int meth_setfd(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meth_dirty(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Closes socket used by object
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_close(lua_State *L)
|
||||||
|
{
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
socket_destroy(&un->sock);
|
||||||
|
lua_pushnumber(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Just call tm methods
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_settimeout(lua_State *L) {
|
||||||
|
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||||
|
return timeout_meth_settimeout(L, &un->tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*=========================================================================*\
|
||||||
|
* Library functions
|
||||||
|
\*=========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Creates a serial object
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int global_create(lua_State *L) {
|
||||||
|
const char* path = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
/* allocate unix object */
|
||||||
|
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||||
|
|
||||||
|
/* open serial device */
|
||||||
|
t_socket sock = open(path, O_NOCTTY|O_RDWR);
|
||||||
|
|
||||||
|
/*printf("open %s on %d\n", path, sock);*/
|
||||||
|
|
||||||
|
if (sock < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
|
lua_pushnumber(L, errno);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
/* set its type as client object */
|
||||||
|
auxiliar_setclass(L, "serial{client}", -1);
|
||||||
|
/* initialize remaining structure fields */
|
||||||
|
socket_setnonblocking(&sock);
|
||||||
|
un->sock = sock;
|
||||||
|
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
|
||||||
|
(p_error) socket_ioerror, &un->sock);
|
||||||
|
timeout_init(&un->tm, -1, -1);
|
||||||
|
buffer_init(&un->buf, &un->io, &un->tm);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
45
src/smtp.lua
45
src/smtp.lua
@@ -2,7 +2,6 @@
|
|||||||
-- SMTP client support for the Lua language.
|
-- SMTP client support for the Lua language.
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -16,23 +15,26 @@ local os = require("os")
|
|||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
local tp = require("socket.tp")
|
local tp = require("socket.tp")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
|
local headers = require("socket.headers")
|
||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
module("socket.smtp")
|
|
||||||
|
socket.smtp = {}
|
||||||
|
local _M = socket.smtp
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Program constants
|
-- Program constants
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- timeout for connection
|
-- timeout for connection
|
||||||
TIMEOUT = 60
|
_M.TIMEOUT = 60
|
||||||
-- default server used to send e-mails
|
-- default server used to send e-mails
|
||||||
SERVER = "localhost"
|
_M.SERVER = "localhost"
|
||||||
-- default port
|
-- default port
|
||||||
PORT = 25
|
_M.PORT = 25
|
||||||
-- domain used in HELO command and default sendmail
|
-- domain used in HELO command and default sendmail
|
||||||
-- If we are under a CGI, try to get from environment
|
-- If we are under a CGI, try to get from environment
|
||||||
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
|
_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost"
|
||||||
-- default time zone (means we don't know)
|
-- default time zone (means we don't know)
|
||||||
ZONE = "-0000"
|
_M.ZONE = "-0000"
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
-- Low level SMTP API
|
-- Low level SMTP API
|
||||||
@@ -41,7 +43,7 @@ local metat = { __index = {} }
|
|||||||
|
|
||||||
function metat.__index:greet(domain)
|
function metat.__index:greet(domain)
|
||||||
self.try(self.tp:check("2.."))
|
self.try(self.tp:check("2.."))
|
||||||
self.try(self.tp:command("EHLO", domain or DOMAIN))
|
self.try(self.tp:command("EHLO", domain or _M.DOMAIN))
|
||||||
return socket.skip(1, self.try(self.tp:check("2..")))
|
return socket.skip(1, self.try(self.tp:check("2..")))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,9 +77,9 @@ end
|
|||||||
function metat.__index:login(user, password)
|
function metat.__index:login(user, password)
|
||||||
self.try(self.tp:command("AUTH", "LOGIN"))
|
self.try(self.tp:command("AUTH", "LOGIN"))
|
||||||
self.try(self.tp:check("3.."))
|
self.try(self.tp:check("3.."))
|
||||||
self.try(self.tp:command(mime.b64(user)))
|
self.try(self.tp:send(mime.b64(user) .. "\r\n"))
|
||||||
self.try(self.tp:check("3.."))
|
self.try(self.tp:check("3.."))
|
||||||
self.try(self.tp:command(mime.b64(password)))
|
self.try(self.tp:send(mime.b64(password) .. "\r\n"))
|
||||||
return self.try(self.tp:check("2.."))
|
return self.try(self.tp:check("2.."))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -111,9 +113,9 @@ function metat.__index:send(mailt)
|
|||||||
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
|
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
|
||||||
end
|
end
|
||||||
|
|
||||||
function open(server, port, create)
|
function _M.open(server, port, create)
|
||||||
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
|
local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,
|
||||||
TIMEOUT, create))
|
_M.TIMEOUT, create))
|
||||||
local s = base.setmetatable({tp = tp}, metat)
|
local s = base.setmetatable({tp = tp}, metat)
|
||||||
-- make sure tp is closed if we get an exception
|
-- make sure tp is closed if we get an exception
|
||||||
s.try = socket.newtry(function()
|
s.try = socket.newtry(function()
|
||||||
@@ -146,10 +148,11 @@ end
|
|||||||
local send_message
|
local send_message
|
||||||
|
|
||||||
-- yield the headers all at once, it's faster
|
-- yield the headers all at once, it's faster
|
||||||
local function send_headers(headers)
|
local function send_headers(tosend)
|
||||||
|
local canonic = headers.canonic
|
||||||
local h = "\r\n"
|
local h = "\r\n"
|
||||||
for i,v in base.pairs(headers) do
|
for f,v in base.pairs(tosend) do
|
||||||
h = i .. ': ' .. v .. "\r\n" .. h
|
h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h
|
||||||
end
|
end
|
||||||
coroutine.yield(h)
|
coroutine.yield(h)
|
||||||
end
|
end
|
||||||
@@ -220,14 +223,14 @@ end
|
|||||||
local function adjust_headers(mesgt)
|
local function adjust_headers(mesgt)
|
||||||
local lower = lower_headers(mesgt.headers)
|
local lower = lower_headers(mesgt.headers)
|
||||||
lower["date"] = lower["date"] or
|
lower["date"] = lower["date"] or
|
||||||
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
|
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE)
|
||||||
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
|
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
|
||||||
-- this can't be overriden
|
-- this can't be overriden
|
||||||
lower["mime-version"] = "1.0"
|
lower["mime-version"] = "1.0"
|
||||||
return lower
|
return lower
|
||||||
end
|
end
|
||||||
|
|
||||||
function message(mesgt)
|
function _M.message(mesgt)
|
||||||
mesgt.headers = adjust_headers(mesgt)
|
mesgt.headers = adjust_headers(mesgt)
|
||||||
-- create and return message source
|
-- create and return message source
|
||||||
local co = coroutine.create(function() send_message(mesgt) end)
|
local co = coroutine.create(function() send_message(mesgt) end)
|
||||||
@@ -241,11 +244,13 @@ end
|
|||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
-- High level SMTP API
|
-- High level SMTP API
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
send = socket.protect(function(mailt)
|
_M.send = socket.protect(function(mailt)
|
||||||
local s = open(mailt.server, mailt.port, mailt.create)
|
local s = _M.open(mailt.server, mailt.port, mailt.create)
|
||||||
local ext = s:greet(mailt.domain)
|
local ext = s:greet(mailt.domain)
|
||||||
s:auth(mailt.user, mailt.password, ext)
|
s:auth(mailt.user, mailt.password, ext)
|
||||||
s:send(mailt)
|
s:send(mailt)
|
||||||
s:quit()
|
s:quit()
|
||||||
return s:close()
|
return s:close()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
return _M
|
||||||
55
src/socket.h
55
src/socket.h
@@ -8,8 +8,6 @@
|
|||||||
* differences. Also, not all *nix platforms behave the same. This module
|
* differences. Also, not all *nix platforms behave the same. This module
|
||||||
* (and the associated usocket.h and wsocket.h) factor these differences and
|
* (and the associated usocket.h and wsocket.h) factor these differences and
|
||||||
* creates a interface compatible with the io.h module.
|
* creates a interface compatible with the io.h module.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
@@ -30,47 +28,46 @@
|
|||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
|
|
||||||
/* we are lazy... */
|
/* convenient shorthand */
|
||||||
typedef struct sockaddr SA;
|
typedef struct sockaddr SA;
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Functions bellow implement a comfortable platform independent
|
* Functions bellow implement a comfortable platform independent
|
||||||
* interface to sockets
|
* interface to sockets
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
|
||||||
int socket_open(void);
|
int socket_open(void);
|
||||||
int socket_close(void);
|
int socket_close(void);
|
||||||
void socket_destroy(p_socket ps);
|
void socket_destroy(p_socket ps);
|
||||||
void socket_shutdown(p_socket ps, int how);
|
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_timeout tm);
|
||||||
int socket_sendto(p_socket ps, const char *data, size_t count,
|
|
||||||
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
|
|
||||||
int socket_recvfrom(p_socket ps, char *data, size_t count,
|
|
||||||
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
|
|
||||||
|
|
||||||
void socket_setnonblocking(p_socket ps);
|
|
||||||
void socket_setblocking(p_socket ps);
|
|
||||||
|
|
||||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
|
|
||||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
|
||||||
p_timeout tm);
|
|
||||||
|
|
||||||
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
|
|
||||||
int socket_create(p_socket ps, int domain, int type, int protocol);
|
int socket_create(p_socket ps, int domain, int type, int protocol);
|
||||||
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
|
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
|
||||||
int socket_listen(p_socket ps, int backlog);
|
int socket_listen(p_socket ps, int backlog);
|
||||||
int socket_accept(p_socket ps, p_socket pa, SA *addr,
|
void socket_shutdown(p_socket ps, int how);
|
||||||
socklen_t *addr_len, p_timeout tm);
|
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||||
|
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *addr_len, p_timeout tm);
|
||||||
const char *socket_hoststrerror(int err);
|
int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
|
||||||
const char *socket_strerror(int err);
|
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||||
|
|
||||||
/* these are perfect to use with the io abstraction module
|
|
||||||
and the buffered input module */
|
|
||||||
int socket_send(p_socket ps, const char *data, size_t count,
|
|
||||||
size_t *sent, p_timeout tm);
|
|
||||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||||
const char *socket_ioerror(p_socket ps, int err);
|
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
|
||||||
|
int socket_write(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
|
||||||
|
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||||
|
void socket_setblocking(p_socket ps);
|
||||||
|
void socket_setnonblocking(p_socket ps);
|
||||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
||||||
int socket_gethostbyname(const char *addr, struct hostent **hp);
|
int socket_gethostbyname(const char *addr, struct hostent **hp);
|
||||||
|
const char *socket_hoststrerror(int err);
|
||||||
|
const char *socket_strerror(int err);
|
||||||
|
const char *socket_ioerror(p_socket ps, int err);
|
||||||
|
const char *socket_gaistrerror(int err);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* SOCKET_H */
|
#endif /* SOCKET_H */
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- LuaSocket helper module
|
-- LuaSocket helper module
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -11,37 +10,52 @@ local base = _G
|
|||||||
local string = require("string")
|
local string = require("string")
|
||||||
local math = require("math")
|
local math = require("math")
|
||||||
local socket = require("socket.core")
|
local socket = require("socket.core")
|
||||||
module("socket")
|
|
||||||
|
local _M = socket
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Exported auxiliar functions
|
-- Exported auxiliar functions
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
function connect(address, port, laddress, lport)
|
function _M.connect4(address, port, laddress, lport)
|
||||||
local sock, err = socket.tcp()
|
return socket.connect(address, port, laddress, lport, "inet")
|
||||||
if not sock then return nil, err end
|
end
|
||||||
if laddress then
|
|
||||||
local res, err = sock:bind(laddress, lport, -1)
|
function _M.connect6(address, port, laddress, lport)
|
||||||
if not res then return nil, err end
|
return socket.connect(address, port, laddress, lport, "inet6")
|
||||||
|
end
|
||||||
|
|
||||||
|
function _M.bind(host, port, backlog)
|
||||||
|
if host == "*" then host = "0.0.0.0" end
|
||||||
|
local addrinfo, err = socket.dns.getaddrinfo(host);
|
||||||
|
if not addrinfo then return nil, err end
|
||||||
|
local sock, res
|
||||||
|
err = "no info on address"
|
||||||
|
for i, alt in base.ipairs(addrinfo) do
|
||||||
|
if alt.family == "inet" then
|
||||||
|
sock, err = socket.tcp4()
|
||||||
|
else
|
||||||
|
sock, err = socket.tcp6()
|
||||||
|
end
|
||||||
|
if not sock then return nil, err end
|
||||||
|
sock:setoption("reuseaddr", true)
|
||||||
|
res, err = sock:bind(alt.addr, port)
|
||||||
|
if not res then
|
||||||
|
sock:close()
|
||||||
|
else
|
||||||
|
res, err = sock:listen(backlog)
|
||||||
|
if not res then
|
||||||
|
sock:close()
|
||||||
|
else
|
||||||
|
return sock
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local res, err = sock:connect(address, port)
|
return nil, err
|
||||||
if not res then return nil, err end
|
|
||||||
return sock
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function bind(host, port, backlog)
|
_M.try = _M.newtry()
|
||||||
local sock, err = socket.tcp()
|
|
||||||
if not sock then return nil, err end
|
|
||||||
sock:setoption("reuseaddr", true)
|
|
||||||
local res, err = sock:bind(host, port)
|
|
||||||
if not res then return nil, err end
|
|
||||||
res, err = sock:listen(backlog)
|
|
||||||
if not res then return nil, err end
|
|
||||||
return sock
|
|
||||||
end
|
|
||||||
|
|
||||||
try = newtry()
|
function _M.choose(table)
|
||||||
|
|
||||||
function choose(table)
|
|
||||||
return function(name, opt1, opt2)
|
return function(name, opt1, opt2)
|
||||||
if base.type(name) ~= "string" then
|
if base.type(name) ~= "string" then
|
||||||
name, opt1, opt2 = "default", name, opt1
|
name, opt1, opt2 = "default", name, opt1
|
||||||
@@ -56,10 +70,11 @@ end
|
|||||||
-- Socket sources and sinks, conforming to LTN12
|
-- Socket sources and sinks, conforming to LTN12
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- create namespaces inside LuaSocket namespace
|
-- create namespaces inside LuaSocket namespace
|
||||||
sourcet = {}
|
local sourcet, sinkt = {}, {}
|
||||||
sinkt = {}
|
_M.sourcet = sourcet
|
||||||
|
_M.sinkt = sinkt
|
||||||
|
|
||||||
BLOCKSIZE = 2048
|
_M.BLOCKSIZE = 2048
|
||||||
|
|
||||||
sinkt["close-when-done"] = function(sock)
|
sinkt["close-when-done"] = function(sock)
|
||||||
return base.setmetatable({
|
return base.setmetatable({
|
||||||
@@ -89,7 +104,7 @@ end
|
|||||||
|
|
||||||
sinkt["default"] = sinkt["keep-open"]
|
sinkt["default"] = sinkt["keep-open"]
|
||||||
|
|
||||||
sink = choose(sinkt)
|
_M.sink = _M.choose(sinkt)
|
||||||
|
|
||||||
sourcet["by-length"] = function(sock, length)
|
sourcet["by-length"] = function(sock, length)
|
||||||
return base.setmetatable({
|
return base.setmetatable({
|
||||||
@@ -129,5 +144,6 @@ end
|
|||||||
|
|
||||||
sourcet["default"] = sourcet["until-closed"]
|
sourcet["default"] = sourcet["until-closed"]
|
||||||
|
|
||||||
source = choose(sourcet)
|
_M.source = _M.choose(sourcet)
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
290
src/tcp.c
290
src/tcp.c
@@ -1,13 +1,8 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* TCP object
|
* TCP object
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <string.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "auxiliar.h"
|
#include "auxiliar.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
@@ -15,12 +10,18 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal function prototypes
|
* Internal function prototypes
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int global_create(lua_State *L);
|
static int global_create(lua_State *L);
|
||||||
|
static int global_create4(lua_State *L);
|
||||||
|
static int global_create6(lua_State *L);
|
||||||
|
static int global_connect(lua_State *L);
|
||||||
static int meth_connect(lua_State *L);
|
static int meth_connect(lua_State *L);
|
||||||
static int meth_listen(lua_State *L);
|
static int meth_listen(lua_State *L);
|
||||||
|
static int meth_getfamily(lua_State *L);
|
||||||
static int meth_bind(lua_State *L);
|
static int meth_bind(lua_State *L);
|
||||||
static int meth_send(lua_State *L);
|
static int meth_send(lua_State *L);
|
||||||
static int meth_getstats(lua_State *L);
|
static int meth_getstats(lua_State *L);
|
||||||
@@ -31,14 +32,16 @@ static int meth_shutdown(lua_State *L);
|
|||||||
static int meth_receive(lua_State *L);
|
static int meth_receive(lua_State *L);
|
||||||
static int meth_accept(lua_State *L);
|
static int meth_accept(lua_State *L);
|
||||||
static int meth_close(lua_State *L);
|
static int meth_close(lua_State *L);
|
||||||
|
static int meth_getoption(lua_State *L);
|
||||||
static int meth_setoption(lua_State *L);
|
static int meth_setoption(lua_State *L);
|
||||||
|
static int meth_gettimeout(lua_State *L);
|
||||||
static int meth_settimeout(lua_State *L);
|
static int meth_settimeout(lua_State *L);
|
||||||
static int meth_getfd(lua_State *L);
|
static int meth_getfd(lua_State *L);
|
||||||
static int meth_setfd(lua_State *L);
|
static int meth_setfd(lua_State *L);
|
||||||
static int meth_dirty(lua_State *L);
|
static int meth_dirty(lua_State *L);
|
||||||
|
|
||||||
/* tcp object methods */
|
/* tcp object methods */
|
||||||
static luaL_reg tcp[] = {
|
static luaL_Reg tcp_methods[] = {
|
||||||
{"__gc", meth_close},
|
{"__gc", meth_close},
|
||||||
{"__tostring", auxiliar_tostring},
|
{"__tostring", auxiliar_tostring},
|
||||||
{"accept", meth_accept},
|
{"accept", meth_accept},
|
||||||
@@ -46,7 +49,9 @@ static luaL_reg tcp[] = {
|
|||||||
{"close", meth_close},
|
{"close", meth_close},
|
||||||
{"connect", meth_connect},
|
{"connect", meth_connect},
|
||||||
{"dirty", meth_dirty},
|
{"dirty", meth_dirty},
|
||||||
|
{"getfamily", meth_getfamily},
|
||||||
{"getfd", meth_getfd},
|
{"getfd", meth_getfd},
|
||||||
|
{"getoption", meth_getoption},
|
||||||
{"getpeername", meth_getpeername},
|
{"getpeername", meth_getpeername},
|
||||||
{"getsockname", meth_getsockname},
|
{"getsockname", meth_getsockname},
|
||||||
{"getstats", meth_getstats},
|
{"getstats", meth_getstats},
|
||||||
@@ -59,22 +64,60 @@ static luaL_reg tcp[] = {
|
|||||||
{"setpeername", meth_connect},
|
{"setpeername", meth_connect},
|
||||||
{"setsockname", meth_bind},
|
{"setsockname", meth_bind},
|
||||||
{"settimeout", meth_settimeout},
|
{"settimeout", meth_settimeout},
|
||||||
|
{"gettimeout", meth_gettimeout},
|
||||||
{"shutdown", meth_shutdown},
|
{"shutdown", meth_shutdown},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* socket option handlers */
|
/* socket option handlers */
|
||||||
static t_opt opt[] = {
|
static t_opt optget[] = {
|
||||||
{"keepalive", opt_keepalive},
|
{"keepalive", opt_get_keepalive},
|
||||||
{"reuseaddr", opt_reuseaddr},
|
{"reuseaddr", opt_get_reuseaddr},
|
||||||
{"tcp-nodelay", opt_tcp_nodelay},
|
{"reuseport", opt_get_reuseport},
|
||||||
{"linger", opt_linger},
|
{"tcp-nodelay", opt_get_tcp_nodelay},
|
||||||
|
#ifdef TCP_KEEPIDLE
|
||||||
|
{"tcp-keepidle", opt_get_tcp_keepidle},
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
{"tcp-keepcnt", opt_get_tcp_keepcnt},
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPINTVL
|
||||||
|
{"tcp-keepintvl", opt_get_tcp_keepintvl},
|
||||||
|
#endif
|
||||||
|
{"linger", opt_get_linger},
|
||||||
|
{"error", opt_get_error},
|
||||||
|
{"recv-buffer-size", opt_get_recv_buf_size},
|
||||||
|
{"send-buffer-size", opt_get_send_buf_size},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static t_opt optset[] = {
|
||||||
|
{"keepalive", opt_set_keepalive},
|
||||||
|
{"reuseaddr", opt_set_reuseaddr},
|
||||||
|
{"reuseport", opt_set_reuseport},
|
||||||
|
{"tcp-nodelay", opt_set_tcp_nodelay},
|
||||||
|
#ifdef TCP_KEEPIDLE
|
||||||
|
{"tcp-keepidle", opt_set_tcp_keepidle},
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
{"tcp-keepcnt", opt_set_tcp_keepcnt},
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPINTVL
|
||||||
|
{"tcp-keepintvl", opt_set_tcp_keepintvl},
|
||||||
|
#endif
|
||||||
|
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||||
|
{"linger", opt_set_linger},
|
||||||
|
{"recv-buffer-size", opt_set_recv_buf_size},
|
||||||
|
{"send-buffer-size", opt_set_send_buf_size},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* functions in library namespace */
|
/* functions in library namespace */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"tcp", global_create},
|
{"tcp", global_create},
|
||||||
|
{"tcp4", global_create4},
|
||||||
|
{"tcp6", global_create6},
|
||||||
|
{"connect", global_connect},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,15 +127,15 @@ static luaL_reg func[] = {
|
|||||||
int tcp_open(lua_State *L)
|
int tcp_open(lua_State *L)
|
||||||
{
|
{
|
||||||
/* create classes */
|
/* create classes */
|
||||||
auxiliar_newclass(L, "tcp{master}", tcp);
|
auxiliar_newclass(L, "tcp{master}", tcp_methods);
|
||||||
auxiliar_newclass(L, "tcp{client}", tcp);
|
auxiliar_newclass(L, "tcp{client}", tcp_methods);
|
||||||
auxiliar_newclass(L, "tcp{server}", tcp);
|
auxiliar_newclass(L, "tcp{server}", tcp_methods);
|
||||||
/* create class groups */
|
/* create class groups */
|
||||||
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
|
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
|
||||||
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
|
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
|
||||||
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
|
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
|
||||||
/* define library functions */
|
/* define library functions */
|
||||||
luaL_openlib(L, NULL, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,10 +168,16 @@ static int meth_setstats(lua_State *L) {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Just call option handler
|
* Just call option handler
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getoption(lua_State *L)
|
||||||
|
{
|
||||||
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
|
return opt_meth_getoption(L, optget, &tcp->sock);
|
||||||
|
}
|
||||||
|
|
||||||
static int meth_setoption(lua_State *L)
|
static int meth_setoption(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
return opt_meth_setoption(L, opt, &tcp->sock);
|
return opt_meth_setoption(L, optset, &tcp->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -145,7 +194,7 @@ static int meth_getfd(lua_State *L)
|
|||||||
static int meth_setfd(lua_State *L)
|
static int meth_setfd(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
tcp->sock = (t_socket) luaL_checknumber(L, 2);
|
tcp->sock = (t_socket) luaL_checknumber(L, 2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,43 +206,50 @@ static int meth_dirty(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Waits for and returns a client object attempting connection to the
|
* Waits for and returns a client object attempting connection to the
|
||||||
* server object
|
* server object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_accept(lua_State *L)
|
static int meth_accept(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
|
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
|
||||||
p_timeout tm = timeout_markstart(&server->tm);
|
p_timeout tm = timeout_markstart(&server->tm);
|
||||||
t_socket sock;
|
t_socket sock;
|
||||||
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
|
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
|
||||||
/* if successful, push client socket */
|
/* if successful, push client socket */
|
||||||
if (err == IO_DONE) {
|
if (err == NULL) {
|
||||||
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||||
auxiliar_setclass(L, "tcp{client}", -1);
|
auxiliar_setclass(L, "tcp{client}", -1);
|
||||||
/* initialize structure fields */
|
/* initialize structure fields */
|
||||||
|
memset(clnt, 0, sizeof(t_tcp));
|
||||||
socket_setnonblocking(&sock);
|
socket_setnonblocking(&sock);
|
||||||
clnt->sock = sock;
|
clnt->sock = sock;
|
||||||
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
|
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||||
(p_error) socket_ioerror, &clnt->sock);
|
(p_error) socket_ioerror, &clnt->sock);
|
||||||
timeout_init(&clnt->tm, -1, -1);
|
timeout_init(&clnt->tm, -1, -1);
|
||||||
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||||
|
clnt->family = server->family;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, socket_strerror(err));
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Binds an object to an address
|
* Binds an object to an address
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_bind(lua_State *L)
|
static int meth_bind(lua_State *L) {
|
||||||
{
|
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
const char *port = luaL_checkstring(L, 3);
|
||||||
const char *err = inet_trybind(&tcp->sock, address, port);
|
const char *err;
|
||||||
|
struct addrinfo bindhints;
|
||||||
|
memset(&bindhints, 0, sizeof(bindhints));
|
||||||
|
bindhints.ai_socktype = SOCK_STREAM;
|
||||||
|
bindhints.ai_family = tcp->family;
|
||||||
|
bindhints.ai_flags = AI_PASSIVE;
|
||||||
|
err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
|
||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@@ -206,13 +262,19 @@ static int meth_bind(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Turns a master tcp object into a client object.
|
* Turns a master tcp object into a client object.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_connect(lua_State *L)
|
static int meth_connect(lua_State *L) {
|
||||||
{
|
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
const char *port = luaL_checkstring(L, 3);
|
||||||
p_timeout tm = timeout_markstart(&tcp->tm);
|
struct addrinfo connecthints;
|
||||||
const char *err = inet_tryconnect(&tcp->sock, address, port, tm);
|
const char *err;
|
||||||
|
memset(&connecthints, 0, sizeof(connecthints));
|
||||||
|
connecthints.ai_socktype = SOCK_STREAM;
|
||||||
|
/* make sure we try to connect only to the same family */
|
||||||
|
connecthints.ai_family = tcp->family;
|
||||||
|
timeout_markstart(&tcp->tm);
|
||||||
|
err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
|
||||||
|
&tcp->tm, &connecthints);
|
||||||
/* have to set the class even if it failed due to non-blocking connects */
|
/* have to set the class even if it failed due to non-blocking connects */
|
||||||
auxiliar_setclass(L, "tcp{client}", 1);
|
auxiliar_setclass(L, "tcp{client}", 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -220,13 +282,12 @@ static int meth_connect(lua_State *L)
|
|||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* turn master object into a client object */
|
|
||||||
lua_pushnumber(L, 1);
|
lua_pushnumber(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Closes socket used by object
|
* Closes socket used by object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_close(lua_State *L)
|
static int meth_close(lua_State *L)
|
||||||
{
|
{
|
||||||
@@ -236,6 +297,24 @@ static int meth_close(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Returns family as string
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getfamily(lua_State *L)
|
||||||
|
{
|
||||||
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
|
if (tcp->family == AF_INET6) {
|
||||||
|
lua_pushliteral(L, "inet6");
|
||||||
|
return 1;
|
||||||
|
} else if (tcp->family == AF_INET) {
|
||||||
|
lua_pushliteral(L, "inet4");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushliteral(L, "inet4");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Puts the sockt in listen mode
|
* Puts the sockt in listen mode
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -260,27 +339,13 @@ static int meth_listen(lua_State *L)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_shutdown(lua_State *L)
|
static int meth_shutdown(lua_State *L)
|
||||||
{
|
{
|
||||||
|
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
|
||||||
|
static const char* methods[] = { "receive", "send", "both", NULL };
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||||
const char *how = luaL_optstring(L, 2, "both");
|
int how = luaL_checkoption(L, 2, "both", methods);
|
||||||
switch (how[0]) {
|
socket_shutdown(&tcp->sock, how);
|
||||||
case 'b':
|
|
||||||
if (strcmp(how, "both")) goto error;
|
|
||||||
socket_shutdown(&tcp->sock, 2);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
if (strcmp(how, "send")) goto error;
|
|
||||||
socket_shutdown(&tcp->sock, 1);
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
if (strcmp(how, "receive")) goto error;
|
|
||||||
socket_shutdown(&tcp->sock, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lua_pushnumber(L, 1);
|
lua_pushnumber(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
error:
|
|
||||||
luaL_argerror(L, 2, "invalid shutdown method");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -289,13 +354,13 @@ error:
|
|||||||
static int meth_getpeername(lua_State *L)
|
static int meth_getpeername(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
return inet_meth_getpeername(L, &tcp->sock);
|
return inet_meth_getpeername(L, &tcp->sock, tcp->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meth_getsockname(lua_State *L)
|
static int meth_getsockname(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
return inet_meth_getsockname(L, &tcp->sock);
|
return inet_meth_getsockname(L, &tcp->sock, tcp->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -307,33 +372,100 @@ static int meth_settimeout(lua_State *L)
|
|||||||
return timeout_meth_settimeout(L, &tcp->tm);
|
return timeout_meth_settimeout(L, &tcp->tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int meth_gettimeout(lua_State *L)
|
||||||
|
{
|
||||||
|
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||||
|
return timeout_meth_gettimeout(L, &tcp->tm);
|
||||||
|
}
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Library functions
|
* Library functions
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a master tcp object
|
* Creates a master tcp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_create(lua_State *L)
|
static int tcp_create(lua_State *L, int family) {
|
||||||
{
|
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||||
t_socket sock;
|
memset(tcp, 0, sizeof(t_tcp));
|
||||||
const char *err = inet_trycreate(&sock, SOCK_STREAM);
|
/* set its type as master object */
|
||||||
/* try to allocate a system socket */
|
auxiliar_setclass(L, "tcp{master}", -1);
|
||||||
if (!err) {
|
/* if family is AF_UNSPEC, we leave the socket invalid and
|
||||||
/* allocate tcp object */
|
* store AF_UNSPEC into family. This will allow it to later be
|
||||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
* replaced with an AF_INET6 or AF_INET socket upon first use. */
|
||||||
/* set its type as master object */
|
tcp->sock = SOCKET_INVALID;
|
||||||
auxiliar_setclass(L, "tcp{master}", -1);
|
tcp->family = family;
|
||||||
/* initialize remaining structure fields */
|
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||||
socket_setnonblocking(&sock);
|
(p_error) socket_ioerror, &tcp->sock);
|
||||||
tcp->sock = sock;
|
timeout_init(&tcp->tm, -1, -1);
|
||||||
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||||
(p_error) socket_ioerror, &tcp->sock);
|
if (family != AF_UNSPEC) {
|
||||||
timeout_init(&tcp->tm, -1, -1);
|
const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
|
||||||
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
if (err != NULL) {
|
||||||
return 1;
|
lua_pushnil(L);
|
||||||
} else {
|
lua_pushstring(L, err);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
socket_setnonblocking(&tcp->sock);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create(lua_State *L) {
|
||||||
|
return tcp_create(L, AF_UNSPEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create4(lua_State *L) {
|
||||||
|
return tcp_create(L, AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create6(lua_State *L) {
|
||||||
|
return tcp_create(L, AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_connect(lua_State *L) {
|
||||||
|
const char *remoteaddr = luaL_checkstring(L, 1);
|
||||||
|
const char *remoteserv = luaL_checkstring(L, 2);
|
||||||
|
const char *localaddr = luaL_optstring(L, 3, NULL);
|
||||||
|
const char *localserv = luaL_optstring(L, 4, "0");
|
||||||
|
int family = inet_optfamily(L, 5, "unspec");
|
||||||
|
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||||
|
struct addrinfo bindhints, connecthints;
|
||||||
|
const char *err = NULL;
|
||||||
|
/* initialize tcp structure */
|
||||||
|
memset(tcp, 0, sizeof(t_tcp));
|
||||||
|
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||||
|
(p_error) socket_ioerror, &tcp->sock);
|
||||||
|
timeout_init(&tcp->tm, -1, -1);
|
||||||
|
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||||
|
tcp->sock = SOCKET_INVALID;
|
||||||
|
tcp->family = AF_UNSPEC;
|
||||||
|
/* allow user to pick local address and port */
|
||||||
|
memset(&bindhints, 0, sizeof(bindhints));
|
||||||
|
bindhints.ai_socktype = SOCK_STREAM;
|
||||||
|
bindhints.ai_family = family;
|
||||||
|
bindhints.ai_flags = AI_PASSIVE;
|
||||||
|
if (localaddr) {
|
||||||
|
err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
|
||||||
|
localserv, &bindhints);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, err);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* try to connect to remote address and port */
|
||||||
|
memset(&connecthints, 0, sizeof(connecthints));
|
||||||
|
connecthints.ai_socktype = SOCK_STREAM;
|
||||||
|
/* make sure we try to connect only to the same family */
|
||||||
|
connecthints.ai_family = tcp->family;
|
||||||
|
err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
|
||||||
|
&tcp->tm, &connecthints);
|
||||||
|
if (err) {
|
||||||
|
socket_destroy(&tcp->sock);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
auxiliar_setclass(L, "tcp{client}", -1);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/tcp.h
13
src/tcp.h
@@ -13,10 +13,8 @@
|
|||||||
* objects are tcp objects bound to some local address. Client objects are
|
* objects are tcp objects bound to some local address. Client objects are
|
||||||
* tcp objects either connected to some address or returned by the accept
|
* tcp objects either connected to some address or returned by the accept
|
||||||
* method of a server object.
|
* method of a server object.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
@@ -27,10 +25,19 @@ typedef struct t_tcp_ {
|
|||||||
t_io io;
|
t_io io;
|
||||||
t_buffer buf;
|
t_buffer buf;
|
||||||
t_timeout tm;
|
t_timeout tm;
|
||||||
|
int family;
|
||||||
} t_tcp;
|
} t_tcp;
|
||||||
|
|
||||||
typedef t_tcp *p_tcp;
|
typedef t_tcp *p_tcp;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int tcp_open(lua_State *L);
|
int tcp_open(lua_State *L);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* TCP_H */
|
#endif /* TCP_H */
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Timeout management functions
|
* Timeout management functions
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <stdio.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "auxiliar.h"
|
#include "auxiliar.h"
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
@@ -33,7 +32,7 @@
|
|||||||
static int timeout_lua_gettime(lua_State *L);
|
static int timeout_lua_gettime(lua_State *L);
|
||||||
static int timeout_lua_sleep(lua_State *L);
|
static int timeout_lua_sleep(lua_State *L);
|
||||||
|
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{ "gettime", timeout_lua_gettime },
|
{ "gettime", timeout_lua_gettime },
|
||||||
{ "sleep", timeout_lua_sleep },
|
{ "sleep", timeout_lua_sleep },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
@@ -52,7 +51,7 @@ void timeout_init(p_timeout tm, double block, double total) {
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Determines how much time we have left for the next system call,
|
* Determines how much time we have left for the next system call,
|
||||||
* if the previous call was successful
|
* if the previous call was successful
|
||||||
* Input
|
* Input
|
||||||
* tm: timeout control structure
|
* tm: timeout control structure
|
||||||
* Returns
|
* Returns
|
||||||
@@ -107,7 +106,7 @@ double timeout_getretry(p_timeout tm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Marks the operation start time in structure
|
* Marks the operation start time in structure
|
||||||
* Input
|
* Input
|
||||||
* tm: timeout control structure
|
* tm: timeout control structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -117,7 +116,7 @@ p_timeout timeout_markstart(p_timeout tm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Gets time in s, relative to January 1, 1970 (UTC)
|
* Gets time in s, relative to January 1, 1970 (UTC)
|
||||||
* Returns
|
* Returns
|
||||||
* time in s.
|
* time in s.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@@ -144,7 +143,7 @@ double timeout_gettime(void) {
|
|||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int timeout_open(lua_State *L) {
|
int timeout_open(lua_State *L) {
|
||||||
luaL_openlib(L, NULL, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +158,7 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
|
|||||||
const char *mode = luaL_optstring(L, 3, "b");
|
const char *mode = luaL_optstring(L, 3, "b");
|
||||||
switch (*mode) {
|
switch (*mode) {
|
||||||
case 'b':
|
case 'b':
|
||||||
tm->block = t;
|
tm->block = t;
|
||||||
break;
|
break;
|
||||||
case 'r': case 't':
|
case 'r': case 't':
|
||||||
tm->total = t;
|
tm->total = t;
|
||||||
@@ -172,6 +171,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Gets timeout values for IO operations
|
||||||
|
* Lua Output: block, total
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
|
||||||
|
lua_pushnumber(L, tm->block);
|
||||||
|
lua_pushnumber(L, tm->total);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Test support functions
|
* Test support functions
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
@@ -187,13 +196,23 @@ static int timeout_lua_gettime(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Sleep for n seconds.
|
* Sleep for n seconds.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
|
#ifdef _WIN32
|
||||||
int timeout_lua_sleep(lua_State *L)
|
int timeout_lua_sleep(lua_State *L)
|
||||||
{
|
{
|
||||||
double n = luaL_checknumber(L, 1);
|
double n = luaL_checknumber(L, 1);
|
||||||
#ifdef _WIN32
|
if (n < 0.0) n = 0.0;
|
||||||
Sleep((int)(n*1000));
|
if (n < DBL_MAX/1000.0) n *= 1000.0;
|
||||||
|
if (n > INT_MAX) n = INT_MAX;
|
||||||
|
Sleep((int)n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
int timeout_lua_sleep(lua_State *L)
|
||||||
|
{
|
||||||
|
double n = luaL_checknumber(L, 1);
|
||||||
struct timespec t, r;
|
struct timespec t, r;
|
||||||
|
if (n < 0.0) n = 0.0;
|
||||||
|
if (n > INT_MAX) n = INT_MAX;
|
||||||
t.tv_sec = (int) n;
|
t.tv_sec = (int) n;
|
||||||
n -= t.tv_sec;
|
n -= t.tv_sec;
|
||||||
t.tv_nsec = (int) (n * 1000000000);
|
t.tv_nsec = (int) (n * 1000000000);
|
||||||
@@ -202,6 +221,6 @@ int timeout_lua_sleep(lua_State *L)
|
|||||||
t.tv_sec = r.tv_sec;
|
t.tv_sec = r.tv_sec;
|
||||||
t.tv_nsec = r.tv_nsec;
|
t.tv_nsec = r.tv_nsec;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Timeout management functions
|
* Timeout management functions
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
/* timeout control structure */
|
/* timeout control structure */
|
||||||
typedef struct t_timeout_ {
|
typedef struct t_timeout_ {
|
||||||
@@ -16,14 +14,26 @@ typedef struct t_timeout_ {
|
|||||||
} t_timeout;
|
} t_timeout;
|
||||||
typedef t_timeout *p_timeout;
|
typedef t_timeout *p_timeout;
|
||||||
|
|
||||||
int timeout_open(lua_State *L);
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
void timeout_init(p_timeout tm, double block, double total);
|
void timeout_init(p_timeout tm, double block, double total);
|
||||||
double timeout_get(p_timeout tm);
|
double timeout_get(p_timeout tm);
|
||||||
|
double timeout_getstart(p_timeout tm);
|
||||||
double timeout_getretry(p_timeout tm);
|
double timeout_getretry(p_timeout tm);
|
||||||
p_timeout timeout_markstart(p_timeout tm);
|
p_timeout timeout_markstart(p_timeout tm);
|
||||||
double timeout_getstart(p_timeout tm);
|
|
||||||
double timeout_gettime(void);
|
double timeout_gettime(void);
|
||||||
|
|
||||||
|
int timeout_open(lua_State *L);
|
||||||
|
|
||||||
int timeout_meth_settimeout(lua_State *L, p_timeout tm);
|
int timeout_meth_settimeout(lua_State *L, p_timeout tm);
|
||||||
|
int timeout_meth_gettimeout(lua_State *L, p_timeout tm);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#define timeout_iszero(tm) ((tm)->block == 0.0)
|
#define timeout_iszero(tm) ((tm)->block == 0.0)
|
||||||
|
|
||||||
|
|||||||
25
src/tp.lua
25
src/tp.lua
@@ -2,7 +2,6 @@
|
|||||||
-- Unified SMTP/FTP subsystem
|
-- Unified SMTP/FTP subsystem
|
||||||
-- LuaSocket toolkit.
|
-- LuaSocket toolkit.
|
||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $Id$
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@@ -12,12 +11,14 @@ local base = _G
|
|||||||
local string = require("string")
|
local string = require("string")
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
module("socket.tp")
|
|
||||||
|
socket.tp = {}
|
||||||
|
local _M = socket.tp
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Program constants
|
-- Program constants
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
TIMEOUT = 60
|
_M.TIMEOUT = 60
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Implementation
|
-- Implementation
|
||||||
@@ -45,6 +46,14 @@ end
|
|||||||
-- metatable for sock object
|
-- metatable for sock object
|
||||||
local metat = { __index = {} }
|
local metat = { __index = {} }
|
||||||
|
|
||||||
|
function metat.__index:getpeername()
|
||||||
|
return self.c:getpeername()
|
||||||
|
end
|
||||||
|
|
||||||
|
function metat.__index:getsockname()
|
||||||
|
return self.c:getpeername()
|
||||||
|
end
|
||||||
|
|
||||||
function metat.__index:check(ok)
|
function metat.__index:check(ok)
|
||||||
local code, reply = get_reply(self.c)
|
local code, reply = get_reply(self.c)
|
||||||
if not code then return nil, reply end
|
if not code then return nil, reply end
|
||||||
@@ -64,6 +73,7 @@ function metat.__index:check(ok)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:command(cmd, arg)
|
function metat.__index:command(cmd, arg)
|
||||||
|
cmd = string.upper(cmd)
|
||||||
if arg then
|
if arg then
|
||||||
return self.c:send(cmd .. " " .. arg.. "\r\n")
|
return self.c:send(cmd .. " " .. arg.. "\r\n")
|
||||||
else
|
else
|
||||||
@@ -72,7 +82,7 @@ function metat.__index:command(cmd, arg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function metat.__index:sink(snk, pat)
|
function metat.__index:sink(snk, pat)
|
||||||
local chunk, err = c:receive(pat)
|
local chunk, err = self.c:receive(pat)
|
||||||
return snk(chunk, err)
|
return snk(chunk, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,14 +115,14 @@ end
|
|||||||
-- closes the underlying c
|
-- closes the underlying c
|
||||||
function metat.__index:close()
|
function metat.__index:close()
|
||||||
self.c:close()
|
self.c:close()
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- connect with server and return c object
|
-- connect with server and return c object
|
||||||
function connect(host, port, timeout, create)
|
function _M.connect(host, port, timeout, create)
|
||||||
local c, e = (create or socket.tcp)()
|
local c, e = (create or socket.tcp)()
|
||||||
if not c then return nil, e end
|
if not c then return nil, e end
|
||||||
c:settimeout(timeout or TIMEOUT)
|
c:settimeout(timeout or _M.TIMEOUT)
|
||||||
local r, e = c:connect(host, port)
|
local r, e = c:connect(host, port)
|
||||||
if not r then
|
if not r then
|
||||||
c:close()
|
c:close()
|
||||||
@@ -121,3 +131,4 @@ function connect(host, port, timeout, create)
|
|||||||
return base.setmetatable({c = c}, metat)
|
return base.setmetatable({c = c}, metat)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return _M
|
||||||
|
|||||||
338
src/udp.c
338
src/udp.c
@@ -1,13 +1,8 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* UDP object
|
* UDP object
|
||||||
* LuaSocket toolkit
|
* LuaSocket toolkit
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <string.h>
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
#include "auxiliar.h"
|
#include "auxiliar.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
@@ -15,39 +10,48 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* min and max macros */
|
/* min and max macros */
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAX
|
#ifndef MAX
|
||||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Internal function prototypes
|
* Internal function prototypes
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int global_create(lua_State *L);
|
static int global_create(lua_State *L);
|
||||||
|
static int global_create4(lua_State *L);
|
||||||
|
static int global_create6(lua_State *L);
|
||||||
static int meth_send(lua_State *L);
|
static int meth_send(lua_State *L);
|
||||||
static int meth_sendto(lua_State *L);
|
static int meth_sendto(lua_State *L);
|
||||||
static int meth_receive(lua_State *L);
|
static int meth_receive(lua_State *L);
|
||||||
static int meth_receivefrom(lua_State *L);
|
static int meth_receivefrom(lua_State *L);
|
||||||
|
static int meth_getfamily(lua_State *L);
|
||||||
static int meth_getsockname(lua_State *L);
|
static int meth_getsockname(lua_State *L);
|
||||||
static int meth_getpeername(lua_State *L);
|
static int meth_getpeername(lua_State *L);
|
||||||
|
static int meth_gettimeout(lua_State *L);
|
||||||
static int meth_setsockname(lua_State *L);
|
static int meth_setsockname(lua_State *L);
|
||||||
static int meth_setpeername(lua_State *L);
|
static int meth_setpeername(lua_State *L);
|
||||||
static int meth_close(lua_State *L);
|
static int meth_close(lua_State *L);
|
||||||
static int meth_setoption(lua_State *L);
|
static int meth_setoption(lua_State *L);
|
||||||
|
static int meth_getoption(lua_State *L);
|
||||||
static int meth_settimeout(lua_State *L);
|
static int meth_settimeout(lua_State *L);
|
||||||
static int meth_getfd(lua_State *L);
|
static int meth_getfd(lua_State *L);
|
||||||
static int meth_setfd(lua_State *L);
|
static int meth_setfd(lua_State *L);
|
||||||
static int meth_dirty(lua_State *L);
|
static int meth_dirty(lua_State *L);
|
||||||
|
|
||||||
/* udp object methods */
|
/* udp object methods */
|
||||||
static luaL_reg udp[] = {
|
static luaL_Reg udp_methods[] = {
|
||||||
{"__gc", meth_close},
|
{"__gc", meth_close},
|
||||||
{"__tostring", auxiliar_tostring},
|
{"__tostring", auxiliar_tostring},
|
||||||
{"close", meth_close},
|
{"close", meth_close},
|
||||||
{"dirty", meth_dirty},
|
{"dirty", meth_dirty},
|
||||||
|
{"getfamily", meth_getfamily},
|
||||||
{"getfd", meth_getfd},
|
{"getfd", meth_getfd},
|
||||||
{"getpeername", meth_getpeername},
|
{"getpeername", meth_getpeername},
|
||||||
{"getsockname", meth_getsockname},
|
{"getsockname", meth_getsockname},
|
||||||
@@ -57,52 +61,87 @@ static luaL_reg udp[] = {
|
|||||||
{"sendto", meth_sendto},
|
{"sendto", meth_sendto},
|
||||||
{"setfd", meth_setfd},
|
{"setfd", meth_setfd},
|
||||||
{"setoption", meth_setoption},
|
{"setoption", meth_setoption},
|
||||||
|
{"getoption", meth_getoption},
|
||||||
{"setpeername", meth_setpeername},
|
{"setpeername", meth_setpeername},
|
||||||
{"setsockname", meth_setsockname},
|
{"setsockname", meth_setsockname},
|
||||||
{"settimeout", meth_settimeout},
|
{"settimeout", meth_settimeout},
|
||||||
|
{"gettimeout", meth_gettimeout},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* socket options */
|
/* socket options for setoption */
|
||||||
static t_opt opt[] = {
|
static t_opt optset[] = {
|
||||||
{"dontroute", opt_dontroute},
|
{"dontroute", opt_set_dontroute},
|
||||||
{"broadcast", opt_broadcast},
|
{"broadcast", opt_set_broadcast},
|
||||||
{"reuseaddr", opt_reuseaddr},
|
{"reuseaddr", opt_set_reuseaddr},
|
||||||
{"ip-multicast-ttl", opt_ip_multicast_ttl},
|
{"reuseport", opt_set_reuseport},
|
||||||
{"ip-multicast-loop", opt_ip_multicast_loop},
|
{"ip-multicast-if", opt_set_ip_multicast_if},
|
||||||
{"ip-add-membership", opt_ip_add_membership},
|
{"ip-multicast-ttl", opt_set_ip_multicast_ttl},
|
||||||
{"ip-drop-membership", opt_ip_drop_membersip},
|
{"ip-multicast-loop", opt_set_ip_multicast_loop},
|
||||||
{NULL, NULL}
|
{"ip-add-membership", opt_set_ip_add_membership},
|
||||||
|
{"ip-drop-membership", opt_set_ip_drop_membersip},
|
||||||
|
{"ipv6-unicast-hops", opt_set_ip6_unicast_hops},
|
||||||
|
{"ipv6-multicast-hops", opt_set_ip6_unicast_hops},
|
||||||
|
{"ipv6-multicast-loop", opt_set_ip6_multicast_loop},
|
||||||
|
{"ipv6-add-membership", opt_set_ip6_add_membership},
|
||||||
|
{"ipv6-drop-membership", opt_set_ip6_drop_membersip},
|
||||||
|
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||||
|
{"recv-buffer-size", opt_set_recv_buf_size},
|
||||||
|
{"send-buffer-size", opt_set_send_buf_size},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* socket options for getoption */
|
||||||
|
static t_opt optget[] = {
|
||||||
|
{"dontroute", opt_get_dontroute},
|
||||||
|
{"broadcast", opt_get_broadcast},
|
||||||
|
{"reuseaddr", opt_get_reuseaddr},
|
||||||
|
{"reuseport", opt_get_reuseport},
|
||||||
|
{"ip-multicast-if", opt_get_ip_multicast_if},
|
||||||
|
{"ip-multicast-loop", opt_get_ip_multicast_loop},
|
||||||
|
{"error", opt_get_error},
|
||||||
|
{"ipv6-unicast-hops", opt_get_ip6_unicast_hops},
|
||||||
|
{"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
|
||||||
|
{"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
|
||||||
|
{"ipv6-v6only", opt_get_ip6_v6only},
|
||||||
|
{"recv-buffer-size", opt_get_recv_buf_size},
|
||||||
|
{"send-buffer-size", opt_get_send_buf_size},
|
||||||
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* functions in library namespace */
|
/* functions in library namespace */
|
||||||
static luaL_reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"udp", global_create},
|
{"udp", global_create},
|
||||||
|
{"udp4", global_create4},
|
||||||
|
{"udp6", global_create6},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int udp_open(lua_State *L)
|
int udp_open(lua_State *L) {
|
||||||
{
|
|
||||||
/* create classes */
|
/* create classes */
|
||||||
auxiliar_newclass(L, "udp{connected}", udp);
|
auxiliar_newclass(L, "udp{connected}", udp_methods);
|
||||||
auxiliar_newclass(L, "udp{unconnected}", udp);
|
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
|
||||||
/* create class groups */
|
/* create class groups */
|
||||||
auxiliar_add2group(L, "udp{connected}", "udp{any}");
|
auxiliar_add2group(L, "udp{connected}", "udp{any}");
|
||||||
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
|
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
|
||||||
auxiliar_add2group(L, "udp{connected}", "select{able}");
|
auxiliar_add2group(L, "udp{connected}", "select{able}");
|
||||||
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
||||||
/* define library functions */
|
/* define library functions */
|
||||||
luaL_openlib(L, NULL, func, 0);
|
luaL_setfuncs(L, func, 0);
|
||||||
|
/* export default UDP size */
|
||||||
|
lua_pushliteral(L, "_DATAGRAMSIZE");
|
||||||
|
lua_pushinteger(L, UDP_DATAGRAMSIZE);
|
||||||
|
lua_rawset(L, -3);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Lua methods
|
* Lua methods
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
const char *udp_strerror(int err) {
|
static const char *udp_strerror(int err) {
|
||||||
/* a 'closed' error on an unconnected means the target address was not
|
/* a 'closed' error on an unconnected means the target address was not
|
||||||
* accepted by the transport layer */
|
* accepted by the transport layer */
|
||||||
if (err == IO_CLOSED) return "refused";
|
if (err == IO_CLOSED) return "refused";
|
||||||
@@ -125,7 +164,7 @@ static int meth_send(lua_State *L) {
|
|||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushstring(L, udp_strerror(err));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushnumber(L, sent);
|
lua_pushnumber(L, (lua_Number) sent);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,24 +176,55 @@ static int meth_sendto(lua_State *L) {
|
|||||||
size_t count, sent = 0;
|
size_t count, sent = 0;
|
||||||
const char *data = luaL_checklstring(L, 2, &count);
|
const char *data = luaL_checklstring(L, 2, &count);
|
||||||
const char *ip = luaL_checkstring(L, 3);
|
const char *ip = luaL_checkstring(L, 3);
|
||||||
unsigned short port = (unsigned short) luaL_checknumber(L, 4);
|
const char *port = luaL_checkstring(L, 4);
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
struct sockaddr_in addr;
|
|
||||||
int err;
|
int err;
|
||||||
memset(&addr, 0, sizeof(addr));
|
struct addrinfo aihint;
|
||||||
if (!inet_aton(ip, &addr.sin_addr))
|
struct addrinfo *ai;
|
||||||
luaL_argerror(L, 3, "invalid ip address");
|
memset(&aihint, 0, sizeof(aihint));
|
||||||
addr.sin_family = AF_INET;
|
aihint.ai_family = udp->family;
|
||||||
addr.sin_port = htons(port);
|
aihint.ai_socktype = SOCK_DGRAM;
|
||||||
|
aihint.ai_flags = AI_NUMERICHOST;
|
||||||
|
#ifdef AI_NUMERICSERV
|
||||||
|
aihint.ai_flags |= AI_NUMERICSERV;
|
||||||
|
#endif
|
||||||
|
err = getaddrinfo(ip, port, &aihint, &ai);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, gai_strerror(err));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create socket if on first sendto if AF_UNSPEC was set */
|
||||||
|
if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) {
|
||||||
|
struct addrinfo *ap;
|
||||||
|
const char *errstr = NULL;
|
||||||
|
for (ap = ai; ap != NULL; ap = ap->ai_next) {
|
||||||
|
errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0);
|
||||||
|
if (errstr == NULL) {
|
||||||
|
socket_setnonblocking(&udp->sock);
|
||||||
|
udp->family = ap->ai_family;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errstr != NULL) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, errstr);
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timeout_markstart(tm);
|
timeout_markstart(tm);
|
||||||
err = socket_sendto(&udp->sock, data, count, &sent,
|
err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
|
||||||
(SA *) &addr, sizeof(addr), tm);
|
(socklen_t) ai->ai_addrlen, tm);
|
||||||
|
freeaddrinfo(ai);
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushstring(L, udp_strerror(err));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushnumber(L, sent);
|
lua_pushnumber(L, (lua_Number) sent);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,19 +233,27 @@ static int meth_sendto(lua_State *L) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_receive(lua_State *L) {
|
static int meth_receive(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
char buffer[UDP_DATAGRAMSIZE];
|
char buf[UDP_DATAGRAMSIZE];
|
||||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
|
||||||
|
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
|
||||||
int err;
|
int err;
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
count = MIN(count, sizeof(buffer));
|
|
||||||
timeout_markstart(tm);
|
timeout_markstart(tm);
|
||||||
err = socket_recv(&udp->sock, buffer, count, &got, tm);
|
if (!dgram) {
|
||||||
if (err != IO_DONE) {
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushliteral(L, "out of memory");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushlstring(L, buffer, got);
|
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
|
||||||
|
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||||
|
if (err != IO_DONE && err != IO_CLOSED) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, udp_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushlstring(L, dgram, got);
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,26 +262,57 @@ static int meth_receive(lua_State *L) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_receivefrom(lua_State *L) {
|
static int meth_receivefrom(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||||
struct sockaddr_in addr;
|
char buf[UDP_DATAGRAMSIZE];
|
||||||
|
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
|
||||||
|
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
char buffer[UDP_DATAGRAMSIZE];
|
char addrstr[INET6_ADDRSTRLEN];
|
||||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
char portstr[6];
|
||||||
int err;
|
int err;
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
timeout_markstart(tm);
|
timeout_markstart(tm);
|
||||||
count = MIN(count, sizeof(buffer));
|
if (!dgram) {
|
||||||
err = socket_recvfrom(&udp->sock, buffer, count, &got,
|
lua_pushnil(L);
|
||||||
(SA *) &addr, &addr_len, tm);
|
lua_pushliteral(L, "out of memory");
|
||||||
if (err == IO_DONE) {
|
return 2;
|
||||||
lua_pushlstring(L, buffer, got);
|
}
|
||||||
lua_pushstring(L, inet_ntoa(addr.sin_addr));
|
err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
|
||||||
lua_pushnumber(L, ntohs(addr.sin_port));
|
&addr_len, tm);
|
||||||
return 3;
|
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||||
} else {
|
if (err != IO_DONE && err != IO_CLOSED) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, udp_strerror(err));
|
lua_pushstring(L, udp_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
|
||||||
|
INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, gai_strerror(err));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_pushlstring(L, dgram, got);
|
||||||
|
lua_pushstring(L, addrstr);
|
||||||
|
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
|
||||||
|
if (wanted > sizeof(buf)) free(dgram);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Returns family as string
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getfamily(lua_State *L) {
|
||||||
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
|
if (udp->family == AF_INET6) {
|
||||||
|
lua_pushliteral(L, "inet6");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushliteral(L, "inet4");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -234,12 +343,12 @@ static int meth_dirty(lua_State *L) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_getpeername(lua_State *L) {
|
static int meth_getpeername(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
||||||
return inet_meth_getpeername(L, &udp->sock);
|
return inet_meth_getpeername(L, &udp->sock, udp->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meth_getsockname(lua_State *L) {
|
static int meth_getsockname(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
return inet_meth_getsockname(L, &udp->sock);
|
return inet_meth_getsockname(L, &udp->sock, udp->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -247,7 +356,15 @@ static int meth_getsockname(lua_State *L) {
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_setoption(lua_State *L) {
|
static int meth_setoption(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
return opt_meth_setoption(L, opt, &udp->sock);
|
return opt_meth_setoption(L, optset, &udp->sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Just call option handler
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_getoption(lua_State *L) {
|
||||||
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
|
return opt_meth_getoption(L, optget, &udp->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@@ -258,32 +375,47 @@ static int meth_settimeout(lua_State *L) {
|
|||||||
return timeout_meth_settimeout(L, &udp->tm);
|
return timeout_meth_settimeout(L, &udp->tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int meth_gettimeout(lua_State *L) {
|
||||||
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
|
return timeout_meth_gettimeout(L, &udp->tm);
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Turns a master udp object into a client object.
|
* Turns a master udp object into a client object.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_setpeername(lua_State *L) {
|
static int meth_setpeername(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
p_timeout tm = &udp->tm;
|
p_timeout tm = &udp->tm;
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
int connecting = strcmp(address, "*");
|
int connecting = strcmp(address, "*");
|
||||||
unsigned short port = connecting ?
|
const char *port = connecting? luaL_checkstring(L, 3): "0";
|
||||||
(unsigned short) luaL_checknumber(L, 3) :
|
struct addrinfo connecthints;
|
||||||
(unsigned short) luaL_optnumber(L, 3, 0);
|
const char *err;
|
||||||
const char *err = inet_tryconnect(&udp->sock, address, port, tm);
|
memset(&connecthints, 0, sizeof(connecthints));
|
||||||
if (err) {
|
connecthints.ai_socktype = SOCK_DGRAM;
|
||||||
lua_pushnil(L);
|
/* make sure we try to connect only to the same family */
|
||||||
lua_pushstring(L, err);
|
connecthints.ai_family = udp->family;
|
||||||
return 2;
|
if (connecting) {
|
||||||
|
err = inet_tryconnect(&udp->sock, &udp->family, address,
|
||||||
|
port, tm, &connecthints);
|
||||||
|
if (err) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, err);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
auxiliar_setclass(L, "udp{connected}", 1);
|
||||||
|
} else {
|
||||||
|
/* we ignore possible errors because Mac OS X always
|
||||||
|
* returns EAFNOSUPPORT */
|
||||||
|
inet_trydisconnect(&udp->sock, udp->family, tm);
|
||||||
|
auxiliar_setclass(L, "udp{unconnected}", 1);
|
||||||
}
|
}
|
||||||
/* change class to connected or unconnected depending on address */
|
|
||||||
if (connecting) auxiliar_setclass(L, "udp{connected}", 1);
|
|
||||||
else auxiliar_setclass(L, "udp{unconnected}", 1);
|
|
||||||
lua_pushnumber(L, 1);
|
lua_pushnumber(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Closes socket used by object
|
* Closes socket used by object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_close(lua_State *L) {
|
static int meth_close(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||||
@@ -298,8 +430,14 @@ static int meth_close(lua_State *L) {
|
|||||||
static int meth_setsockname(lua_State *L) {
|
static int meth_setsockname(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
const char *port = luaL_checkstring(L, 3);
|
||||||
const char *err = inet_trybind(&udp->sock, address, port);
|
const char *err;
|
||||||
|
struct addrinfo bindhints;
|
||||||
|
memset(&bindhints, 0, sizeof(bindhints));
|
||||||
|
bindhints.ai_socktype = SOCK_DGRAM;
|
||||||
|
bindhints.ai_family = udp->family;
|
||||||
|
bindhints.ai_flags = AI_PASSIVE;
|
||||||
|
err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
|
||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@@ -313,24 +451,38 @@ static int meth_setsockname(lua_State *L) {
|
|||||||
* Library functions
|
* Library functions
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a master udp object
|
* Creates a master udp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_create(lua_State *L) {
|
static int udp_create(lua_State *L, int family) {
|
||||||
t_socket sock;
|
/* allocate udp object */
|
||||||
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
|
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
||||||
/* try to allocate a system socket */
|
auxiliar_setclass(L, "udp{unconnected}", -1);
|
||||||
if (!err) {
|
/* if family is AF_UNSPEC, we leave the socket invalid and
|
||||||
/* allocate tcp object */
|
* store AF_UNSPEC into family. This will allow it to later be
|
||||||
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
* replaced with an AF_INET6 or AF_INET socket upon first use. */
|
||||||
auxiliar_setclass(L, "udp{unconnected}", -1);
|
udp->sock = SOCKET_INVALID;
|
||||||
/* initialize remaining structure fields */
|
timeout_init(&udp->tm, -1, -1);
|
||||||
socket_setnonblocking(&sock);
|
udp->family = family;
|
||||||
udp->sock = sock;
|
if (family != AF_UNSPEC) {
|
||||||
timeout_init(&udp->tm, -1, -1);
|
const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
|
||||||
return 1;
|
if (err != NULL) {
|
||||||
} else {
|
lua_pushnil(L);
|
||||||
lua_pushnil(L);
|
lua_pushstring(L, err);
|
||||||
lua_pushstring(L, err);
|
return 2;
|
||||||
return 2;
|
}
|
||||||
|
socket_setnonblocking(&udp->sock);
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create(lua_State *L) {
|
||||||
|
return udp_create(L, AF_UNSPEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create4(lua_State *L) {
|
||||||
|
return udp_create(L, AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int global_create6(lua_State *L) {
|
||||||
|
return udp_create(L, AF_INET6);
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/udp.h
16
src/udp.h
@@ -8,26 +8,32 @@
|
|||||||
* (AF_INET, SOCK_DGRAM).
|
* (AF_INET, SOCK_DGRAM).
|
||||||
*
|
*
|
||||||
* Two classes are defined: connected and unconnected. UDP objects are
|
* Two classes are defined: connected and unconnected. UDP objects are
|
||||||
* originally unconnected. They can be "connected" to a given address
|
* originally unconnected. They can be "connected" to a given address
|
||||||
* with a call to the setpeername function. The same function can be used to
|
* with a call to the setpeername function. The same function can be used to
|
||||||
* break the connection.
|
* break the connection.
|
||||||
*
|
|
||||||
* RCS ID: $Id$
|
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include "lua.h"
|
#include "luasocket.h"
|
||||||
|
|
||||||
#include "timeout.h"
|
#include "timeout.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
/* can't be larger than wsocket.c MAXCHUNK!!! */
|
|
||||||
#define UDP_DATAGRAMSIZE 8192
|
#define UDP_DATAGRAMSIZE 8192
|
||||||
|
|
||||||
typedef struct t_udp_ {
|
typedef struct t_udp_ {
|
||||||
t_socket sock;
|
t_socket sock;
|
||||||
t_timeout tm;
|
t_timeout tm;
|
||||||
|
int family;
|
||||||
} t_udp;
|
} t_udp;
|
||||||
typedef t_udp *p_udp;
|
typedef t_udp *p_udp;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility push(hidden)
|
||||||
|
#endif
|
||||||
|
|
||||||
int udp_open(lua_State *L);
|
int udp_open(lua_State *L);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#pragma GCC visibility pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* UDP_H */
|
#endif /* UDP_H */
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user