aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Maclennan <caleb@alerque.com>2023-11-10 09:12:04 +0300
committerCaleb Maclennan <caleb@alerque.com>2023-11-10 09:12:04 +0300
commit5c4fc93d5f4137bf4c22ddf1a048c907a4a26727 (patch)
treea9a68e1f6a9c3bfe2b64fa1c3a4098865b7d3b5d
parentccef3bc4e2aa6ee5b997a80aabb58f4ff0b0e98f (diff)
parent43a97b7f0053313b43906371dbdc226271e6c8ab (diff)
downloadluasocket-hjelmeland-patch-1.tar.gz
luasocket-hjelmeland-patch-1.tar.bz2
luasocket-hjelmeland-patch-1.zip
Merge branch 'master' into hjelmeland-patch-1hjelmeland-patch-1
-rw-r--r--.editorconfig23
-rw-r--r--.github/workflows/build.yml50
-rw-r--r--.github/workflows/deploy.yml34
-rw-r--r--.github/workflows/luacheck.yml13
-rw-r--r--.gitignore1
-rw-r--r--.luacheckrc29
-rw-r--r--.travis.yml54
-rw-r--r--CHANGELOG.md65
-rw-r--r--FIX28
-rw-r--r--LICENSE3
-rwxr-xr-xLua.props49
-rw-r--r--Lua51.props28
-rw-r--r--Lua52.props28
-rw-r--r--NEW44
-rw-r--r--README11
-rw-r--r--README.md12
-rw-r--r--TODO81
-rw-r--r--TODO.md135
-rw-r--r--WISH22
-rw-r--r--doc/index.html215
-rw-r--r--doc/lua05.pptbin304128 -> 0 bytes
-rw-r--r--docs/dns.html (renamed from doc/dns.html)78
-rw-r--r--docs/ftp.html (renamed from doc/ftp.html)123
-rw-r--r--docs/http.html (renamed from doc/http.html)151
-rw-r--r--docs/index.html138
-rw-r--r--docs/installation.html (renamed from doc/installation.html)2
-rw-r--r--docs/introduction.html (renamed from doc/introduction.html)0
-rw-r--r--docs/logo.ps (renamed from logo.ps)0
-rw-r--r--docs/ltn12.html (renamed from doc/ltn12.html)206
-rw-r--r--docs/luasocket.png (renamed from doc/luasocket.png)bin11732 -> 11732 bytes
-rw-r--r--docs/mime.html (renamed from doc/mime.html)339
-rw-r--r--docs/reference.css (renamed from doc/reference.css)0
-rw-r--r--docs/reference.html (renamed from doc/reference.html)29
-rw-r--r--docs/smtp.html (renamed from doc/smtp.html)382
-rw-r--r--docs/socket.html (renamed from doc/socket.html)337
-rw-r--r--docs/tcp.html (renamed from doc/tcp.html)533
-rw-r--r--docs/udp.html (renamed from doc/udp.html)464
-rw-r--r--docs/url.html (renamed from doc/url.html)0
-rw-r--r--etc/README89
-rw-r--r--gem/ex1.lua4
-rw-r--r--gem/ex10.lua17
-rw-r--r--gem/ex11.lua7
-rw-r--r--gem/ex12.lua34
-rw-r--r--gem/ex2.lua11
-rw-r--r--gem/ex3.lua15
-rw-r--r--gem/ex4.lua5
-rw-r--r--gem/ex5.lua15
-rw-r--r--gem/ex6.lua14
-rw-r--r--gem/ex7.lua16
-rw-r--r--gem/ex8.lua5
-rw-r--r--gem/ex9.lua3
-rw-r--r--gem/gem.c54
-rw-r--r--gem/gt.b64206
-rw-r--r--gem/input.binbin11732 -> 0 bytes
-rw-r--r--gem/ltn012.tex695
-rw-r--r--gem/luasocket.pngbin11732 -> 0 bytes
-rw-r--r--gem/makefile14
-rwxr-xr-xgem/myps2pdf113
-rw-r--r--gem/t1.lua25
-rw-r--r--gem/t1lf.txt5
-rw-r--r--gem/t2.lua36
-rw-r--r--gem/t2.txt4
-rw-r--r--gem/t2gt.qp5
-rw-r--r--gem/t3.lua25
-rw-r--r--gem/t4.lua10
-rw-r--r--gem/t5.lua30
-rw-r--r--gem/test.lua46
-rw-r--r--linux.cmd2
-rw-r--r--ltn012.md390
-rw-r--r--ltn012.wiki393
-rw-r--r--ltn013.md191
-rw-r--r--ltn013.wiki194
-rw-r--r--luasocket-scm-0.rockspec101
-rw-r--r--luasocket-scm-3.rockspec134
-rw-r--r--macosx.cmd2
-rwxr-xr-x[-rw-r--r--]makefile8
-rw-r--r--makefile.dist72
-rwxr-xr-xmime.vcxproj56
-rw-r--r--mime.vcxproj.filters16
-rw-r--r--rockspecs/luasocket-3.0.0-1.rockspec134
-rw-r--r--rockspecs/luasocket-3.0rc1-2.rockspec108
-rw-r--r--rockspecs/luasocket-3.1.0-1.rockspec135
-rw-r--r--samples/README90
-rw-r--r--samples/b64.lua (renamed from etc/b64.lua)0
-rw-r--r--samples/cddb.lua2
-rw-r--r--samples/check-links.lua (renamed from etc/check-links.lua)0
-rw-r--r--samples/check-memory.lua (renamed from etc/check-memory.lua)0
-rw-r--r--samples/cookie.lua (renamed from etc/cookie.lua)22
-rw-r--r--samples/dict.lua (renamed from etc/dict.lua)0
-rw-r--r--samples/dispatch.lua (renamed from etc/dispatch.lua)0
-rw-r--r--samples/eol.lua (renamed from etc/eol.lua)0
-rw-r--r--samples/forward.lua (renamed from etc/forward.lua)0
-rw-r--r--samples/get.lua (renamed from etc/get.lua)2
-rw-r--r--samples/links (renamed from etc/links)0
-rw-r--r--samples/lp.lua (renamed from etc/lp.lua)0
-rw-r--r--samples/qp.lua (renamed from etc/qp.lua)0
-rw-r--r--samples/tftp.lua (renamed from etc/tftp.lua)0
-rwxr-xr-xsocket.vcxproj135
-rw-r--r--socket.vcxproj.filters51
-rw-r--r--src/auxiliar.c10
-rw-r--r--src/auxiliar.h20
-rw-r--r--src/buffer.c10
-rw-r--r--src/buffer.h15
-rw-r--r--src/compat.c22
-rw-r--r--src/compat.h19
-rw-r--r--src/except.c62
-rw-r--r--src/except.h33
-rw-r--r--src/ftp.lua92
-rw-r--r--src/http.lua131
-rwxr-xr-x[-rw-r--r--]src/inet.c20
-rw-r--r--src/inet.h26
-rw-r--r--src/io.c4
-rw-r--r--src/io.h13
-rw-r--r--src/ltn12.lua15
-rwxr-xr-x[-rw-r--r--]src/luasocket.c12
-rw-r--r--src/luasocket.h15
-rwxr-xr-x[-rw-r--r--]src/makefile174
-rw-r--r--src/mbox.lua15
-rwxr-xr-x[-rw-r--r--]src/mime.c165
-rw-r--r--src/mime.h11
-rw-r--r--src/mime.lua15
-rw-r--r--src/options.c175
-rw-r--r--src/options.h110
-rw-r--r--src/select.c17
-rw-r--r--src/select.h8
-rw-r--r--src/serial.c7
-rwxr-xr-x[-rw-r--r--]src/socket.h57
-rw-r--r--src/tcp.c55
-rw-r--r--src/tcp.h10
-rw-r--r--src/timeout.c22
-rw-r--r--src/timeout.h18
-rw-r--r--src/tp.lua12
-rwxr-xr-x[-rw-r--r--]src/udp.c111
-rw-r--r--src/udp.h13
-rw-r--r--src/unix.c349
-rw-r--r--src/unix.h8
-rw-r--r--src/unixdgram.c405
-rw-r--r--src/unixdgram.h28
-rw-r--r--src/unixstream.c355
-rw-r--r--src/unixstream.h29
-rw-r--r--src/url.lua98
-rw-r--r--src/usocket.c15
-rwxr-xr-x[-rw-r--r--]src/wsocket.c29
-rw-r--r--test/auth/.htaccess2
-rw-r--r--test/excepttest.lua32
-rwxr-xr-xtest/find-connect-limit2
-rw-r--r--test/ftptest.lua34
-rw-r--r--test/httptest.lua31
-rw-r--r--test/ltn12test.lua33
-rw-r--r--test/mimetest.lua46
-rw-r--r--test/smtptest.lua20
-rwxr-xr-xtest/tcp-getoptions28
-rw-r--r--test/test_socket_error.lua2
-rw-r--r--test/testclnt.lua1
-rw-r--r--test/testmesg.lua14
-rw-r--r--test/testsupport.lua2
-rwxr-xr-xtest/udp-zero-length-send4
-rwxr-xr-xtest/udp-zero-length-send-recv4
-rw-r--r--test/unixdgramclnt.lua9
-rw-r--r--test/unixdgramsrvr.lua9
-rw-r--r--test/unixstreamclnt.lua (renamed from test/unixclnt.lua)2
-rw-r--r--test/unixstreamsrvr.lua (renamed from test/unixsrvr.lua)2
-rw-r--r--test/urltest.lua211
-rw-r--r--test/utestclnt.lua68
-rw-r--r--test/utestsrvr.lua2
-rwxr-xr-xvc32.bat3
-rwxr-xr-xvc64.bat3
-rwxr-xr-x[-rw-r--r--]win32.cmd13
-rwxr-xr-xwin64.cmd1
169 files changed, 5631 insertions, 5225 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..56ad87d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,23 @@
1root = true
2
3[*]
4end_of_line = lf
5insert_final_newline = true
6trim_trailing_whitespace = true
7charset = utf-8
8
9[{*.lua,*.rockspec,.luacheckrc}]
10indent_style = space
11indent_size = 4
12
13[Makefile]
14indent_style = tab
15indent_size = 4
16
17[*.html]
18indent_style = space
19indent_size = 4
20
21[*.{c,h}]
22indent_style = space
23indent_size = 4
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..49c2c73
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,50 @@
1name: Build
2
3on:
4 push:
5 branches:
6 - master
7 pull_request:
8
9jobs:
10 build:
11 name: Test ${{ matrix.luaVersion }} on ${{ matrix.platform }}
12 strategy:
13 fail-fast: false
14 matrix:
15 luaVersion: [ "5.4", "5.3", "5.2", "5.1", "luajit", "luajit-openresty" ]
16 platform: [ "ubuntu-22.04", "macos-11", "windows-2022" ]
17 runs-on: ${{ matrix.platform }}
18 steps:
19 - name: Checkout
20 uses: actions/checkout@v4
21 - name: Setup ’msvc’
22 if: ${{ startsWith(matrix.platform, 'windows') && !startsWith(matrix.luaVersion, 'luajit') }}
23 uses: ilammy/msvc-dev-cmd@v1
24 - name: Setup ‘lua’
25 uses: leso-kn/gh-actions-lua@v11-staging
26 with:
27 luaVersion: ${{ matrix.luaVersion }}
28 - name: Setup ‘luarocks’
29 uses: hishamhm/gh-actions-luarocks@master
30 - name: Make and install
31 run: |
32 luarocks make -- luasocket-scm-3.rockspec
33 env:
34 DEBUG: DEBUG
35 - name: Run regression tests
36 shell: bash
37 run: |
38 cd test
39 lua hello.lua
40 lua testsrvr.lua > /dev/null &
41 lua testclnt.lua
42 lua stufftest.lua
43 lua excepttest.lua
44 lua test_bind.lua
45 lua test_getaddrinfo.lua
46 lua ltn12test.lua
47 lua mimetest.lua
48 lua urltest.lua
49 lua test_socket_error.lua
50 kill %1
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..acd66ea
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,34 @@
1name: Deploy
2
3on: [ push, workflow_dispatch ]
4
5jobs:
6
7 affected:
8 uses: lunarmodules/.github/.github/workflows/list_affected_rockspecs.yml@main
9
10 build:
11 needs: affected
12 if: ${{ needs.affected.outputs.rockspecs }}
13 uses: lunarmodules/.github/.github/workflows/test_build_rock.yml@main
14 with:
15 rockspecs: ${{ needs.affected.outputs.rockspecs }}
16
17 upload:
18 needs: [ affected, build ]
19 # Only run upload if:
20 # 1. We are on the canonical repository (no uploads from forks)
21 # 2. The current commit is either tagged or on the default branch (the workflow will upload dev/scm rockspecs any
22 # time they are touched, tagged ones whenever the edited rockspec and tag match)
23 # 3. Some rockspecs were changed — this implies the commit changing the rockspec is the same one that gets tagged
24 if: >-
25 ${{
26 github.repository == 'lunarmodules/luasocket' &&
27 ( github.ref_name == 'master' || startsWith(github.ref, 'refs/tags/') ) &&
28 needs.affected.outputs.rockspecs
29 }}
30 uses: lunarmodules/.github/.github/workflows/upload_to_luarocks.yml@main
31 with:
32 rockspecs: ${{ needs.affected.outputs.rockspecs }}
33 secrets:
34 apikey: ${{ secrets.LUAROCKS_APIKEY }}
diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml
new file mode 100644
index 0000000..9cb784c
--- /dev/null
+++ b/.github/workflows/luacheck.yml
@@ -0,0 +1,13 @@
1name: Luacheck
2
3on: [push, pull_request]
4
5jobs:
6
7 luacheck:
8 runs-on: ubuntu-22.04
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v4
12 - name: Luacheck
13 uses: lunarmodules/luacheck@v1
diff --git a/.gitignore b/.gitignore
index 8307483..9ed661c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,6 @@
6*.dll* 6*.dll*
7*.user 7*.user
8*.sdf 8*.sdf
9Lua.props
10Debug 9Debug
11Release 10Release
12*.manifest 11*.manifest
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000..a3b4f63
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1,29 @@
1unused_args = false
2redefined = false
3max_line_length = false
4
5not_globals = {
6 "string.len",
7 "table.getn",
8}
9
10include_files = {
11 "**/*.lua",
12 "**/*.rockspec",
13 ".busted",
14 ".luacheckrc",
15}
16
17exclude_files = {
18 "test/*.lua",
19 "test/**/*.lua",
20 "samples/*.lua",
21 "samples/**/*.lua",
22 "gem/*.lua",
23 "gem/**/*.lua",
24 -- GH Actions Lua Environment
25 ".lua",
26 ".luarocks",
27 ".install",
28}
29
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index fce8a96..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,54 +0,0 @@
1language: erlang
2
3env:
4 global:
5 - LUAROCKS_BASE=luarocks-2.0.13
6 matrix:
7 - LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
8 - LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
9 - LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
10
11branches:
12 only:
13 - master
14
15before_install:
16 - if [ $LUA = "luajit" ]; then
17 sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
18 fi
19 - sudo apt-get install $LUA
20 - sudo apt-get install $LUA_DEV
21 - lua$LUA_SFX -v
22 # Install a recent luarocks release
23 - wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
24 - tar zxvpf $LUAROCKS_BASE.tar.gz
25 - cd $LUAROCKS_BASE
26 - ./configure
27 --lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
28 - sudo make
29 - sudo make install
30 - cd $TRAVIS_BUILD_DIR
31
32
33install:
34 - export DEBUG=DEBUG
35 - sudo -E luarocks make luasocket-scm-0.rockspec
36
37script:
38 - cd test
39 - lua$LUA_SFX hello.lua
40 - lua$LUA_SFX testsrvr.lua > /dev/null &
41 - lua$LUA_SFX testclnt.lua
42 - lua$LUA_SFX stufftest.lua
43 - lua$LUA_SFX excepttest.lua
44 - lua$LUA_SFX test_bind.lua
45 - lua$LUA_SFX test_getaddrinfo.lua
46 - lua$LUA_SFX ltn12test.lua
47 - lua$LUA_SFX mimetest.lua
48 - lua$LUA_SFX urltest.lua
49 - lua$LUA_SFX test_socket_error.lua
50
51notifications:
52 email:
53 on_success: change
54 on_failure: always
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..3a25186
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,65 @@
1# Changelog
2
3## [v3.1.0](https://github.com/lunarmodules/luasocket/releases/v3.1.0) — 2022-07-27
4
5* Add support for TCP Defer Accept – @Zash
6* Add support for TCP Fast Open – @Zash
7* Fix Windows (mingw32) builds – @goldenstein64
8* Avoid build warnings on 64-bit Windows – @rpatters1
9
10## [v3.0.0](https://github.com/lunarmodules/luasocket/releases/v3.0.0) — 2022-03-25
11
12The last time LuaSocket had a stable release tag was 14 years ago when 2.0.2 was tagged.
13A v3 release candidate was tagged 9 years ago.
14Since then it has been downloaded over 3 million times.
15Additionally the Git repository regularly gets several hundred clones a day.
16But 9 years is a long time and even the release candidate has grown a bit long in the tooth.
17Many Linux distros have packaged the current Git HEAD or some specific tested point as dated or otherwise labeled releases.
18256 commits later and having been migrated to the @lunarmodules org namespace on GitHub, please welcome v3.
19
20This release is a "safe-harbor" tag that represents a minimal amount of changes to get a release tagged.
21Beyond some CI tooling, very little code has changed since migration to @lunarmodules ([5b18e47..e47d98f](https://github.com/lunarmodules/luasocket/compare/5b18e47..e47d98f?w=1)):
22
23* Lua 5.4.3+ support – @pkulchenko, @Zash
24* Cleanup minor issues to get a code linter to pass – @Tieske, @jyoui, @alerque
25* Update Visual Studio build rules for Lua 5.1 – @ewestbrook
26* Set http transfer-encoding even without content-length – @tokenrove
27
28Prior to migration to @lunarmodules ([v3.0-rc1..5b18e47](https://github.com/lunarmodules/luasocket/compare/v3.0-rc1..5b18e47?w=1)) many things happened of which the author of this changelog is not fully apprised.
29Your best bet if it affects your project somehow is to read the commit log & diffs yourself.
30
31## [v3.0-rc1](https://github.com/lunarmodules/luasocket/releases/v3.0-rc1) — 2013-06-14
32
33Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
34
35* Added: Compatible with Lua 5.2
36 - Note that unless you define LUA_COMPAT_MODULE, package tables will not be exported as globals!
37* Added: IPv6 support;
38 - Socket.connect and socket.bind support IPv6 addresses;
39 - Getpeername and getsockname support IPv6 addresses, and return the socket family as a third value;
40 - URL module updated to support IPv6 host names;
41 - New socket.tcp6 and socket.udp6 functions;
42 - New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
43* Added: getoption method;
44* Fixed: url.unescape was returning additional values;
45* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could mistaking their own stack slots for functions arguments;
46* Fixed: Receiving zero-length datagram is now possible;
47* Improved: Hidden all internal library symbols;
48* Improved: Better error messages;
49* Improved: Better documentation of socket options.
50* Fixed: manual sample of HTTP authentication now uses correct "authorization" header (Alexandre Ittner);
51* Fixed: failure on bind() was destroying the socket (Sam Roberts);
52* Fixed: receive() returns immediatelly if prefix can satisfy bytes requested (M Joonas Pihlaja);
53* Fixed: multicast didn't work on Windows, or anywhere else for that matter (Herbert Leuwer, Adrian Sietsma);
54* Fixed: select() now reports an error when called with more sockets than FD_SETSIZE (Lorenzo Leonini);
55* Fixed: manual links to home.html changed to index.html (Robert Hahn);
56* Fixed: mime.unb64() would return an empty string on results that started with a null character (Robert Raschke);
57* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
58* Fixed: calling sleep() with negative numbers could block forever, wasting CPU. Now it returns immediately (MPB);
59* Improved: FTP commands are now sent in upper case to help buggy servers (Anders Eurenius);
60* Improved: known headers now sent in canonic capitalization to help buggy servers (Joseph Stewart);
61* Improved: Clarified tcp:receive() in the manual (MPB);
62* Improved: Decent makefiles (LHF).
63* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
64
65## [v2.0.2](https://github.com/lunarmodules/luasocket/releases/v2.0.2) — 2007-09-11
diff --git a/FIX b/FIX
deleted file mode 100644
index 40f30a1..0000000
--- a/FIX
+++ /dev/null
@@ -1,28 +0,0 @@
1
2
3
4
5
6
7http was preserving old host header during redirects
8fix smtp.send hang on source error
9add create field to FTP and SMTP and fix HTTP ugliness
10clean timeout argument to open functions in SMTP, HTTP and FTP
11eliminate globals from namespaces created by module().
12url.absolute was not working when base_url was already parsed
13http.request was redirecting even when the location header was empty
14tcp{client}:shutdown() was checking for group instead of class.
15tcp{client}:send() now returns i+sent-1...
16get rid of a = socket.try() in the manual, except for protected cases. replace it with assert.
17get rid of "base." kludge in package.loaded
18check all "require("http")" etc in the manual.
19make sure sock_gethostname.* only return success if the hp is not null!
20change 'l' prefix in C libraries to 'c' to avoid clash with LHF libraries
21 don't forget the declarations in luasocket.h and mime.h!!!
22setpeername was using udp{unconnected}
23fixed a bug in http.lua that caused some requests to fail (Florian Berger)
24fixed a bug in select.c that prevented sockets with descriptor 0 from working (Renato Maia)
25fixed a "bug" that caused dns.toip to crash under uLinux
26fixed a "bug" that caused a crash in gethostbyname under VMS
27DEBUG and VERSION became _DEBUG and _VERSION
28send returns the right value if input is "". Alexander Marinov
diff --git a/LICENSE b/LICENSE
index b635451..a8ed03e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,4 @@
1LuaSocket 3.0 license 1Copyright (C) 2004-2022 Diego Nehab
2Copyright © 2004-2013 Diego Nehab
3 2
4Permission is hereby granted, free of charge, to any person obtaining a 3Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"), 4copy of this software and associated documentation files (the "Software"),
diff --git a/Lua.props b/Lua.props
new file mode 100755
index 0000000..d748448
--- /dev/null
+++ b/Lua.props
@@ -0,0 +1,49 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ImportGroup Label="PropertySheets" />
4 <PropertyGroup Condition="'$(Platform)'=='x64'" Label="LuaPlat">
5 <LUAPLAT>$(Platform)/$(Configuration)</LUAPLAT>
6 </PropertyGroup>
7 <PropertyGroup Condition="'$(Platform)'=='Win32'" Label="LuaPlat">
8 <LUAPLAT>$(Configuration)</LUAPLAT>
9 </PropertyGroup>
10 <PropertyGroup Label="UserMacros">
11 <LUAV>5.3</LUAV>
12 <LUAPREFIX>z:\data\build\vc14\</LUAPREFIX>
13 <LUALIB>$(LUAPREFIX)\lib\lua\$(LUAV)\$(LUAPLAT)</LUALIB>
14 <LUACDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)</LUACDIR>
15 <LUALDIR>$(LUAPREFIX)\bin\lua\$(LUAV)\$(LUAPLAT)\lua</LUALDIR>
16 <LUAINC>$(LUAPREFIX)\include\lua\$(LUAV);$(LUAPREFIX)\include\lua$(LUAV)</LUAINC>
17 <LUALIBNAME>lua$(LUAV.Replace('.', '')).lib</LUALIBNAME>
18 </PropertyGroup>
19 <PropertyGroup>
20 <_PropertySheetDisplayName>Lua</_PropertySheetDisplayName>
21 </PropertyGroup>
22 <ItemDefinitionGroup />
23 <ItemGroup>
24 <BuildMacro Include="LUAPLAT">
25 <Value>$(LUAPLAT)</Value>
26 </BuildMacro>
27 <BuildMacro Include="LUAPREFIX">
28 <Value>$(LUAPREFIX)</Value>
29 </BuildMacro>
30 <BuildMacro Include="LUAV">
31 <Value>$(LUAV)</Value>
32 </BuildMacro>
33 <BuildMacro Include="LUALIB">
34 <Value>$(LUALIB)</Value>
35 </BuildMacro>
36 <BuildMacro Include="LUAINC">
37 <Value>$(LUAINC)</Value>
38 </BuildMacro>
39 <BuildMacro Include="LUACDIR">
40 <Value>$(LUACDIR)</Value>
41 </BuildMacro>
42 <BuildMacro Include="LUALDIR">
43 <Value>$(LUALDIR)</Value>
44 </BuildMacro>
45 <BuildMacro Include="LUALIBNAME">
46 <Value>$(LUALIBNAME)</Value>
47 </BuildMacro>
48 </ItemGroup>
49</Project>
diff --git a/Lua51.props b/Lua51.props
deleted file mode 100644
index 1bd6256..0000000
--- a/Lua51.props
+++ /dev/null
@@ -1,28 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ImportGroup Label="PropertySheets" />
4 <PropertyGroup Label="UserMacros">
5 <LUABIN_PATH>..\build\vc12\bin\lua\5.1\</LUABIN_PATH>
6 <LUALIB_PATH>..\build\vc12\bin\lua\5.1\</LUALIB_PATH>
7 <LUAINC_PATH>..\build\vc12\include\lua\5.1\</LUAINC_PATH>
8 <LUALIB>lua51.lib</LUALIB>
9 </PropertyGroup>
10 <PropertyGroup>
11 <_PropertySheetDisplayName>Lua51</_PropertySheetDisplayName>
12 </PropertyGroup>
13 <ItemDefinitionGroup />
14 <ItemGroup>
15 <BuildMacro Include="LUALIB_PATH">
16 <Value>$(LUALIB_PATH)</Value>
17 </BuildMacro>
18 <BuildMacro Include="LUABIN_PATH">
19 <Value>$(LUABIN_PATH)</Value>
20 </BuildMacro>
21 <BuildMacro Include="LUAINC_PATH">
22 <Value>$(LUAINC_PATH)</Value>
23 </BuildMacro>
24 <BuildMacro Include="LUALIB">
25 <Value>$(LUALIB)</Value>
26 </BuildMacro>
27 </ItemGroup>
28</Project>
diff --git a/Lua52.props b/Lua52.props
deleted file mode 100644
index 01afcfa..0000000
--- a/Lua52.props
+++ /dev/null
@@ -1,28 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ImportGroup Label="PropertySheets" />
4 <PropertyGroup Label="UserMacros">
5 <LUABIN_PATH>..\build\vc12\bin\lua\5.2\</LUABIN_PATH>
6 <LUALIB_PATH>..\build\vc12\bin\lua\5.2\</LUALIB_PATH>
7 <LUAINC_PATH>..\build\vc12\include\lua\5.2\</LUAINC_PATH>
8 <LUALIB>lua52.lib</LUALIB>
9 </PropertyGroup>
10 <PropertyGroup>
11 <_PropertySheetDisplayName>Lua52</_PropertySheetDisplayName>
12 </PropertyGroup>
13 <ItemDefinitionGroup />
14 <ItemGroup>
15 <BuildMacro Include="LUALIB_PATH">
16 <Value>$(LUALIB_PATH)</Value>
17 </BuildMacro>
18 <BuildMacro Include="LUABIN_PATH">
19 <Value>$(LUABIN_PATH)</Value>
20 </BuildMacro>
21 <BuildMacro Include="LUAINC_PATH">
22 <Value>$(LUAINC_PATH)</Value>
23 </BuildMacro>
24 <BuildMacro Include="LUALIB">
25 <Value>$(LUALIB)</Value>
26 </BuildMacro>
27 </ItemGroup>
28</Project>
diff --git a/NEW b/NEW
deleted file mode 100644
index 0bff64c..0000000
--- a/NEW
+++ /dev/null
@@ -1,44 +0,0 @@
1What's New
2
3Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
4
5 * Added: Compatible with Lua 5.2
6 - Note that unless you define LUA_COMPAT_MODULE, package
7 tables will not be exported as globals!
8 * Added: IPv6 support;
9 - Socket.connect and socket.bind support IPv6 addresses;
10 - Getpeername and getsockname support IPv6 addresses, and
11 return the socket family as a third value;
12 - URL module updated to support IPv6 host names;
13 - New socket.tcp6 and socket.udp6 functions;
14 - New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
15 * Added: getoption method;
16 * Fixed: url.unescape was returning additional values;
17 * Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could
18 mistaking their own stack slots for functions arguments;
19 * Fixed: Receiving zero-length datagram is now possible;
20 * Improved: Hidden all internal library symbols;
21 * Improved: Better error messages;
22 * Improved: Better documentation of socket options.
23 * Fixed: manual sample of HTTP authentication now uses correct
24 "authorization" header (Alexandre Ittner);
25 * Fixed: failure on bind() was destroying the socket (Sam Roberts);
26 * Fixed: receive() returns immediatelly if prefix can satisfy
27 bytes requested (M Joonas Pihlaja);
28 * Fixed: multicast didn't work on Windows, or anywhere
29 else for that matter (Herbert Leuwer, Adrian Sietsma);
30 * Fixed: select() now reports an error when called with more
31 sockets than FD_SETSIZE (Lorenzo Leonini);
32 * Fixed: manual links to home.html changed to index.html (Robert Hahn);
33 * Fixed: mime.unb64() would return an empty string on results that started
34 with a null character (Robert Raschke);
35 * Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
36 * Fixed: calling sleep() with negative numbers could
37 block forever, wasting CPU. Now it returns immediately (MPB);
38 * Improved: FTP commands are now sent in upper case to
39 help buggy servers (Anders Eurenius);
40 * Improved: known headers now sent in canonic
41 capitalization to help buggy servers (Joseph Stewart);
42 * Improved: Clarified tcp:receive() in the manual (MPB);
43 * Improved: Decent makefiles (LHF).
44 * Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
diff --git a/README b/README
deleted file mode 100644
index cd8ee59..0000000
--- a/README
+++ /dev/null
@@ -1,11 +0,0 @@
1This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
2and Linux.
3
4Please use the project page at GitHub
5
6 https://github.com/diegonehab/luasocket
7
8to file bug reports or propose changes.
9
10Have fun,
11Diego Nehab.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6f5657c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
1# LuaSocket
2
3
4[![Build](https://img.shields.io/github/actions/workflow/status/lunarmodules/luasocket/build.yml?branch=master&label=Build&logo=Lua)](https://github.com/lunarmodules/luasocket/actions?workflow=Build)
5[![Luacheck](https://img.shields.io/github/actions/workflow/status/lunarmodules/luasocket/luacheck.yml?branch=master&label=Luacheck&logo=Lua)](https://github.com/lunarmodules/luasocket/actions?workflow=Luacheck)
6[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/lunarmodules/luasocket?label=Tag&logo=GitHub)](https://github.com/lunarmodules/luasocket/releases)
7[![Luarocks](https://img.shields.io/luarocks/v/lunarmodules/luasocket?label=Luarocks&logo=Lua)](https://luarocks.org/modules/lunarmodules/luasocket)
8
9LuaSocket is a Lua extension library composed of two parts:
10
111. a set of C modules that provide support for the TCP and UDP transport layers, and
122. a set of Lua modules that provide functions commonly needed by applications that deal with the Internet.
diff --git a/TODO b/TODO
deleted file mode 100644
index a838fc0..0000000
--- a/TODO
+++ /dev/null
@@ -1,81 +0,0 @@
1- bizarre default values for getnameinfo should throw error instead!
2
3> It's just too bad it can't talk to gmail -
4> reason 1: they absolutely want TLS
5> reason 2: unlike all the other SMTP implementations, they
6> don't
7> tolerate missing < > around adresses
8
9- document the new bind and connect behavior.
10- shouldn't we instead make the code compatible to Lua 5.2
11 without any compat stuff, and use a compatibility layer to
12 make it work on 5.1?
13- add what's new to manual
14- should there be an equivalent to tohostname for IPv6?
15- should we add service name resolution as well to getaddrinfo?
16- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
17
18- add http POST sample to manual
19 people keep asking stupid questions
20- documentation of dirty/getfd/setfd is problematic because of portability
21 same for unix and serial.
22 what to do about this? add a stronger disclaimer?
23- fix makefile with decent defaults?
24
25Done:
26
27- added IPv6 support to getsockname
28- simplified getpeername implementation
29- added family to return of getsockname and getpeername
30 and added modification to the manual to describe
31
32- connect and bind try all adresses returned by getaddrinfo
33- document headers.lua?
34- update copyright date everywhere?
35- remove RCSID from files?
36- move version to 2.1 rather than 2.1.1?
37- fixed url package to support ipv6 hosts
38- changed domain to family
39- implement getfamily methods.
40
41- remove references to Lua 5.0 from documentation, add 5.2?
42- update lua and luasocket version in samples in documentation
43- document ipv5_v6only default option being set?
44- document tcp6 and udp6
45- document dns.getaddrinfo
46- documented zero-sized datagram change?
47 no.
48- document unix socket and serial socket? add raw support?
49 no.
50- document getoption
51- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
52
53
54
55
56
57
58
59
60
61
62replace \r\n with \0xD\0xA in everything
63New mime support
64
65ftp send should return server replies?
66make sure there are no object files in the distribution tarball
67http handling of 100-continue, see DB patch
68DB ftp.lua bug.
69test unix.c to return just a function and works with require"unix"
70get rid of setmetatable(, nil) since packages don't need this anymore in 5.1
71compat-5.1 novo
72ajeitar pra lua-5.1
73
74adicionar exemplos de expansão: pipe, local, named pipe
75testar os options!
76
77
78- Thread-unsafe functions to protect
79 gethostbyname(), gethostbyaddr(), gethostent(),
80inet_ntoa(), strerror(),
81
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..d265694
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,135 @@
1## FIX
2
3http was preserving old host header during redirects
4fix smtp.send hang on source error
5add create field to FTP and SMTP and fix HTTP ugliness
6clean timeout argument to open functions in SMTP, HTTP and FTP
7eliminate globals from namespaces created by module().
8url.absolute was not working when base_url was already parsed
9http.request was redirecting even when the location header was empty
10tcp{client}:shutdown() was checking for group instead of class.
11tcp{client}:send() now returns i+sent-1...
12get rid of a = socket.try() in the manual, except for protected cases. replace it with assert.
13get rid of "base." kludge in package.loaded
14check all "require("http")" etc in the manual.
15make sure sock_gethostname.* only return success if the hp is not null!
16change 'l' prefix in C libraries to 'c' to avoid clash with LHF libraries
17 don't forget the declarations in luasocket.h and mime.h!!!
18setpeername was using udp{unconnected}
19fixed a bug in http.lua that caused some requests to fail (Florian Berger)
20fixed a bug in select.c that prevented sockets with descriptor 0 from working (Renato Maia)
21fixed a "bug" that caused dns.toip to crash under uLinux
22fixed a "bug" that caused a crash in gethostbyname under VMS
23DEBUG and VERSION became _DEBUG and _VERSION
24send returns the right value if input is "". Alexander Marinov
25
26
27## WISH
28
29... as an l-value to get all results of a function call?
30at least ...[i] and #...
31extend to full tuples?
32
33__and __or __not metamethods
34
35lua_tostring, lua_tonumber, lua_touseradta etc push values in stack
36__tostring,__tonumber, __touserdata metamethods are checked
37and expected to push an object of correct type on stack
38
39lua_rawtostring, lua_rawtonumber, lua_rawtouserdata don't
40push anything on stack, return data of appropriate type,
41skip metamethods and throw error if object not of exact type
42
43package.findfile exported
44module not polluting the global namespace
45
46coxpcall with a coroutine pool for efficiency (reusing coroutines)
47
48exception mechanism formalized? just like the package system was.
49
50a nice bitlib in the core
51
52
53## TODO
54
55- bizarre default values for getnameinfo should throw error instead!
56
57> It's just too bad it can't talk to gmail -
58> reason 1: they absolutely want TLS
59> reason 2: unlike all the other SMTP implementations, they
60> don't
61> tolerate missing < > around adresses
62
63- document the new bind and connect behavior.
64- shouldn't we instead make the code compatible to Lua 5.2
65 without any compat stuff, and use a compatibility layer to
66 make it work on 5.1?
67- add what's new to manual
68- should there be an equivalent to tohostname for IPv6?
69- should we add service name resolution as well to getaddrinfo?
70- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
71
72- add http POST sample to manual
73 people keep asking stupid questions
74- documentation of dirty/getfd/setfd is problematic because of portability
75 same for unix and serial.
76 what to do about this? add a stronger disclaimer?
77- fix makefile with decent defaults?
78
79## Done:
80
81- added IPv6 support to getsockname
82- simplified getpeername implementation
83- added family to return of getsockname and getpeername
84 and added modification to the manual to describe
85
86- connect and bind try all adresses returned by getaddrinfo
87- document headers.lua?
88- update copyright date everywhere?
89- remove RCSID from files?
90- move version to 2.1 rather than 2.1.1?
91- fixed url package to support ipv6 hosts
92- changed domain to family
93- implement getfamily methods.
94
95- remove references to Lua 5.0 from documentation, add 5.2?
96- update lua and luasocket version in samples in documentation
97- document ipv5_v6only default option being set?
98- document tcp6 and udp6
99- document dns.getaddrinfo
100- documented zero-sized datagram change?
101 no.
102- document unix socket and serial socket? add raw support?
103 no.
104- document getoption
105- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
106
107
108
109
110
111
112
113
114
115
116replace \r\n with \0xD\0xA in everything
117New mime support
118
119ftp send should return server replies?
120make sure there are no object files in the distribution tarball
121http handling of 100-continue, see DB patch
122DB ftp.lua bug.
123test unix.c to return just a function and works with require"unix"
124get rid of setmetatable(, nil) since packages don't need this anymore in 5.1
125compat-5.1 novo
126ajeitar pra lua-5.1
127
128adicionar exemplos de expans�o: pipe, local, named pipe
129testar os options!
130
131
132- Thread-unsafe functions to protect
133 gethostbyname(), gethostbyaddr(), gethostent(),
134inet_ntoa(), strerror(),
135
diff --git a/WISH b/WISH
deleted file mode 100644
index e7e9c07..0000000
--- a/WISH
+++ /dev/null
@@ -1,22 +0,0 @@
1... as an l-value to get all results of a function call?
2at least ...[i] and #...
3extend to full tuples?
4
5__and __or __not metamethods
6
7lua_tostring, lua_tonumber, lua_touseradta etc push values in stack
8__tostring,__tonumber, __touserdata metamethods are checked
9and expected to push an object of correct type on stack
10
11lua_rawtostring, lua_rawtonumber, lua_rawtouserdata don't
12push anything on stack, return data of appropriate type,
13skip metamethods and throw error if object not of exact type
14
15package.findfile exported
16module not polluting the global namespace
17
18coxpcall with a coroutine pool for efficiency (reusing coroutines)
19
20exception mechanism formalized? just like the package system was.
21
22a nice bitlib in the core
diff --git a/doc/index.html b/doc/index.html
deleted file mode 100644
index 7d81b41..0000000
--- a/doc/index.html
+++ /dev/null
@@ -1,215 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd">
3<html>
4
5<head>
6<meta name="description" content="The LuaSocket Homepage">
7<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
8<title>LuaSocket: Network support for the Lua language </title>
9<link rel="stylesheet" href="reference.css" type="text/css">
10</head>
11
12<body>
13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15
16<div class=header>
17<hr>
18<center>
19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language
24</td></tr>
25</table>
26<p class=bar>
27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a>
32</p>
33</center>
34<hr>
35</div>
36
37<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38
39<h2 id=whatis>What is LuaSocket?</h2>
40
41<p>
42LuaSocket is a <a href="http://www.lua.org">Lua</a> extension library
43that is composed by two parts: a C core that provides support for the TCP
44and UDP transport layers, and a set of Lua modules that add support for
45functionality commonly needed by applications that deal with the Internet.
46</p>
47
48<p>
49The core support has been implemented so that it is both efficient and
50simple to use. It is available to any Lua application once it has been
51properly initialized by the interpreter in use. The code has been tested
52and runs well on several Windows and UNIX platforms. </p>
53
54<p>
55Among the support modules, the most commonly used implement the
56<a href=smtp.html>SMTP</a>
57(sending e-mails),
58<a href=http.html>HTTP</a>
59(WWW access) and
60<a href=ftp.html>FTP</a>
61(uploading and downloading files) client
62protocols. These provide a very natural and generic interface to the
63functionality defined by each protocol.
64In addition, you will find that the
65<a href=mime.html>MIME</a> (common encodings),
66<a href=url.html>URL</a>
67(anything you could possible want to do with one) and
68<a href=ltn12.html>LTN12</a>
69(filters, sinks, sources and pumps) modules can be very handy.
70</p>
71
72<p>
73The library is available under the same
74<a href="http://www.lua.org/copyright.html">
75terms and conditions</a> as the Lua language, the MIT license. The idea is
76that if you can use Lua in a project, you should also be able to use
77LuaSocket.
78</p>
79
80<p>
81Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
82Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
83</p>
84
85<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
86
87<h2 id=download>Download</h2>
88
89<p>
90LuaSocket version 3.0-rc1 is now available for download!
91It is compatible with Lua&nbsp;5.1 and 5.2, and has
92been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
93are it works well on most UNIX distributions and Windows flavors.
94</p>
95
96<p>
97The current version of the library can be found at
98the <a href="https://github.com/diegonehab/luasocket">LuaSocket
99project page</a> on GitHub. Besides the full C and Lua source code
100for the library, the distribution contains several examples,
101this user's manual and basic test procedures.
102</p>
103
104<p> Take a look at the <a
105href=installation.html>installation</a> section of the
106manual to find out how to properly install the library.
107</p>
108
109<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
110
111<h2 id=thanks>Special thanks</h2>
112
113<p>
114This marks the first release of LuaSocket that
115wholeheartedly embraces the open-source development
116philosophy. After a long hiatus, Matthew Wild finally
117convinced me it was time for a release including IPv6 and
118Lua 5.2 support. It was more work than we anticipated.
119Special thanks to Sam Roberts, Florian Zeitz, and Paul
120Aurich, Liam Devine, Alexey Melnichuk, and everybody else
121that has helped bring this library back to life.
122</p>
123
124<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
125
126<h2 id=new>What's New</h2>
127
128<p>
129Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
130and Lua&nbsp;5.2 compatibility.
131</p>
132
133<ul>
134<li> Added: Compatible with Lua&nbsp;5.2
135<ul>
136<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
137package tables will <em>not</em> be exported as globals!
138</ul>
139<li> Added: IPv6 support;
140<ul>
141<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
142<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
143IPv6 addresses, and return the socket family as a third value;
144<li> URL module updated to support IPv6 host names;
145<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
146<li> New <tt>socket.dns.getaddrinfo</tt> and
147 <tt>socket.dns.getnameinfo</tt> functions;
148</ul>
149<li> Added: <tt>getoption</tt> method;
150<li> Fixed: <tt>url.unescape</tt> was returning additional values;
151<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
152 <tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
153 mistaking their own stack slots for functions arguments;
154<li> Fixed: Receiving zero-length datagram is now possible;
155<li> Improved: Hidden all internal library symbols;
156<li> Improved: Better error messages;
157<li> Improved: Better documentation of socket options.
158<li> Fixed: manual sample of HTTP authentication now uses correct
159 "authorization" header (Alexandre Ittner);
160<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
161<li> Fixed: receive() returns immediatelly if prefix can satisfy
162 bytes requested (M Joonas Pihlaja);
163<li> Fixed: multicast didn't work on Windows, or anywhere
164 else for that matter (Herbert Leuwer, Adrian Sietsma);
165<li> Fixed: select() now reports an error when called with more
166 sockets than FD_SETSIZE (Lorenzo Leonini);
167<li> Fixed: manual links to home.html changed to index.html
168(Robert Hahn);
169<li> Fixed: mime.unb64() would return an empty string on results that started
170 with a null character (Robert Raschke);
171<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
172<li> Fixed: calling sleep() with negative numbers could
173 block forever, wasting CPU. Now it returns immediately (MPB);
174<li> Improved: FTP commands are now sent in upper case to
175 help buggy servers (Anders Eurenius);
176<li> Improved: known headers now sent in canonic
177 capitalization to help buggy servers (Joseph Stewart);
178<li> Improved: Clarified tcp:receive() in the manual (MPB);
179<li> Improved: Decent makefiles (LHF).
180<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
181</ul>
182
183<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
184
185<h2 id=old>Old Versions</h2>
186
187<p>
188All previous versions of the LuaSocket library can be downloaded <a
189href="http://www.impa.br/~diego/software/luasocket/old">
190here</a>. Although these versions are no longer supported, they are
191still available for those that have compatibility issues.
192</p>
193
194<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
195
196<div class=footer>
197<hr>
198<center>
199<p class=bar>
200<a href="index.html#download">download</a> &middot;
201<a href="installation.html">installation</a> &middot;
202<a href="introduction.html">introduction</a> &middot;
203<a href="reference.html">reference</a>
204</p>
205<p>
206<small>
207Last modified by Diego Nehab on <br>
208Tue Jun 11 18:50:23 HKT 2013
209</small>
210</p>
211</center>
212</div>
213
214</body>
215</html>
diff --git a/doc/lua05.ppt b/doc/lua05.ppt
deleted file mode 100644
index e2b7ab4..0000000
--- a/doc/lua05.ppt
+++ /dev/null
Binary files differ
diff --git a/doc/dns.html b/docs/dns.html
index c4a0472..56ce3ba 100644
--- a/doc/dns.html
+++ b/docs/dns.html
@@ -1,4 +1,4 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
@@ -13,22 +13,22 @@
13 13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,14 +36,14 @@
36 36
37<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id=dns>DNS</h2> 39<h2 id="dns">DNS</h2>
40 40
41<p> 41<p>
42IPv4 name resolution functions 42IPv4 name resolution functions
43<a href=#toip><tt>dns.toip</tt></a> 43<a href="#toip"><tt>dns.toip</tt></a>
44and 44and
45<a href=#tohostname><tt>dns.tohostname</tt></a> 45<a href="#tohostname"><tt>dns.tohostname</tt></a>
46return <em>all</em> information obtained from 46return <em>all</em> information obtained from
47the resolver in a table of the form: 47the resolver in a table of the form:
48</p> 48</p>
49 49
@@ -60,10 +60,10 @@ Note that the <tt>alias</tt> list can be empty.
60</p> 60</p>
61 61
62<p> 62<p>
63The more general name resolution function 63The more general name resolution function
64<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which 64<a href="#getaddrinfo"><tt>dns.getaddrinfo</tt></a>, which
65supports both IPv6 and IPv4, 65supports both IPv6 and IPv4,
66returns <em>all</em> information obtained from 66returns <em>all</em> information obtained from
67the resolver in a table of the form: 67the resolver in a table of the form:
68</p> 68</p>
69 69
@@ -88,82 +88,82 @@ addresses, and <tt>"inet6"</tt> for IPv6 addresses.
88 88
89<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 89<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
90 90
91<p class=name id=getaddrinfo> 91<p class="name" id="getaddrinfo">
92socket.dns.<b>getaddrinfo(</b>address<b>)</b> 92socket.dns.<b>getaddrinfo(</b>address<b>)</b>
93</p> 93</p>
94 94
95<p class=description> 95<p class="description">
96Converts from host name to address. 96Converts from host name to address.
97</p> 97</p>
98 98
99<p class=parameters> 99<p class="parameters">
100<tt>Address</tt> can be an IPv4 or IPv6 address or host name. 100<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
101</p> 101</p>
102 102
103<p class=return> 103<p class="return">
104The function returns a table with all information returned by 104The function returns a table with all information returned by
105the resolver. In case of error, the function returns <b><tt>nil</tt></b> 105the resolver. In case of error, the function returns <b><tt>nil</tt></b>
106followed by an error message. 106followed by an error message.
107</p> 107</p>
108 108
109<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 109<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
110 110
111<p class=name id=gethostname> 111<p class="name" id="gethostname">
112socket.dns.<b>gethostname()</b> 112socket.dns.<b>gethostname()</b>
113</p> 113</p>
114 114
115<p class=description> 115<p class="description">
116Returns the standard host name for the machine as a string. 116Returns the standard host name for the machine as a string.
117</p> 117</p>
118 118
119<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 119<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
120 120
121<p class=name id=tohostname> 121<p class="name" id="tohostname">
122socket.dns.<b>tohostname(</b>address<b>)</b> 122socket.dns.<b>tohostname(</b>address<b>)</b>
123</p> 123</p>
124 124
125<p class=description> 125<p class="description">
126Converts from IPv4 address to host name. 126Converts from IPv4 address to host name.
127</p> 127</p>
128 128
129<p class=parameters> 129<p class="parameters">
130<tt>Address</tt> can be an IP address or host name. 130<tt>Address</tt> can be an IP address or host name.
131</p> 131</p>
132 132
133<p class=return> 133<p class="return">
134The function returns a string with the canonic host name of the given 134The function returns a string with the canonic host name of the given
135<tt>address</tt>, followed by a table with all information returned by 135<tt>address</tt>, followed by a table with all information returned by
136the resolver. In case of error, the function returns <b><tt>nil</tt></b> 136the resolver. In case of error, the function returns <b><tt>nil</tt></b>
137followed by an error message. 137followed by an error message.
138</p> 138</p>
139 139
140<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 140<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
141 141
142<p class=name id=toip> 142<p class="name" id="toip">
143socket.dns.<b>toip(</b>address<b>)</b> 143socket.dns.<b>toip(</b>address<b>)</b>
144</p> 144</p>
145 145
146<p class=description> 146<p class="description">
147Converts from host name to IPv4 address. 147Converts from host name to IPv4 address.
148</p> 148</p>
149 149
150<p class=parameters> 150<p class="parameters">
151<tt>Address</tt> can be an IP address or host name. 151<tt>Address</tt> can be an IP address or host name.
152</p> 152</p>
153 153
154<p class=return> 154<p class="return">
155Returns a string with the first IP address found for <tt>address</tt>, 155Returns a string with the first IP address found for <tt>address</tt>,
156followed by a table with all information returned by the resolver. 156followed by a table with all information returned by the resolver.
157In case of error, the function returns <b><tt>nil</tt></b> followed by an error 157In case of error, the function returns <b><tt>nil</tt></b> followed by an error
158message. 158message.
159</p> 159</p>
160 160
161<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 161<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
162 162
163<div class=footer> 163<div class="footer">
164<hr> 164<hr>
165<center> 165<center>
166<p class=bar> 166<p class="bar">
167<a href="index.html">home</a> &middot; 167<a href="index.html">home</a> &middot;
168<a href="index.html#down">download</a> &middot; 168<a href="index.html#down">download</a> &middot;
169<a href="installation.html">installation</a> &middot; 169<a href="installation.html">installation</a> &middot;
diff --git a/doc/ftp.html b/docs/ftp.html
index 3f23a4a..7f7da2e 100644
--- a/doc/ftp.html
+++ b/docs/ftp.html
@@ -1,5 +1,5 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
@@ -13,22 +13,22 @@
13 13
14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,7 +36,7 @@
36 36
37<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id=ftp>FTP</h2> 39<h2 id="ftp">FTP</h2>
40 40
41<p> 41<p>
42FTP (File Transfer Protocol) is a protocol used to transfer files 42FTP (File Transfer Protocol) is a protocol used to transfer files
@@ -50,28 +50,28 @@ High level functions are provided supporting the most common operations.
50These high level functions are implemented on top of a lower level 50These high level functions are implemented on top of a lower level
51interface. Using the low-level interface, users can easily create their 51interface. Using the low-level interface, users can easily create their
52own functions to access <em>any</em> operation supported by the FTP 52own functions to access <em>any</em> operation supported by the FTP
53protocol. For that, check the implementation. 53protocol. For that, check the implementation.
54</p> 54</p>
55 55
56<p> 56<p>
57To really benefit from this module, a good understanding of 57To really benefit from this module, a good understanding of
58<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> 58<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
59LTN012, Filters sources and sinks</a> is necessary. 59LTN012, Filters sources and sinks</a> is necessary.
60</p> 60</p>
61 61
62<p> 62<p>
63To obtain the <tt>ftp</tt> namespace, run: 63To obtain the <tt>ftp</tt> namespace, run:
64</p> 64</p>
65 65
66<pre class=example> 66<pre class="example">
67-- loads the FTP module and any libraries it requires 67-- loads the FTP module and any libraries it requires
68local ftp = require("socket.ftp") 68local ftp = require("socket.ftp")
69</pre> 69</pre>
70 70
71<p> 71<p>
72URLs MUST conform to 72URLs MUST conform to
73<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>, 73<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
74that is, an URL is a string in the form: 74that is, an URL is a string in the form:
75</p> 75</p>
76 76
77<blockquote> 77<blockquote>
@@ -81,20 +81,19 @@ that is, an URL is a string in the form:
81 81
82<p> 82<p>
83The following constants in the namespace can be set to control the default behavior of 83The following constants in the namespace can be set to control the default behavior of
84the FTP module: 84the FTP module:
85</p> 85</p>
86 86
87<ul> 87<ul>
88<li> <tt>PASSWORD</tt>: default anonymous password. 88<li> <tt>PASSWORD</tt>: default anonymous password.</li>
89<li> <tt>PORT</tt>: default port used for the control connection; 89<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
90<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; 90<li> <tt>USER</tt>: default anonymous user;</li>
91<li> <tt>USER</tt>: default anonymous user;
92</ul> 91</ul>
93 92
94 93
95<!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 94<!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
96 95
97<p class=name id=get> 96<p class="name" id="get">
98ftp.<b>get(</b>url<b>)</b><br> 97ftp.<b>get(</b>url<b>)</b><br>
99ftp.<b>get{</b><br> 98ftp.<b>get{</b><br>
100&nbsp;&nbsp;host = <i>string</i>,<br> 99&nbsp;&nbsp;host = <i>string</i>,<br>
@@ -110,19 +109,19 @@ ftp.<b>get{</b><br>
110<b>}</b> 109<b>}</b>
111</p> 110</p>
112 111
113<p class=description> 112<p class="description">
114The <tt>get</tt> function has two forms. The simple form has fixed 113The <tt>get</tt> function has two forms. The simple form has fixed
115functionality: it downloads the contents of a URL and returns it as a 114functionality: it downloads the contents of a URL and returns it as a
116string. The generic form allows a <em>lot</em> more control, as explained 115string. The generic form allows a <em>lot</em> more control, as explained
117below. 116below.
118</p> 117</p>
119 118
120<p class=parameters> 119<p class="parameters">
121If the argument of the <tt>get</tt> function is a table, the function 120If the argument of the <tt>get</tt> function is a table, the function
122expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of 121expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of
123<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes 122<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
124precedence). <tt>Host</tt> is the server to connect to. <tt>Sink</tt> is 123precedence). <tt>Host</tt> is the server to connect to. <tt>Sink</tt> is
125the <em>simple</em> 124the <em>simple</em>
126<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 125<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
127sink that will receive the downloaded data. <tt>Argument</tt> or 126sink that will receive the downloaded data. <tt>Argument</tt> or
128<tt>path</tt> give the target path to the resource in the server. The 127<tt>path</tt> give the target path to the resource in the server. The
@@ -130,28 +129,28 @@ optional arguments are the following:
130</p> 129</p>
131<ul> 130<ul>
132<li><tt>user</tt>, <tt>password</tt>: User name and password used for 131<li><tt>user</tt>, <tt>password</tt>: User name and password used for
133authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>"; 132authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
134<li><tt>command</tt>: The FTP command used to obtain data. Defaults to 133<li><tt>command</tt>: The FTP command used to obtain data. Defaults to
135"<tt>retr</tt>", but see example below; 134"<tt>retr</tt>", but see example below;</li>
136<li><tt>port</tt>: The port to used for the control connection. Defaults to 21; 135<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
137<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or 136<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
138"<tt>a</tt>". Defaults to whatever is the server default; 137"<tt>a</tt>". Defaults to whatever is the server default;</li>
139<li><tt>step</tt>: 138<li><tt>step</tt>:
140<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 139<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
141pump step function used to pass data from the 140pump step function used to pass data from the
142server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function; 141server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
143<li><tt>create</tt>: An optional function to be used instead of 142<li><tt>create</tt>: An optional function to be used instead of
144<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. 143<a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
145</ul> 144</ul>
146 145
147<p class=return> 146<p class="return">
148If successful, the simple version returns the URL contents as a 147If successful, the simple version returns the URL contents as a
149string, and the generic function returns 1. In case of error, both 148string, and the generic function returns 1. In case of error, both
150functions return <b><tt>nil</tt></b> and an error message describing the 149functions return <b><tt>nil</tt></b> and an error message describing the
151error. 150error.
152</p> 151</p>
153 152
154<pre class=example> 153<pre class="example">
155-- load the ftp support 154-- load the ftp support
156local ftp = require("socket.ftp") 155local ftp = require("socket.ftp")
157 156
@@ -160,7 +159,7 @@ local ftp = require("socket.ftp")
160f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i") 159f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
161</pre> 160</pre>
162 161
163<pre class=example> 162<pre class="example">
164-- load needed modules 163-- load needed modules
165local ftp = require("socket.ftp") 164local ftp = require("socket.ftp")
166local ltn12 = require("ltn12") 165local ltn12 = require("ltn12")
@@ -179,7 +178,7 @@ end
179 178
180<!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 179<!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
181 180
182<p class=name id=put> 181<p class="name" id="put">
183ftp.<b>put(</b>url, content<b>)</b><br> 182ftp.<b>put(</b>url, content<b>)</b><br>
184ftp.<b>put{</b><br> 183ftp.<b>put{</b><br>
185&nbsp;&nbsp;host = <i>string</i>,<br> 184&nbsp;&nbsp;host = <i>string</i>,<br>
@@ -195,57 +194,57 @@ ftp.<b>put{</b><br>
195<b>}</b> 194<b>}</b>
196</p> 195</p>
197 196
198<p class=description> 197<p class="description">
199The <tt>put</tt> function has two forms. The simple form has fixed 198The <tt>put</tt> function has two forms. The simple form has fixed
200functionality: it uploads a string of content into a URL. The generic form 199functionality: it uploads a string of content into a URL. The generic form
201allows a <em>lot</em> more control, as explained below. 200allows a <em>lot</em> more control, as explained below.
202</p> 201</p>
203 202
204<p class=parameters> 203<p class="parameters">
205If the argument of the <tt>put</tt> function is a table, the function 204If the argument of the <tt>put</tt> function is a table, the function
206expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of 205expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of
207<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes 206<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
208precedence). <tt>Host</tt> is the server to connect to. <tt>Source</tt> is 207precedence). <tt>Host</tt> is the server to connect to. <tt>Source</tt> is
209the <em>simple</em> 208the <em>simple</em>
210<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 209<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
211source that will provide the contents to be uploaded. 210source that will provide the contents to be uploaded.
212<tt>Argument</tt> or 211<tt>Argument</tt> or
213<tt>path</tt> give the target path to the resource in the server. The 212<tt>path</tt> give the target path to the resource in the server. The
214optional arguments are the following: 213optional arguments are the following:
215</p> 214</p>
216<ul> 215<ul>
217<li><tt>user</tt>, <tt>password</tt>: User name and password used for 216<li><tt>user</tt>, <tt>password</tt>: User name and password used for
218authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>"; 217authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
219<li><tt>command</tt>: The FTP command used to send data. Defaults to 218<li><tt>command</tt>: The FTP command used to send data. Defaults to
220"<tt>stor</tt>", but see example below; 219"<tt>stor</tt>", but see example below;</li>
221<li><tt>port</tt>: The port to used for the control connection. Defaults to 21; 220<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
222<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or 221<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
223"<tt>a</tt>". Defaults to whatever is the server default; 222"<tt>a</tt>". Defaults to whatever is the server default;</li>
224<li><tt>step</tt>: 223<li><tt>step</tt>:
225<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 224<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
226pump step function used to pass data from the 225pump step function used to pass data from the
227server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function; 226server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
228<li><tt>create</tt>: An optional function to be used instead of 227<li><tt>create</tt>: An optional function to be used instead of
229<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. 228<a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
230</ul> 229</ul>
231 230
232<p class=return> 231<p class="return">
233Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error 232Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error
234message describing the reason for failure. 233message describing the reason for failure.
235</p> 234</p>
236 235
237<pre class=example> 236<pre class="example">
238-- load the ftp support 237-- load the ftp support
239local ftp = require("socket.ftp") 238local ftp = require("socket.ftp")
240 239
241-- Log as user "fulano" on server "ftp.example.com", 240-- Log as user "fulano" on server "ftp.example.com",
242-- using password "silva", and store a file "README" with contents 241-- using password "silva", and store a file "README" with contents
243-- "wrong password, of course" 242-- "wrong password, of course"
244f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README", 243f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",
245 "wrong password, of course") 244 "wrong password, of course")
246</pre> 245</pre>
247 246
248<pre class=example> 247<pre class="example">
249-- load the ftp support 248-- load the ftp support
250local ftp = require("socket.ftp") 249local ftp = require("socket.ftp")
251local ltn12 = require("ltn12") 250local ltn12 = require("ltn12")
@@ -254,7 +253,7 @@ local ltn12 = require("ltn12")
254-- using password "silva", and append to the remote file "LOG", sending the 253-- using password "silva", and append to the remote file "LOG", sending the
255-- contents of the local file "LOCAL-LOG" 254-- contents of the local file "LOCAL-LOG"
256f, e = ftp.put{ 255f, e = ftp.put{
257 host = "ftp.example.com", 256 host = "ftp.example.com",
258 user = "fulano", 257 user = "fulano",
259 password = "silva", 258 password = "silva",
260 command = "appe", 259 command = "appe",
@@ -266,15 +265,15 @@ f, e = ftp.put{
266 265
267<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 266<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
268 267
269<div class=footer> 268<div class="footer">
270<hr> 269<hr>
271<center> 270<center>
272<p class=bar> 271<p class="bar">
273<a href="index.html">home</a> &middot; 272<a href="index.html">home</a> &middot;
274<a href="index.html#download">download</a> &middot; 273<a href="index.html#download">download</a> &middot;
275<a href="installation.html">installation</a> &middot; 274<a href="installation.html">installation</a> &middot;
276<a href="introduction.html">introduction</a> &middot; 275<a href="introduction.html">introduction</a> &middot;
277<a href="reference.html">reference</a> 276<a href="reference.html">reference</a>
278</p> 277</p>
279<p> 278<p>
280<small> 279<small>
diff --git a/doc/http.html b/docs/http.html
index cd41c0d..52b8a30 100644
--- a/doc/http.html
+++ b/docs/http.html
@@ -1,10 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: HTTP support"> 6<meta name="description" content="LuaSocket: HTTP support">
7<meta name="keywords" content="Lua, HTTP, Library, WWW, Browser, Network, Support"> 7<meta name="keywords" content="Lua, HTTP, Library, WWW, Browser, Network, Support">
8<title>LuaSocket: HTTP support</title> 8<title>LuaSocket: HTTP support</title>
9<link rel="stylesheet" href="reference.css" type="text/css"> 9<link rel="stylesheet" href="reference.css" type="text/css">
10</head> 10</head>
@@ -13,22 +13,22 @@
13 13
14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="introduction.html">introduction</a> &middot; 29<a href="introduction.html">introduction</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,12 +36,12 @@
36 36
37<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id="http">HTTP</h2> 39<h2 id="http">HTTP</h2>
40 40
41<p> 41<p>
42HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange 42HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
43information between web-browsers and servers. The <tt>http</tt> 43information between web-browsers and servers. The <tt>http</tt>
44namespace offers full support for the client side of the HTTP 44namespace offers full support for the client side of the HTTP
45protocol (i.e., 45protocol (i.e.,
46the facilities that would be used by a web-browser implementation). The 46the facilities that would be used by a web-browser implementation). The
47implementation conforms to the HTTP/1.1 standard, 47implementation conforms to the HTTP/1.1 standard,
@@ -50,16 +50,16 @@ implementation conforms to the HTTP/1.1 standard,
50 50
51<p> 51<p>
52The module exports functions that provide HTTP functionality in different 52The module exports functions that provide HTTP functionality in different
53levels of abstraction. From the simple 53levels of abstraction. From the simple
54string oriented requests, through generic 54string oriented requests, through generic
55<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based, down to even lower-level if you bother to look through the source code. 55<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based, down to even lower-level if you bother to look through the source code.
56</p> 56</p>
57 57
58<p> 58<p>
59To obtain the <tt>http</tt> namespace, run: 59To obtain the <tt>http</tt> namespace, run:
60</p> 60</p>
61 61
62<pre class=example> 62<pre class="example">
63-- loads the HTTP module and any libraries it requires 63-- loads the HTTP module and any libraries it requires
64local http = require("socket.http") 64local http = require("socket.http")
65</pre> 65</pre>
@@ -67,12 +67,12 @@ local http = require("socket.http")
67<p> 67<p>
68URLs must conform to 68URLs must conform to
69<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>, 69<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
70that is, an URL is a string in the form: 70that is, an URL is a string in the form:
71</p> 71</p>
72 72
73<blockquote> 73<blockquote>
74<pre> 74<pre>
75[http://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;] 75[http://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;]
76</pre> 76</pre>
77</blockquote> 77</blockquote>
78 78
@@ -97,31 +97,34 @@ headers = {<br>
97<p> 97<p>
98Field names are case insensitive (as specified by the standard) and all 98Field names are case insensitive (as specified by the standard) and all
99functions work with lowercase field names (but see 99functions work with lowercase field names (but see
100<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>). 100<a href="socket.html#headers.canonic"><tt>socket.headers.canonic</tt></a>).
101Field values are left unmodified. 101Field values are left unmodified.
102</p> 102</p>
103 103
104<p class=note> 104<p class="note">
105Note: MIME headers are independent of order. Therefore, there is no problem 105Note: MIME headers are independent of order. Therefore, there is no problem
106in representing them in a Lua table. 106in representing them in a Lua table.
107</p> 107</p>
108 108
109<p> 109<p>
110The following constants can be set to control the default behavior of 110The following constants can be set to control the default behavior of
111the HTTP module: 111the HTTP module:
112</p> 112</p>
113 113
114<ul> 114<ul>
115<li> <tt>PORT</tt>: default port used for connections; 115<li> <tt>PROXY</tt>: default proxy used for connections;</li>
116<li> <tt>PROXY</tt>: default proxy used for connections; 116<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
117<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; 117<li> <tt>USERAGENT</tt>: default user agent reported to server.</li>
118<li> <tt>USERAGENT</tt>: default user agent reported to server.
119</ul> 118</ul>
120 119
120<p class="note">
121Note: These constants are global. Changing them will also
122change the behavior other code that might be using LuaSocket.
123</p>
121 124
122<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 125<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
123 126
124<p class=name id="request"> 127<p class="name" id="request">
125http.<b>request(</b>url [, body]<b>)</b><br> 128http.<b>request(</b>url [, body]<b>)</b><br>
126http.<b>request{</b><br> 129http.<b>request{</b><br>
127&nbsp;&nbsp;url = <i>string</i>,<br> 130&nbsp;&nbsp;url = <i>string</i>,<br>
@@ -132,30 +135,31 @@ http.<b>request{</b><br>
132&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> 135&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
133&nbsp;&nbsp;[proxy = <i>string</i>,]<br> 136&nbsp;&nbsp;[proxy = <i>string</i>,]<br>
134&nbsp;&nbsp;[redirect = <i>boolean</i>,]<br> 137&nbsp;&nbsp;[redirect = <i>boolean</i>,]<br>
135&nbsp;&nbsp;[create = <i>function</i>]<br> 138&nbsp;&nbsp;[create = <i>function</i>,]<br>
139&nbsp;&nbsp;[maxredirects = <i>number</i>]<br>
136<b>}</b> 140<b>}</b>
137</p> 141</p>
138 142
139<p class=description> 143<p class="description">
140The request function has two forms. The simple form downloads 144The request function has two forms. The simple form downloads
141a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based 145a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based
142on strings. The generic form performs any HTTP method and is 146on strings. The generic form performs any HTTP method and is
143<a href=http://lua-users.org/wiki/FiltersSourcesAndSinks>LTN12</a> based. 147<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based.
144</p> 148</p>
145 149
146<p class=parameters> 150<p class="parameters">
147If the first argument of the <tt>request</tt> function is a string, it 151If the first argument of the <tt>request</tt> function is a string, it
148should be an <tt>url</tt>. In that case, if a <tt>body</tt> 152should be an <tt>url</tt>. In that case, if a <tt>body</tt>
149is provided as a string, the function will perform a <tt>POST</tt> method 153is provided as a string, the function will perform a <tt>POST</tt> method
150in the <tt>url</tt>. Otherwise, it performs a <tt>GET</tt> in the 154in the <tt>url</tt>. Otherwise, it performs a <tt>GET</tt> in the
151<tt>url</tt> 155<tt>url</tt>
152</p> 156</p>
153 157
154<p class=parameters> 158<p class="parameters">
155If the first argument is instead a table, the most important fields are 159If the first argument is instead a table, the most important fields are
156the <tt>url</tt> and the <em>simple</em> 160the <tt>url</tt> and the <em>simple</em>
157<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 161<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
158<tt>sink</tt> that will receive the downloaded content. 162<tt>sink</tt> that will receive the downloaded content.
159Any part of the <tt>url</tt> can be overridden by including 163Any part of the <tt>url</tt> can be overridden by including
160the appropriate field in the request table. 164the appropriate field in the request table.
161If authentication information is provided, the function 165If authentication information is provided, the function
@@ -165,48 +169,51 @@ function discards the downloaded data. The optional parameters are the
165following: 169following:
166</p> 170</p>
167<ul> 171<ul>
168<li><tt>method</tt>: The HTTP request method. Defaults to "GET"; 172<li><tt>method</tt>: The HTTP request method. Defaults to "GET";</li>
169<li><tt>headers</tt>: Any additional HTTP headers to send with the request; 173<li><tt>headers</tt>: Any additional HTTP headers to send with the request;</li>
170<li><tt>source</tt>: <em>simple</em> 174<li><tt>source</tt>: <em>simple</em>
171<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 175<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
172source to provide the request body. If there 176source to provide the request body. If there
173is a body, you need to provide an appropriate "<tt>content-length</tt>" 177is a body, you need to provide an appropriate "<tt>content-length</tt>"
174request header field, or the function will attempt to send the body as 178request header field, or the function will attempt to send the body as
175"<tt>chunked</tt>" (something few servers support). Defaults to the empty source; 179"<tt>chunked</tt>" (something few servers support). Defaults to the empty source;</li>
176<li><tt>step</tt>: 180<li><tt>step</tt>:
177<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 181<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
178pump step function used to move data. 182pump step function used to move data.
179Defaults to the LTN12 <tt>pump.step</tt> function. 183Defaults to the LTN12 <tt>pump.step</tt> function.</li>
180<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy; 184<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;</li>
181<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the 185<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
182function from automatically following 301 or 302 server redirect messages; 186function from automatically following 301 or 302 server redirect messages;</li>
183<li><tt>create</tt>: An optional function to be used instead of 187<li><tt>create</tt>: An optional function to be used instead of
184<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. 188<a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
189<li><tt>maxredirects</tt>: An optional number specifying the maximum number of
190 redirects to follow. Defaults to <tt>5</tt> if not specified. A boolean
191 <tt>false</tt> value means no maximum (unlimited).</li>
185</ul> 192</ul>
186 193
187<p class=return> 194<p class="return">
188In case of failure, the function returns <tt><b>nil</b></tt> followed by an 195In case of failure, the function returns <tt><b>nil</b></tt> followed by an
189error message. If successful, the simple form returns the response 196error message. If successful, the simple form returns the response
190body as a string, followed by the response status code, the response 197body as a string, followed by the response status code, the response
191headers and the response status line. The generic function returns the same 198headers and the response status line. The generic function returns the same
192information, except the first return value is just the number 1 (the body 199information, except the first return value is just the number 1 (the body
193goes to the <tt>sink</tt>). 200goes to the <tt>sink</tt>).
194</p> 201</p>
195 202
196<p class=return> 203<p class="return">
197Even when the server fails to provide the contents of the requested URL (URL not found, for example), 204Even when the server fails to provide the contents of the requested URL (URL not found, for example),
198it usually returns a message body (a web page informing the 205it usually returns a message body (a web page informing the
199URL was not found or some other useless page). To make sure the 206URL was not found or some other useless page). To make sure the
200operation was successful, check the returned status <tt>code</tt>. For 207operation was successful, check the returned status <tt>code</tt>. For
201a list of the possible values and their meanings, refer to <a 208a list of the possible values and their meanings, refer to <a
202href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>. 209href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
203</p> 210</p>
204 211
205<p class=description> 212<p class="description">
206Here are a few examples with the simple interface: 213Here are a few examples with the simple interface:
207</p> 214</p>
208 215
209<pre class=example> 216<pre class="example">
210-- load the http module 217-- load the http module
211local io = require("io") 218local io = require("io")
212local http = require("socket.http") 219local http = require("socket.http")
@@ -214,15 +221,15 @@ local ltn12 = require("ltn12")
214 221
215-- connect to server "www.cs.princeton.edu" and retrieves this manual 222-- connect to server "www.cs.princeton.edu" and retrieves this manual
216-- file from "~diego/professional/luasocket/http.html" and print it to stdout 223-- file from "~diego/professional/luasocket/http.html" and print it to stdout
217http.request{ 224http.request{
218 url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html", 225 url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html",
219 sink = ltn12.sink.file(io.stdout) 226 sink = ltn12.sink.file(io.stdout)
220} 227}
221 228
222-- connect to server "www.example.com" and tries to retrieve 229-- connect to server "www.example.com" and tries to retrieve
223-- "/private/index.html". Fails because authentication is needed. 230-- "/private/index.html". Fails because authentication is needed.
224b, c, h = http.request("http://www.example.com/private/index.html") 231b, c, h = http.request("http://www.example.com/private/index.html")
225-- b returns some useless page telling about the denied access, 232-- b returns some useless page telling about the denied access,
226-- h returns authentication information 233-- h returns authentication information
227-- and c returns with value 401 (Authentication Required) 234-- and c returns with value 401 (Authentication Required)
228 235
@@ -232,11 +239,11 @@ r, e = http.request("http://wrong.host/")
232-- r is nil, and e returns with value "host not found" 239-- r is nil, and e returns with value "host not found"
233</pre> 240</pre>
234 241
235<p class=description> 242<p class="description">
236And here is an example using the generic interface: 243And here is an example using the generic interface:
237</p> 244</p>
238 245
239<pre class=example> 246<pre class="example">
240-- load the http module 247-- load the http module
241http = require("socket.http") 248http = require("socket.http")
242 249
@@ -258,7 +265,7 @@ r, c, h = http.request {
258-- } 265-- }
259</pre> 266</pre>
260 267
261<p class=note id="post"> 268<p class="note" id="post">
262Note: When sending a POST request, simple interface adds a 269Note: When sending a POST request, simple interface adds a
263"<tt>Content-type: application/x-www-form-urlencoded</tt>" 270"<tt>Content-type: application/x-www-form-urlencoded</tt>"
264header to the request. This is the type used by 271header to the request. This is the type used by
@@ -266,21 +273,21 @@ HTML forms. If you need another type, use the generic
266interface. 273interface.
267</p> 274</p>
268 275
269<p class=note id="authentication"> 276<p class="note" id="authentication">
270Note: Some URLs are protected by their 277Note: Some URLs are protected by their
271servers from anonymous download. For those URLs, the server must receive 278servers from anonymous download. For those URLs, the server must receive
272some sort of authentication along with the request or it will deny 279some sort of authentication along with the request or it will deny
273download and return status "401&nbsp;Authentication Required". 280download and return status "401&nbsp;Authentication Required".
274</p> 281</p>
275 282
276<p class=note> 283<p class="note">
277The HTTP/1.1 standard defines two authentication methods: the Basic 284The HTTP/1.1 standard defines two authentication methods: the Basic
278Authentication Scheme and the Digest Authentication Scheme, both 285Authentication Scheme and the Digest Authentication Scheme, both
279explained in detail in 286explained in detail in
280<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>. 287<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
281</p> 288</p>
282 289
283<p class=note>The Basic Authentication Scheme sends 290<p class="note">The Basic Authentication Scheme sends
284<tt>&lt;user&gt;</tt> and 291<tt>&lt;user&gt;</tt> and
285<tt>&lt;password&gt;</tt> unencrypted to the server and is therefore 292<tt>&lt;password&gt;</tt> unencrypted to the server and is therefore
286considered unsafe. Unfortunately, by the time of this implementation, 293considered unsafe. Unfortunately, by the time of this implementation,
@@ -289,7 +296,7 @@ Therefore, this is the method used by the toolkit whenever
289authentication is required. 296authentication is required.
290</p> 297</p>
291 298
292<pre class=example> 299<pre class="example">
293-- load required modules 300-- load required modules
294http = require("socket.http") 301http = require("socket.http")
295mime = require("mime") 302mime = require("mime")
@@ -309,20 +316,20 @@ r, c = http.request {
309 316
310<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 317<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
311 318
312<div class=footer> 319<div class="footer">
313<hr> 320<hr>
314<center> 321<center>
315<p class=bar> 322<p class="bar">
316<a href="index.html">home</a> &middot; 323<a href="index.html">home</a> &middot;
317<a href="index.html#download">download</a> &middot; 324<a href="index.html#download">download</a> &middot;
318<a href="installation.html">installation</a> &middot; 325<a href="installation.html">installation</a> &middot;
319<a href="introduction.html">introduction</a> &middot; 326<a href="introduction.html">introduction</a> &middot;
320<a href="reference.html">reference</a> 327<a href="reference.html">reference</a>
321</p> 328</p>
322<p> 329<p>
323<small> 330<small>
324Last modified by Diego Nehab on <br> 331Last modified by Eric Westbrook on <br>
325Thu Apr 20 00:25:26 EDT 2006 332Sat Feb 23 19:09:42 UTC 2019
326</small> 333</small>
327</p> 334</p>
328</center> 335</center>
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..ad92687
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,138 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd">
3<html>
4
5<head>
6<meta name="description" content="The LuaSocket Homepage">
7<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
8<title>LuaSocket: Network support for the Lua language </title>
9<link rel="stylesheet" href="reference.css" type="text/css">
10</head>
11
12<body>
13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15
16<div class="header">
17<hr>
18<center>
19<table summary="LuaSocket logo">
20<tr><td align="center"><a href="http://www.lua.org">
21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr>
23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr>
25</table>
26<p class="bar">
27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a>
32</p>
33</center>
34<hr>
35</div>
36
37<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38
39<h2 id="whatis">What is LuaSocket?</h2>
40
41<p>
42LuaSocket is a <a href="http://www.lua.org">Lua</a> extension library
43that is composed by two parts: a C core that provides support for the TCP
44and UDP transport layers, and a set of Lua modules that add support for
45functionality commonly needed by applications that deal with the Internet.
46</p>
47
48<p>
49The core support has been implemented so that it is both efficient and
50simple to use. It is available to any Lua application once it has been
51properly initialized by the interpreter in use. The code has been tested
52and runs well on several Windows and UNIX platforms. </p>
53
54<p>
55Among the support modules, the most commonly used implement the
56<a href="smtp.html">SMTP</a>
57(sending e-mails),
58<a href="http.html">HTTP</a>
59(WWW access) and
60<a href="ftp.html">FTP</a>
61(uploading and downloading files) client
62protocols. These provide a very natural and generic interface to the
63functionality defined by each protocol.
64In addition, you will find that the
65<a href="mime.html">MIME</a> (common encodings),
66<a href="url.html">URL</a>
67(anything you could possible want to do with one) and
68<a href="ltn12.html">LTN12</a>
69(filters, sinks, sources and pumps) modules can be very handy.
70</p>
71
72<p>
73The library is available under the same
74<a href="http://www.lua.org/copyright.html">
75terms and conditions</a> as the Lua language, the MIT license. The idea is
76that if you can use Lua in a project, you should also be able to use
77LuaSocket.
78</p>
79
80<p>
81Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
82Author: <a href="http://www.impa.br/~diego">Diego Nehab</a>
83</p>
84
85<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
86
87<h2 id="download">Download</h2>
88
89<p>
90LuaSocket version 3.1.0 is now available for download!
91It is compatible with Lua&nbsp;5.1 through 5.4.
92Chances are it works well on most UNIX distributions and Windows flavors.
93</p>
94
95<p>
96The current version of the library can be found at
97the <a href="https://github.com/lunarmodules/luasocket">LuaSocket
98project page</a> on GitHub. Besides the full C and Lua source code
99for the library, the distribution contains several examples,
100this user's manual and basic test procedures.
101</p>
102
103<p> Take a look at the <a
104href="installation.html">installation</a> section of the
105manual to find out how to properly install the library.
106</p>
107
108<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
109
110<h2 id="thanks">Special thanks</h2>
111
112<p>
113This marks the first release of LuaSocket that
114wholeheartedly embraces the open-source development
115philosophy. After a long hiatus, Matthew Wild finally
116convinced me it was time for a release including IPv6 and
117Lua 5.2 support. It was more work than we anticipated.
118Special thanks to Sam Roberts, Florian Zeitz, and Paul
119Aurich, Liam Devine, Alexey Melnichuk, and everybody else
120that has helped bring this library back to life.
121</p>
122
123<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
124
125<div class="footer">
126<hr>
127<center>
128<p class="bar">
129<a href="index.html#download">download</a> &middot;
130<a href="installation.html">installation</a> &middot;
131<a href="introduction.html">introduction</a> &middot;
132<a href="reference.html">reference</a>
133</p>
134</center>
135</div>
136
137</body>
138</html>
diff --git a/doc/installation.html b/docs/installation.html
index 28a9fbb..dcf9d36 100644
--- a/doc/installation.html
+++ b/docs/installation.html
@@ -89,7 +89,7 @@ it should be easy to use LuaSocket. Just fire the interpreter and use the
89Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio 89Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
90&gt; socket = require("socket") 90&gt; socket = require("socket")
91&gt; print(socket._VERSION) 91&gt; print(socket._VERSION)
92--&gt; LuaSocket 3.0-rc1 92--&gt; LuaSocket 3.0.0
93</pre> 93</pre>
94 94
95<p> Each module loads their dependencies automatically, so you only need to 95<p> Each module loads their dependencies automatically, so you only need to
diff --git a/doc/introduction.html b/docs/introduction.html
index fd22f48..fd22f48 100644
--- a/doc/introduction.html
+++ b/docs/introduction.html
diff --git a/logo.ps b/docs/logo.ps
index 8b5809a..8b5809a 100644
--- a/logo.ps
+++ b/docs/logo.ps
diff --git a/doc/ltn12.html b/docs/ltn12.html
index 54e66fb..fe3e3a0 100644
--- a/doc/ltn12.html
+++ b/docs/ltn12.html
@@ -1,4 +1,4 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
@@ -14,22 +14,22 @@ Pump, Support, Library">
14 14
15<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 15<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
16 16
17<div class=header> 17<div class="header">
18<hr> 18<hr>
19<center> 19<center>
20<table summary="LuaSocket logo"> 20<table summary="LuaSocket logo">
21<tr><td align=center><a href="http://www.lua.org"> 21<tr><td align="center"><a href="http://www.lua.org">
22<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 22<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
23</a></td></tr> 23</a></td></tr>
24<tr><td align=center valign=top>Network support for the Lua language 24<tr><td align="center" valign="top">Network support for the Lua language
25</td></tr> 25</td></tr>
26</table> 26</table>
27<p class=bar> 27<p class="bar">
28<a href="index.html">home</a> &middot; 28<a href="index.html">home</a> &middot;
29<a href="index.html#download">download</a> &middot; 29<a href="index.html#download">download</a> &middot;
30<a href="installation.html">installation</a> &middot; 30<a href="installation.html">installation</a> &middot;
31<a href="introduction.html">introduction</a> &middot; 31<a href="introduction.html">introduction</a> &middot;
32<a href="reference.html">reference</a> 32<a href="reference.html">reference</a>
33</p> 33</p>
34</center> 34</center>
35<hr> 35<hr>
@@ -37,7 +37,7 @@ Pump, Support, Library">
37 37
38<!-- ltn12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 38<!-- ltn12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
39 39
40<h2 id=ltn12>LTN12</h2> 40<h2 id="ltn12">LTN12</h2>
41 41
42<p> The <tt>ltn12</tt> namespace implements the ideas described in 42<p> The <tt>ltn12</tt> namespace implements the ideas described in
43<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> 43<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
@@ -46,11 +46,11 @@ functions. Please refer to the LTN for a deeper explanation of the
46functionality provided by this module. 46functionality provided by this module.
47</p> 47</p>
48 48
49<p> 49<p>
50To obtain the <tt>ltn12</tt> namespace, run: 50To obtain the <tt>ltn12</tt> namespace, run:
51</p> 51</p>
52 52
53<pre class=example> 53<pre class="example">
54-- loads the LTN21 module 54-- loads the LTN21 module
55local ltn12 = require("ltn12") 55local ltn12 = require("ltn12")
56</pre> 56</pre>
@@ -61,32 +61,32 @@ local ltn12 = require("ltn12")
61 61
62<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 62<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
63 63
64<p class=name id="filter.chain"> 64<p class="name" id="filter.chain">
65ltn12.filter.<b>chain(</b>filter<sub>1</sub>, filter<sub>2</sub> 65ltn12.filter.<b>chain(</b>filter<sub>1</sub>, filter<sub>2</sub>
66[, ... filter<sub>N</sub>]<b>)</b> 66[, ... filter<sub>N</sub>]<b>)</b>
67</p> 67</p>
68 68
69<p class=description> 69<p class="description">
70Returns a filter that passes all data it receives through each of a 70Returns a filter that passes all data it receives through each of a
71series of given filters. 71series of given filters.
72</p> 72</p>
73 73
74<p class=parameters> 74<p class="parameters">
75<tt>Filter<sub>1</sub></tt> to <tt>filter<sub>N</sub></tt> are simple 75<tt>Filter<sub>1</sub></tt> to <tt>filter<sub>N</sub></tt> are simple
76filters. 76filters.
77</p> 77</p>
78 78
79<p class=return> 79<p class="return">
80The function returns the chained filter. 80The function returns the chained filter.
81</p> 81</p>
82 82
83<p class=note> 83<p class="note">
84The nesting of filters can be arbitrary. For instance, the useless filter 84The nesting of filters can be arbitrary. For instance, the useless filter
85below doesn't do anything but return the data that was passed to it, 85below doesn't do anything but return the data that was passed to it,
86unaltered. 86unaltered.
87</p> 87</p>
88 88
89<pre class=example> 89<pre class="example">
90-- load required modules 90-- load required modules
91local ltn12 = require("ltn12") 91local ltn12 = require("ltn12")
92local mime = require("mime") 92local mime = require("mime")
@@ -102,26 +102,26 @@ id = ltn12.filter.chain(
102 102
103<!-- cycle ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 103<!-- cycle ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
104 104
105<p class=name id="filter.cycle"> 105<p class="name" id="filter.cycle">
106ltn12.filter.<b>cycle(</b>low [, ctx, extra]<b>)</b> 106ltn12.filter.<b>cycle(</b>low [, ctx, extra]<b>)</b>
107</p> 107</p>
108 108
109<p class=description> 109<p class="description">
110Returns a high-level filter that cycles though a low-level filter by 110Returns a high-level filter that cycles though a low-level filter by
111passing it each chunk and updating a context between calls. 111passing it each chunk and updating a context between calls.
112</p> 112</p>
113 113
114<p class=parameters> 114<p class="parameters">
115<tt>Low</tt> is the low-level filter to be cycled, 115<tt>Low</tt> is the low-level filter to be cycled,
116<tt>ctx</tt> is the initial context and <tt>extra</tt> is any extra 116<tt>ctx</tt> is the initial context and <tt>extra</tt> is any extra
117argument the low-level filter might take. 117argument the low-level filter might take.
118</p> 118</p>
119 119
120<p class=return> 120<p class="return">
121The function returns the high-level filter. 121The function returns the high-level filter.
122</p> 122</p>
123 123
124<pre class=example> 124<pre class="example">
125-- load the ltn12 module 125-- load the ltn12 module
126local ltn12 = require("ltn12") 126local ltn12 = require("ltn12")
127 127
@@ -137,15 +137,15 @@ end
137 137
138<!-- all ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 138<!-- all ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
139 139
140<p class=name id="pump.all"> 140<p class="name" id="pump.all">
141ltn12.pump.<b>all(</b>source, sink<b>)</b> 141ltn12.pump.<b>all(</b>source, sink<b>)</b>
142</p> 142</p>
143 143
144<p class=description> 144<p class="description">
145Pumps <em>all</em> data from a <tt>source</tt> to a <tt>sink</tt>. 145Pumps <em>all</em> data from a <tt>source</tt> to a <tt>sink</tt>.
146</p> 146</p>
147 147
148<p class=return> 148<p class="return">
149If successful, the function returns a value that evaluates to 149If successful, the function returns a value that evaluates to
150<b><tt>true</tt></b>. In case 150<b><tt>true</tt></b>. In case
151of error, the function returns a <b><tt>false</tt></b> value, followed by an error message. 151of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
@@ -153,15 +153,15 @@ of error, the function returns a <b><tt>false</tt></b> value, followed by an err
153 153
154<!-- step +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 154<!-- step +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
155 155
156<p class=name id="pump.step"> 156<p class="name" id="pump.step">
157ltn12.pump.<b>step(</b>source, sink<b>)</b> 157ltn12.pump.<b>step(</b>source, sink<b>)</b>
158</p> 158</p>
159 159
160<p class=description> 160<p class="description">
161Pumps <em>one</em> chunk of data from a <tt>source</tt> to a <tt>sink</tt>. 161Pumps <em>one</em> chunk of data from a <tt>source</tt> to a <tt>sink</tt>.
162</p> 162</p>
163 163
164<p class=return> 164<p class="return">
165If successful, the function returns a value that evaluates to 165If successful, the function returns a value that evaluates to
166<b><tt>true</tt></b>. In case 166<b><tt>true</tt></b>. In case
167of error, the function returns a <b><tt>false</tt></b> value, followed by an error message. 167of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
@@ -173,52 +173,52 @@ of error, the function returns a <b><tt>false</tt></b> value, followed by an err
173 173
174<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 174<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
175 175
176<p class=name id="sink.chain"> 176<p class="name" id="sink.chain">
177ltn12.sink.<b>chain(</b>filter, sink<b>)</b> 177ltn12.sink.<b>chain(</b>filter, sink<b>)</b>
178</p> 178</p>
179 179
180<p class=description> 180<p class="description">
181Creates and returns a new sink that passes data through a <tt>filter</tt> before sending it to a given <tt>sink</tt>. 181Creates and returns a new sink that passes data through a <tt>filter</tt> before sending it to a given <tt>sink</tt>.
182</p> 182</p>
183 183
184<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 184<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
185 185
186<p class=name id="sink.error"> 186<p class="name" id="sink.error">
187ltn12.sink.<b>error(</b>message<b>)</b> 187ltn12.sink.<b>error(</b>message<b>)</b>
188</p> 188</p>
189 189
190<p class=description> 190<p class="description">
191Creates and returns a sink that aborts transmission with the error 191Creates and returns a sink that aborts transmission with the error
192<tt>message</tt>. 192<tt>message</tt>.
193</p> 193</p>
194 194
195<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 195<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
196 196
197<p class=name id="sink.file"> 197<p class="name" id="sink.file">
198ltn12.sink.<b>file(</b>handle, message<b>)</b> 198ltn12.sink.<b>file(</b>handle, message<b>)</b>
199</p> 199</p>
200 200
201<p class=description> 201<p class="description">
202Creates a sink that sends data to a file. 202Creates a sink that sends data to a file.
203</p> 203</p>
204 204
205<p class=parameters> 205<p class="parameters">
206<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>, 206<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
207<tt>message</tt> should give the reason for failure. 207<tt>message</tt> should give the reason for failure.
208</p> 208</p>
209 209
210<p class=return> 210<p class="return">
211The function returns a sink that sends all data to the given <tt>handle</tt> 211The function returns a sink that sends all data to the given <tt>handle</tt>
212and closes the file when done, or a sink that aborts the transmission with 212and closes the file when done, or a sink that aborts the transmission with
213the error <tt>message</tt> 213the error <tt>message</tt>
214</p> 214</p>
215 215
216<p class=note> 216<p class="note">
217In the following example, notice how the prototype is designed to 217In the following example, notice how the prototype is designed to
218fit nicely with the <tt>io.open</tt> function. 218fit nicely with the <tt>io.open</tt> function.
219</p> 219</p>
220 220
221<pre class=example> 221<pre class="example">
222-- load the ltn12 module 222-- load the ltn12 module
223local ltn12 = require("ltn12") 223local ltn12 = require("ltn12")
224 224
@@ -231,45 +231,45 @@ ltn12.pump.all(
231 231
232<!-- null +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 232<!-- null +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
233 233
234<p class=name id="sink.null"> 234<p class="name" id="sink.null">
235ltn12.sink.<b>null()</b> 235ltn12.sink.<b>null()</b>
236</p> 236</p>
237 237
238<p class=description> 238<p class="description">
239Returns a sink that ignores all data it receives. 239Returns a sink that ignores all data it receives.
240</p> 240</p>
241 241
242<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 242<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
243 243
244<p class=name id="sink.simplify"> 244<p class="name" id="sink.simplify">
245ltn12.sink.<b>simplify(</b>sink<b>)</b> 245ltn12.sink.<b>simplify(</b>sink<b>)</b>
246</p> 246</p>
247 247
248<p class=description> 248<p class="description">
249Creates and returns a simple sink given a fancy <tt>sink</tt>. 249Creates and returns a simple sink given a fancy <tt>sink</tt>.
250</p> 250</p>
251 251
252<!-- table ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 252<!-- table ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
253 253
254<p class=name id="sink.table"> 254<p class="name" id="sink.table">
255ltn12.sink.<b>table(</b>[table]<b>)</b> 255ltn12.sink.<b>table(</b>[table]<b>)</b>
256</p> 256</p>
257 257
258<p class=description> 258<p class="description">
259Creates a sink that stores all chunks in a table. The chunks can later be 259Creates a sink that stores all chunks in a table. The chunks can later be
260efficiently concatenated into a single string. 260efficiently concatenated into a single string.
261</p> 261</p>
262 262
263<p class=parameters> 263<p class="parameters">
264<tt>Table</tt> is used to hold the chunks. If 264<tt>Table</tt> is used to hold the chunks. If
265<tt><b>nil</b></tt>, the function creates its own table. 265<tt><b>nil</b></tt>, the function creates its own table.
266</p> 266</p>
267 267
268<p class=return> 268<p class="return">
269The function returns the sink and the table used to store the chunks. 269The function returns the sink and the table used to store the chunks.
270</p> 270</p>
271 271
272<pre class=example> 272<pre class="example">
273-- load needed modules 273-- load needed modules
274local http = require("socket.http") 274local http = require("socket.http")
275local ltn12 = require("ltn12") 275local ltn12 = require("ltn12")
@@ -291,89 +291,89 @@ end
291 291
292<!-- cat ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 292<!-- cat ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
293 293
294<p class=name id="source.cat"> 294<p class="name" id="source.cat">
295ltn12.source.<b>cat(</b>source<sub>1</sub> [, source<sub>2</sub>, ..., 295ltn12.source.<b>cat(</b>source<sub>1</sub> [, source<sub>2</sub>, ...,
296source<sub>N</sub>]<b>)</b> 296source<sub>N</sub>]<b>)</b>
297</p> 297</p>
298 298
299<p class=description> 299<p class="description">
300Creates a new source that produces the concatenation of the data produced 300Creates a new source that produces the concatenation of the data produced
301by a number of sources. 301by a number of sources.
302</p> 302</p>
303 303
304<p class=parameters> 304<p class="parameters">
305<tt>Source<sub>1</sub></tt> to <tt>source<sub>N</sub></tt> are the original 305<tt>Source<sub>1</sub></tt> to <tt>source<sub>N</sub></tt> are the original
306sources. 306sources.
307</p> 307</p>
308 308
309<p class=return> 309<p class="return">
310The function returns the new source. 310The function returns the new source.
311</p> 311</p>
312 312
313<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 313<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
314 314
315<p class=name id="source.chain"> 315<p class="name" id="source.chain">
316ltn12.source.<b>chain(</b>source, filter<b>)</b> 316ltn12.source.<b>chain(</b>source, filter<b>)</b>
317</p> 317</p>
318 318
319<p class=description> 319<p class="description">
320Creates a new <tt>source</tt> that passes data through a <tt>filter</tt> 320Creates a new <tt>source</tt> that passes data through a <tt>filter</tt>
321before returning it. 321before returning it.
322</p> 322</p>
323 323
324<p class=return> 324<p class="return">
325The function returns the new source. 325The function returns the new source.
326</p> 326</p>
327 327
328<!-- empty ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 328<!-- empty ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
329 329
330<p class=name id="source.empty"> 330<p class="name" id="source.empty">
331ltn12.source.<b>empty()</b> 331ltn12.source.<b>empty()</b>
332</p> 332</p>
333 333
334<p class=description> 334<p class="description">
335Creates and returns an empty source. 335Creates and returns an empty source.
336</p> 336</p>
337 337
338<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 338<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
339 339
340<p class=name id="source.error"> 340<p class="name" id="source.error">
341ltn12.source.<b>error(</b>message<b>)</b> 341ltn12.source.<b>error(</b>message<b>)</b>
342</p> 342</p>
343 343
344<p class=description> 344<p class="description">
345Creates and returns a source that aborts transmission with the error 345Creates and returns a source that aborts transmission with the error
346<tt>message</tt>. 346<tt>message</tt>.
347</p> 347</p>
348 348
349<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 349<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
350 350
351<p class=name id="source.file"> 351<p class="name" id="source.file">
352ltn12.source.<b>file(</b>handle, message<b>)</b> 352ltn12.source.<b>file(</b>handle, message<b>)</b>
353</p> 353</p>
354 354
355<p class=description> 355<p class="description">
356Creates a source that produces the contents of a file. 356Creates a source that produces the contents of a file.
357</p> 357</p>
358 358
359<p class=parameters> 359<p class="parameters">
360<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>, 360<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
361<tt>message</tt> should give the reason for failure. 361<tt>message</tt> should give the reason for failure.
362</p> 362</p>
363 363
364<p class=return> 364<p class="return">
365The function returns a source that reads chunks of data from 365The function returns a source that reads chunks of data from
366given <tt>handle</tt> and returns it to the user, 366given <tt>handle</tt> and returns it to the user,
367closing the file when done, or a source that aborts the transmission with 367closing the file when done, or a source that aborts the transmission with
368the error <tt>message</tt> 368the error <tt>message</tt>
369</p> 369</p>
370 370
371<p class=note> 371<p class="note">
372In the following example, notice how the prototype is designed to 372In the following example, notice how the prototype is designed to
373fit nicely with the <tt>io.open</tt> function. 373fit nicely with the <tt>io.open</tt> function.
374</p> 374</p>
375 375
376<pre class=example> 376<pre class="example">
377-- load the ltn12 module 377-- load the ltn12 module
378local ltn12 = require("ltn12") 378local ltn12 = require("ltn12")
379 379
@@ -386,31 +386,41 @@ ltn12.pump.all(
386 386
387<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 387<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
388 388
389<p class=name id="source.simplify"> 389<p class="name" id="source.simplify">
390ltn12.source.<b>simplify(</b>source<b>)</b> 390ltn12.source.<b>simplify(</b>source<b>)</b>
391</p> 391</p>
392 392
393<p class=description> 393<p class="description">
394Creates and returns a simple source given a fancy <tt>source</tt>. 394Creates and returns a simple source given a fancy <tt>source</tt>.
395</p> 395</p>
396 396
397<!-- string +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 397<!-- string +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
398 398
399<p class=name id="source.string"> 399<p class="name" id="source.string">
400ltn12.source.<b>string(</b>string<b>)</b> 400ltn12.source.<b>string(</b>string<b>)</b>
401</p> 401</p>
402 402
403<p class=description> 403<p class="description">
404Creates and returns a source that produces the contents of a 404Creates and returns a source that produces the contents of a
405<tt>string</tt>, chunk by chunk. 405<tt>string</tt>, chunk by chunk.
406</p>
407
408<!-- table +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
409
410<p class="name" id="source.table">
411ltn12.source.<b>table(</b>table<b>)</b>
412</p>
413
414<p class="description">
415Creates 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.
406</p> 416</p>
407 417
408<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 418<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
409 419
410<div class=footer> 420<div class="footer">
411<hr> 421<hr>
412<center> 422<center>
413<p class=bar> 423<p class="bar">
414<a href="index.html">home</a> &middot; 424<a href="index.html">home</a> &middot;
415<a href="index.html#down">download</a> &middot; 425<a href="index.html#down">download</a> &middot;
416<a href="installation.html">installation</a> &middot; 426<a href="installation.html">installation</a> &middot;
diff --git a/doc/luasocket.png b/docs/luasocket.png
index d24a954..d24a954 100644
--- a/doc/luasocket.png
+++ b/docs/luasocket.png
Binary files differ
diff --git a/doc/mime.html b/docs/mime.html
index ae136fd..ff4d8e8 100644
--- a/doc/mime.html
+++ b/docs/mime.html
@@ -1,10 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: MIME support"> 6<meta name="description" content="LuaSocket: MIME support">
7<meta name="keywords" content="Lua, LuaSocket, MIME, Library, Support"> 7<meta name="keywords" content="Lua, LuaSocket, MIME, Library, Support">
8<title>LuaSocket: MIME module</title> 8<title>LuaSocket: MIME module</title>
9<link rel="stylesheet" href="reference.css" type="text/css"> 9<link rel="stylesheet" href="reference.css" type="text/css">
10</head> 10</head>
@@ -13,22 +13,22 @@
13 13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,14 +36,14 @@
36 36
37<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id=mime>MIME</h2> 39<h2 id="mime">MIME</h2>
40 40
41<p> 41<p>
42The <tt>mime</tt> namespace offers filters that apply and remove common 42The <tt>mime</tt> namespace offers filters that apply and remove common
43content transfer encodings, such as Base64 and Quoted-Printable. 43content transfer encodings, such as Base64 and Quoted-Printable.
44It also provides functions to break text into lines and change 44It also provides functions to break text into lines and change
45the end-of-line convention. 45the end-of-line convention.
46MIME is described mainly in 46MIME is described mainly in
47<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, 47<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
48<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>, 48<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
49<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>, 49<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
@@ -52,17 +52,17 @@ MIME is described mainly in
52</p> 52</p>
53 53
54<p> 54<p>
55All functionality provided by the MIME module 55All functionality provided by the MIME module
56follows the ideas presented in 56follows the ideas presented in
57<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> 57<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
58LTN012, Filters sources and sinks</a>. 58LTN012, Filters sources and sinks</a>.
59</p> 59</p>
60 60
61<p> 61<p>
62To obtain the <tt>mime</tt> namespace, run: 62To obtain the <tt>mime</tt> namespace, run:
63</p> 63</p>
64 64
65<pre class=example> 65<pre class="example">
66-- loads the MIME module and everything it requires 66-- loads the MIME module and everything it requires
67local mime = require("mime") 67local mime = require("mime")
68</pre> 68</pre>
@@ -70,88 +70,60 @@ local mime = require("mime")
70 70
71<!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 71<!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
72 72
73<h3 id=high>High-level filters</h3> 73<h3 id="high">High-level filters</h3>
74
75<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
76
77<p class=name id="normalize">
78mime.<b>normalize(</b>[marker]<b>)</b>
79</p>
80 74
81<p class=description>
82Converts most common end-of-line markers to a specific given marker.
83</p>
84
85<p class=parameters>
86<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
87end-of-line marker defined by the MIME standard.
88</p>
89
90<p class=return>
91The function returns a filter that performs the conversion.
92</p>
93
94<p class=note>
95Note: There is no perfect solution to this problem. Different end-of-line
96markers are an evil that will probably plague developers forever.
97This function, however, will work perfectly for text created with any of
98the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
99or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
100markers, the function will still work well, although it doesn't
101guarantee that the number of empty lines will be correct.
102</p>
103 75
104<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 76<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
105 77
106<p class=name id="decode"> 78<p class="name" id="decode">
107mime.<b>decode(</b>"base64"<b>)</b><br> 79mime.<b>decode(</b>"base64"<b>)</b><br>
108mime.<b>decode(</b>"quoted-printable"<b>)</b> 80mime.<b>decode(</b>"quoted-printable"<b>)</b>
109</p> 81</p>
110 82
111<p class=description> 83<p class="description">
112Returns a filter that decodes data from a given transfer content 84Returns a filter that decodes data from a given transfer content
113encoding. 85encoding.
114</p> 86</p>
115 87
116<!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 88<!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
117 89
118<p class=name id="encode"> 90<p class="name" id="encode">
119mime.<b>encode(</b>"base64"<b>)</b><br> 91mime.<b>encode(</b>"base64"<b>)</b><br>
120mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b> 92mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b>
121</p> 93</p>
122 94
123<p class=description> 95<p class="description">
124Returns a filter that encodes data according to a given transfer content 96Returns a filter that encodes data according to a given transfer content
125encoding. 97encoding.
126</p> 98</p>
127 99
128<p class=parameters> 100<p class="parameters">
129In the Quoted-Printable case, the user can specify whether the data is 101In the Quoted-Printable case, the user can specify whether the data is
130textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or 102textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or
131"<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>". 103"<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>".
132</p> 104</p>
133 105
134<p class=note> 106<p class="note">
135Although both transfer content encodings specify a limit for the line 107Although both transfer content encodings specify a limit for the line
136length, the encoding filters do <em>not</em> break text into lines (for 108length, the encoding filters do <em>not</em> break text into lines (for
137added flexibility). 109added flexibility).
138Below is a filter that converts binary data to the Base64 transfer content 110Below is a filter that converts binary data to the Base64 transfer content
139encoding and breaks it into lines of the correct size. 111encoding and breaks it into lines of the correct size.
140</p> 112</p>
141 113
142<pre class=example> 114<pre class="example">
143base64 = ltn12.filter.chain( 115base64 = ltn12.filter.chain(
144 mime.encode("base64"), 116 mime.encode("base64"),
145 mime.wrap("base64") 117 mime.wrap("base64")
146) 118)
147</pre> 119</pre>
148 120
149<p class=note> 121<p class="note">
150Note: Text data <em>has</em> to be converted to canonic form 122Note: Text data <em>has</em> to be converted to canonic form
151<em>before</em> being encoded. 123<em>before</em> being encoded.
152</p> 124</p>
153 125
154<pre class=example> 126<pre class="example">
155base64 = ltn12.filter.chain( 127base64 = ltn12.filter.chain(
156 mime.normalize(), 128 mime.normalize(),
157 mime.encode("base64"), 129 mime.encode("base64"),
@@ -159,50 +131,79 @@ base64 = ltn12.filter.chain(
159) 131)
160</pre> 132</pre>
161 133
134<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
135
136<p class="name" id="normalize">
137mime.<b>normalize(</b>[marker]<b>)</b>
138</p>
139
140<p class="description">
141Converts most common end-of-line markers to a specific given marker.
142</p>
143
144<p class="parameters">
145<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
146end-of-line marker defined by the MIME standard.
147</p>
148
149<p class="return">
150The function returns a filter that performs the conversion.
151</p>
152
153<p class="note">
154Note: There is no perfect solution to this problem. Different end-of-line
155markers are an evil that will probably plague developers forever.
156This function, however, will work perfectly for text created with any of
157the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
158or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
159markers, the function will still work well, although it doesn't
160guarantee that the number of empty lines will be correct.
161</p>
162
162<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 163<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
163 164
164<p class=name id="stuff"> 165<p class="name" id="stuff">
165mime.<b>stuff()</b><br> 166mime.<b>stuff()</b><br>
166</p> 167</p>
167 168
168<p class=description> 169<p class="description">
169Creates and returns a filter that performs stuffing of SMTP messages. 170Creates and returns a filter that performs stuffing of SMTP messages.
170</p> 171</p>
171 172
172<p class=note> 173<p class="note">
173Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function 174Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
174uses this filter automatically. You don't need to chain it with your 175uses this filter automatically. You don't need to chain it with your
175source, or apply it to your message body. 176source, or apply it to your message body.
176</p> 177</p>
177 178
178<!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 179<!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
179 180
180<p class=name id="wrap"> 181<p class="name" id="wrap">
181mime.<b>wrap(</b>"text" [, length]<b>)</b><br> 182mime.<b>wrap(</b>"text" [, length]<b>)</b><br>
182mime.<b>wrap(</b>"base64"<b>)</b><br> 183mime.<b>wrap(</b>"base64"<b>)</b><br>
183mime.<b>wrap(</b>"quoted-printable"<b>)</b> 184mime.<b>wrap(</b>"quoted-printable"<b>)</b>
184</p> 185</p>
185 186
186<p class=description> 187<p class="description">
187Returns a filter that breaks data into lines. 188Returns a filter that breaks data into lines.
188</p> 189</p>
189 190
190<p class=parameters> 191<p class="parameters">
191The "<tt>text</tt>" line-wrap filter simply breaks text into lines by 192The "<tt>text</tt>" line-wrap filter simply breaks text into lines by
192inserting CRLF end-of-line markers at appropriate positions. 193inserting CRLF end-of-line markers at appropriate positions.
193<tt>Length</tt> defaults 76. 194<tt>Length</tt> defaults 76.
194The "<tt>base64</tt>" line-wrap filter works just like the default 195The "<tt>base64</tt>" line-wrap filter works just like the default
195"<tt>text</tt>" line-wrap filter with default length. 196"<tt>text</tt>" line-wrap filter with default length.
196The function can also wrap "<tt>quoted-printable</tt>" lines, taking care 197The function can also wrap "<tt>quoted-printable</tt>" lines, taking care
197not to break lines in the middle of an escaped character. In that case, the 198not to break lines in the middle of an escaped character. In that case, the
198line length is fixed at 76. 199line length is fixed at 76.
199</p> 200</p>
200 201
201<p class=note> 202<p class="note">
202For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following: 203For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following:
203</p> 204</p>
204 205
205<pre class=example> 206<pre class="example">
206qp = ltn12.filter.chain( 207qp = ltn12.filter.chain(
207 mime.normalize(), 208 mime.normalize(),
208 mime.encode("quoted-printable"), 209 mime.encode("quoted-printable"),
@@ -210,155 +211,155 @@ qp = ltn12.filter.chain(
210) 211)
211</pre> 212</pre>
212 213
213<p class=note> 214<p class="note">
214Note: To break into lines with a different end-of-line convention, apply 215Note: To break into lines with a different end-of-line convention, apply
215a normalization filter after the line break filter. 216a normalization filter after the line break filter.
216</p> 217</p>
217 218
218<!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 219<!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
219 220
220<h3 id=low>Low-level filters</h3> 221<h3 id="low">Low-level filters</h3>
221 222
222<!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 223<!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
223 224
224<p class=name id="b64"> 225<p class="name" id="b64">
225A, B = mime.<b>b64(</b>C [, D]<b>)</b> 226A, B = mime.<b>b64(</b>C [, D]<b>)</b>
226</p> 227</p>
227 228
228<p class=description> 229<p class="description">
229Low-level filter to perform Base64 encoding. 230Low-level filter to perform Base64 encoding.
230</p> 231</p>
231 232
232<p class=description> 233<p class="description">
233<tt>A</tt> is the encoded version of the largest prefix of 234<tt>A</tt> is the encoded version of the largest prefix of
234<tt>C..D</tt> 235<tt>C..D</tt>
235that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of 236that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
236<tt>C..D</tt>, <em>before</em> encoding. 237<tt>C..D</tt>, <em>before</em> encoding.
237If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with 238If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
238the encoding of the remaining bytes of <tt>C</tt>. 239the encoding of the remaining bytes of <tt>C</tt>.
239</p> 240</p>
240 241
241<p class=note> 242<p class="note">
242Note: The simplest use of this function is to encode a string into it's 243Note: The simplest use of this function is to encode a string into it's
243Base64 transfer content encoding. Notice the extra parenthesis around the 244Base64 transfer content encoding. Notice the extra parenthesis around the
244call to <tt>mime.b64</tt>, to discard the second return value. 245call to <tt>mime.b64</tt>, to discard the second return value.
245</p> 246</p>
246 247
247<pre class=example> 248<pre class="example">
248print((mime.b64("diego:password"))) 249print((mime.b64("diego:password")))
249--&gt; ZGllZ286cGFzc3dvcmQ= 250--&gt; ZGllZ286cGFzc3dvcmQ=
250</pre> 251</pre>
251 252
252<!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 253<!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
253<p class=name id="dot"> 254<p class="name" id="dot">
254A, n = mime.<b>dot(</b>m [, B]<b>)</b> 255A, n = mime.<b>dot(</b>m [, B]<b>)</b>
255</p> 256</p>
256 257
257<p class=description> 258<p class="description">
258Low-level filter to perform SMTP stuffing and enable transmission of 259Low-level filter to perform SMTP stuffing and enable transmission of
259messages containing the sequence "CRLF.CRLF". 260messages containing the sequence "CRLF.CRLF".
260</p> 261</p>
261 262
262<p class=parameters> 263<p class="parameters">
263<tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the 264<tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the
264number of characters from the sequence CRLF seen in the end of <tt>B</tt>. 265number of characters from the sequence CRLF seen in the end of <tt>B</tt>.
265'<tt>m</tt>' should tell the same, but for the previous chunk. 266'<tt>m</tt>' should tell the same, but for the previous chunk.
266</p> 267</p>
267 268
268<p class=note>Note: The message body is defined to begin with 269<p class="note">Note: The message body is defined to begin with
269an implicit CRLF. Therefore, to stuff a message correctly, the 270an implicit CRLF. Therefore, to stuff a message correctly, the
270first <tt>m</tt> should have the value 2. 271first <tt>m</tt> should have the value 2.
271</p> 272</p>
272 273
273<pre class=example> 274<pre class="example">
274print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n"))) 275print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n")))
275--&gt; ..\nStuffing the message.\n..\n.. 276--&gt; ..\nStuffing the message.\n..\n..
276</pre> 277</pre>
277 278
278<p class=note> 279<p class="note">
279Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function 280Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
280uses this filter automatically. You don't need to 281uses this filter automatically. You don't need to
281apply it again. 282apply it again.
282</p> 283</p>
283 284
284<!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 285<!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
285 286
286<p class=name id="eol"> 287<p class="name" id="eol">
287A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b> 288A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b>
288</p> 289</p>
289 290
290<p class=description> 291<p class="description">
291Low-level filter to perform end-of-line marker translation. 292Low-level filter to perform end-of-line marker translation.
292For each chunk, the function needs to know if the last character of the 293For each chunk, the function needs to know if the last character of the
293previous chunk could be part of an end-of-line marker or not. This is the 294previous chunk could be part of an end-of-line marker or not. This is the
294context the function receives besides the chunk. An updated version of 295context the function receives besides the chunk. An updated version of
295the context is returned after each new chunk. 296the context is returned after each new chunk.
296</p> 297</p>
297 298
298<p class=parameters> 299<p class="parameters">
299<tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the 300<tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the
300ASCII value of the last character of the previous chunk, if it was a 301ASCII value of the last character of the previous chunk, if it was a
301candidate for line break, or 0 otherwise. 302candidate for line break, or 0 otherwise.
302<tt>B</tt> is the same as <tt>C</tt>, but for the current 303<tt>B</tt> is the same as <tt>C</tt>, but for the current
303chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF. 304chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF.
304</p> 305</p>
305 306
306<pre class=example> 307<pre class="example">
307-- translates the end-of-line marker to UNIX 308-- translates the end-of-line marker to UNIX
308unix = mime.eol(0, dos, "\n") 309unix = mime.eol(0, dos, "\n")
309</pre> 310</pre>
310 311
311<!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 312<!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
312 313
313<p class=name id="qp"> 314<p class="name" id="qp">
314A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b> 315A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b>
315</p> 316</p>
316 317
317<p class=description> 318<p class="description">
318Low-level filter to perform Quoted-Printable encoding. 319Low-level filter to perform Quoted-Printable encoding.
319</p> 320</p>
320 321
321<p class=parameters> 322<p class="parameters">
322<tt>A</tt> is the encoded version of the largest prefix of 323<tt>A</tt> is the encoded version of the largest prefix of
323<tt>C..D</tt> 324<tt>C..D</tt>
324that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of 325that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
325<tt>C..D</tt>, <em>before</em> encoding. 326<tt>C..D</tt>, <em>before</em> encoding.
326If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with 327If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
327the encoding of the remaining bytes of <tt>C</tt>. 328the encoding of the remaining bytes of <tt>C</tt>.
328Throughout encoding, occurrences of CRLF are replaced by the 329Throughout encoding, occurrences of CRLF are replaced by the
329<tt>marker</tt>, which itself defaults to CRLF. 330<tt>marker</tt>, which itself defaults to CRLF.
330</p> 331</p>
331 332
332<p class=note> 333<p class="note">
333Note: The simplest use of this function is to encode a string into it's 334Note: The simplest use of this function is to encode a string into it's
334Quoted-Printable transfer content encoding. 335Quoted-Printable transfer content encoding.
335Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value. 336Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value.
336</p> 337</p>
337 338
338<pre class=example> 339<pre class="example">
339print((mime.qp("maçã"))) 340print((mime.qp("ma��")))
340--&gt; ma=E7=E3= 341--&gt; ma=E7=E3=
341</pre> 342</pre>
342 343
343<!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 344<!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
344 345
345<p class=name id="qpwrp"> 346<p class="name" id="qpwrp">
346A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b> 347A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b>
347</p> 348</p>
348 349
349<p class=description> 350<p class="description">
350Low-level filter to break Quoted-Printable text into lines. 351Low-level filter to break Quoted-Printable text into lines.
351</p> 352</p>
352 353
353<p class=parameters> 354<p class="parameters">
354<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most 355<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
355<tt>length</tt> bytes (defaults to 76). 356<tt>length</tt> bytes (defaults to 76).
356'<tt>n</tt>' should tell how many bytes are left for the first 357'<tt>n</tt>' should tell how many bytes are left for the first
357line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes 358line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
358left in the last line of <tt>A</tt>. 359left in the last line of <tt>A</tt>.
359</p> 360</p>
360 361
361<p class=note> 362<p class="note">
362Note: Besides breaking text into lines, this function makes sure the line 363Note: Besides breaking text into lines, this function makes sure the line
363breaks don't fall in the middle of an escaped character combination. Also, 364breaks don't fall in the middle of an escaped character combination. Also,
364this function only breaks lines that are bigger than <tt>length</tt> bytes. 365this function only breaks lines that are bigger than <tt>length</tt> bytes.
@@ -366,86 +367,86 @@ this function only breaks lines that are bigger than <tt>length</tt> bytes.
366 367
367<!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 368<!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
368 369
369<p class=name id="unb64"> 370<p class="name" id="unb64">
370A, B = mime.<b>unb64(</b>C [, D]<b>)</b> 371A, B = mime.<b>unb64(</b>C [, D]<b>)</b>
371</p> 372</p>
372 373
373<p class=description> 374<p class="description">
374Low-level filter to perform Base64 decoding. 375Low-level filter to perform Base64 decoding.
375</p> 376</p>
376 377
377<p class=parameters> 378<p class="parameters">
378<tt>A</tt> is the decoded version of the largest prefix of 379<tt>A</tt> is the decoded version of the largest prefix of
379<tt>C..D</tt> 380<tt>C..D</tt>
380that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of 381that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
381<tt>C..D</tt>, <em>before</em> decoding. 382<tt>C..D</tt>, <em>before</em> decoding.
382If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is the empty string 383If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is the empty string
383and <tt>B</tt> returns whatever couldn't be decoded. 384and <tt>B</tt> returns whatever couldn't be decoded.
384</p> 385</p>
385 386
386<p class=note> 387<p class="note">
387Note: The simplest use of this function is to decode a string from it's 388Note: The simplest use of this function is to decode a string from it's
388Base64 transfer content encoding. 389Base64 transfer content encoding.
389Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value. 390Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
390</p> 391</p>
391 392
392<pre class=example> 393<pre class="example">
393print((mime.unb64("ZGllZ286cGFzc3dvcmQ="))) 394print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
394--&gt; diego:password 395--&gt; diego:password
395</pre> 396</pre>
396 397
397<!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 398<!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
398 399
399<p class=name id="unqp"> 400<p class="name" id="unqp">
400A, B = mime.<b>unqp(</b>C [, D]<b>)</b> 401A, B = mime.<b>unqp(</b>C [, D]<b>)</b>
401</p> 402</p>
402 403
403<p class=description> 404<p class="description">
404Low-level filter to remove the Quoted-Printable transfer content encoding 405Low-level filter to remove the Quoted-Printable transfer content encoding
405from data. 406from data.
406</p> 407</p>
407 408
408<p class=parameters> 409<p class="parameters">
409<tt>A</tt> is the decoded version of the largest prefix of 410<tt>A</tt> is the decoded version of the largest prefix of
410<tt>C..D</tt> 411<tt>C..D</tt>
411that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of 412that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
412<tt>C..D</tt>, <em>before</em> decoding. 413<tt>C..D</tt>, <em>before</em> decoding.
413If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with 414If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with
414the encoding of the remaining bytes of <tt>C</tt>. 415the encoding of the remaining bytes of <tt>C</tt>.
415</p> 416</p>
416 417
417<p class=note> 418<p class="note">
418Note: The simplest use of this function is to decode a string from it's 419Note: The simplest use of this function is to decode a string from it's
419Quoted-Printable transfer content encoding. 420Quoted-Printable transfer content encoding.
420Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value. 421Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
421</p> 422</p>
422 423
423<pre class=example> 424<pre class="example">
424print((mime.qp("ma=E7=E3="))) 425print((mime.qp("ma=E7=E3=")))
425--&gt; maçã 426--&gt; ma��
426</pre> 427</pre>
427 428
428<!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 429<!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
429 430
430<p class=name id="wrp"> 431<p class="name" id="wrp">
431A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b> 432A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b>
432</p> 433</p>
433 434
434<p class=description> 435<p class="description">
435Low-level filter to break text into lines with CRLF marker. 436Low-level filter to break text into lines with CRLF marker.
436Text is assumed to be in the <a href=#normalize><tt>normalize</tt></a> form. 437Text is assumed to be in the <a href="#normalize"><tt>normalize</tt></a> form.
437</p> 438</p>
438 439
439<p class=parameters> 440<p class="parameters">
440<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most 441<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
441<tt>length</tt> bytes (defaults to 76). 442<tt>length</tt> bytes (defaults to 76).
442'<tt>n</tt>' should tell how many bytes are left for the first 443'<tt>n</tt>' should tell how many bytes are left for the first
443line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes 444line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
444left in the last line of <tt>A</tt>. 445left in the last line of <tt>A</tt>.
445</p> 446</p>
446 447
447<p class=note> 448<p class="note">
448Note: This function only breaks lines that are bigger than 449Note: This function only breaks lines that are bigger than
449<tt>length</tt> bytes. The resulting line length does not include the CRLF 450<tt>length</tt> bytes. The resulting line length does not include the CRLF
450marker. 451marker.
451</p> 452</p>
@@ -453,10 +454,10 @@ marker.
453 454
454<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 455<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
455 456
456<div class=footer> 457<div class="footer">
457<hr> 458<hr>
458<center> 459<center>
459<p class=bar> 460<p class="bar">
460<a href="index.html">home</a> &middot; 461<a href="index.html">home</a> &middot;
461<a href="index.html#down">download</a> &middot; 462<a href="index.html#down">download</a> &middot;
462<a href="installation.html">installation</a> &middot; 463<a href="installation.html">installation</a> &middot;
@@ -466,7 +467,7 @@ marker.
466<p> 467<p>
467<small> 468<small>
468Last modified by Diego Nehab on <br> 469Last modified by Diego Nehab on <br>
469Thu Apr 20 00:25:44 EDT 2006 470Fri Mar 4 15:19:17 BRT 2016
470</small> 471</small>
471</p> 472</p>
472</center> 473</center>
diff --git a/doc/reference.css b/docs/reference.css
index 04e38cf..04e38cf 100644
--- a/doc/reference.css
+++ b/docs/reference.css
diff --git a/doc/reference.html b/docs/reference.html
index 6067ba6..2bc5f78 100644
--- a/doc/reference.html
+++ b/docs/reference.html
@@ -1,11 +1,11 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: Index to reference manual"> 6<meta name="description" content="LuaSocket: Index to reference manual">
7<meta name="keywords" content="Lua, LuaSocket, Index, Manual, Network, Library, 7<meta name="keywords" content="Lua, LuaSocket, Index, Manual, Network, Library,
8Support, Manual"> 8Support, Manual">
9<title>LuaSocket: Index to reference manual</title> 9<title>LuaSocket: Index to reference manual</title>
10<link rel="stylesheet" href="reference.css" type="text/css"> 10<link rel="stylesheet" href="reference.css" type="text/css">
11</head> 11</head>
@@ -14,22 +14,22 @@ Support, Manual">
14 14
15<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 15<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
16 16
17<div class=header> 17<div class="header">
18<hr> 18<hr>
19<center> 19<center>
20<table summary="LuaSocket logo"> 20<table summary="LuaSocket logo">
21<tr><td align=center><a href="http://www.lua.org"> 21<tr><td align="center"><a href="http://www.lua.org">
22<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 22<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
23</a></td></tr> 23</a></td></tr>
24<tr><td align=center valign=top>Network support for the Lua language 24<tr><td align="center" valign="top">Network support for the Lua language
25</td></tr> 25</td></tr>
26</table> 26</table>
27<p class=bar> 27<p class="bar">
28<a href="index.html">home</a> &middot; 28<a href="index.html">home</a> &middot;
29<a href="index.html#download">download</a> &middot; 29<a href="index.html#download">download</a> &middot;
30<a href="installation.html">installation</a> &middot; 30<a href="installation.html">installation</a> &middot;
31<a href="introduction.html">introduction</a> &middot; 31<a href="introduction.html">introduction</a> &middot;
32<a href="reference.html">reference</a> 32<a href="reference.html">reference</a>
33</p> 33</p>
34</center> 34</center>
35<hr> 35<hr>
@@ -92,14 +92,15 @@ Support, Manual">
92<a href="ltn12.html#sink.table">table</a>. 92<a href="ltn12.html#sink.table">table</a>.
93</blockquote> 93</blockquote>
94<blockquote> 94<blockquote>
95<a href="ltn12.html#source">source</a>: 95<a href="ltn12.html#source">source</a>:
96<a href="ltn12.html#source.cat">cat</a>, 96<a href="ltn12.html#source.cat">cat</a>,
97<a href="ltn12.html#source.chain">chain</a>, 97<a href="ltn12.html#source.chain">chain</a>,
98<a href="ltn12.html#source.empty">empty</a>, 98<a href="ltn12.html#source.empty">empty</a>,
99<a href="ltn12.html#source.error">error</a>, 99<a href="ltn12.html#source.error">error</a>,
100<a href="ltn12.html#source.file">file</a>, 100<a href="ltn12.html#source.file">file</a>,
101<a href="ltn12.html#source.simplify">simplify</a>, 101<a href="ltn12.html#source.simplify">simplify</a>,
102<a href="ltn12.html#source.string">string</a>. 102<a href="ltn12.html#source.string">string</a>,
103<a href="ltn12.html#source.table">table</a>.
103</blockquote> 104</blockquote>
104</blockquote> 105</blockquote>
105 106
@@ -147,6 +148,7 @@ Support, Manual">
147<a href="socket.html#connect">connect</a>, 148<a href="socket.html#connect">connect</a>,
148<a href="socket.html#connect">connect4</a>, 149<a href="socket.html#connect">connect4</a>,
149<a href="socket.html#connect">connect6</a>, 150<a href="socket.html#connect">connect6</a>,
151<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
150<a href="socket.html#debug">_DEBUG</a>, 152<a href="socket.html#debug">_DEBUG</a>,
151<a href="dns.html#dns">dns</a>, 153<a href="dns.html#dns">dns</a>,
152<a href="socket.html#gettime">gettime</a>, 154<a href="socket.html#gettime">gettime</a>,
@@ -158,6 +160,7 @@ Support, Manual">
158<a href="socket.html#skip">skip</a>, 160<a href="socket.html#skip">skip</a>,
159<a href="socket.html#sleep">sleep</a>, 161<a href="socket.html#sleep">sleep</a>,
160<a href="socket.html#setsize">_SETSIZE</a>, 162<a href="socket.html#setsize">_SETSIZE</a>,
163<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
161<a href="socket.html#source">source</a>, 164<a href="socket.html#source">source</a>,
162<a href="tcp.html#socket.tcp">tcp</a>, 165<a href="tcp.html#socket.tcp">tcp</a>,
163<a href="tcp.html#socket.tcp4">tcp4</a>, 166<a href="tcp.html#socket.tcp4">tcp4</a>,
@@ -185,6 +188,7 @@ Support, Manual">
185<a href="tcp.html#getpeername">getpeername</a>, 188<a href="tcp.html#getpeername">getpeername</a>,
186<a href="tcp.html#getsockname">getsockname</a>, 189<a href="tcp.html#getsockname">getsockname</a>,
187<a href="tcp.html#getstats">getstats</a>, 190<a href="tcp.html#getstats">getstats</a>,
191<a href="tcp.html#gettimeout">gettimeout</a>,
188<a href="tcp.html#listen">listen</a>, 192<a href="tcp.html#listen">listen</a>,
189<a href="tcp.html#receive">receive</a>, 193<a href="tcp.html#receive">receive</a>,
190<a href="tcp.html#send">send</a>, 194<a href="tcp.html#send">send</a>,
@@ -205,6 +209,7 @@ Support, Manual">
205<a href="udp.html#getoption">getoption</a>, 209<a href="udp.html#getoption">getoption</a>,
206<a href="udp.html#getpeername">getpeername</a>, 210<a href="udp.html#getpeername">getpeername</a>,
207<a href="udp.html#getsockname">getsockname</a>, 211<a href="udp.html#getsockname">getsockname</a>,
212<a href="udp.html#gettimeout">gettimeout</a>,
208<a href="udp.html#receive">receive</a>, 213<a href="udp.html#receive">receive</a>,
209<a href="udp.html#receivefrom">receivefrom</a>, 214<a href="udp.html#receivefrom">receivefrom</a>,
210<a href="udp.html#send">send</a>, 215<a href="udp.html#send">send</a>,
@@ -233,10 +238,10 @@ Support, Manual">
233 238
234<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 239<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
235 240
236<div class=footer> 241<div class="footer">
237<hr> 242<hr>
238<center> 243<center>
239<p class=bar> 244<p class="bar">
240<a href="index.html">home</a> &middot; 245<a href="index.html">home</a> &middot;
241<a href="index.html#down">download</a> &middot; 246<a href="index.html#down">download</a> &middot;
242<a href="installation.html">installation</a> &middot; 247<a href="installation.html">installation</a> &middot;
diff --git a/doc/smtp.html b/docs/smtp.html
index bbbff80..787d0b1 100644
--- a/doc/smtp.html
+++ b/docs/smtp.html
@@ -1,11 +1,11 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: SMTP support"> 6<meta name="description" content="LuaSocket: SMTP support">
7<meta name="keywords" content="Lua, LuaSocket, SMTP, E-Mail, MIME, Multipart, 7<meta name="keywords" content="Lua, LuaSocket, SMTP, E-Mail, MIME, Multipart,
8Library, Support"> 8Library, Support">
9<title>LuaSocket: SMTP support</title> 9<title>LuaSocket: SMTP support</title>
10<link rel="stylesheet" href="reference.css" type="text/css"> 10<link rel="stylesheet" href="reference.css" type="text/css">
11</head> 11</head>
@@ -14,22 +14,22 @@ Library, Support">
14 14
15<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 15<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
16 16
17<div class=header> 17<div class="header">
18<hr> 18<hr>
19<center> 19<center>
20<table summary="LuaSocket logo"> 20<table summary="LuaSocket logo">
21<tr><td align=center><a href="http://www.lua.org"> 21<tr><td align="center"><a href="http://www.lua.org">
22<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 22<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
23</a></td></tr> 23</a></td></tr>
24<tr><td align=center valign=top>Network support for the Lua language 24<tr><td align="center" valign="top">Network support for the Lua language
25</td></tr> 25</td></tr>
26</table> 26</table>
27<p class=bar> 27<p class="bar">
28<a href="index.html">home</a> &middot; 28<a href="index.html">home</a> &middot;
29<a href="index.html#download">download</a> &middot; 29<a href="index.html#download">download</a> &middot;
30<a href="installation.html">installation</a> &middot; 30<a href="installation.html">installation</a> &middot;
31<a href="introduction.html">introduction</a> &middot; 31<a href="introduction.html">introduction</a> &middot;
32<a href="reference.html">reference</a> 32<a href="reference.html">reference</a>
33</p> 33</p>
34</center> 34</center>
35<hr> 35<hr>
@@ -37,14 +37,14 @@ Library, Support">
37 37
38<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 38<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
39 39
40<h2 id=smtp>SMTP</h2> 40<h2 id="smtp">SMTP</h2>
41 41
42<p> The <tt>smtp</tt> namespace provides functionality to send e-mail 42<p> The <tt>smtp</tt> namespace provides functionality to send e-mail
43messages. The high-level API consists of two functions: one to 43messages. The high-level API consists of two functions: one to
44define an e-mail message, and another to actually send the message. 44define an e-mail message, and another to actually send the message.
45Although almost all users will find that these functions provide more than 45Although almost all users will find that these functions provide more than
46enough functionality, the underlying implementation allows for even more 46enough functionality, the underlying implementation allows for even more
47control (if you bother to read the code). 47control (if you bother to read the code).
48</p> 48</p>
49 49
50<p>The implementation conforms to the Simple Mail Transfer Protocol, 50<p>The implementation conforms to the Simple Mail Transfer Protocol,
@@ -54,19 +54,19 @@ href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
54which governs the Internet Message Format. 54which governs the Internet Message Format.
55Multipart messages (those that contain attachments) are part 55Multipart messages (those that contain attachments) are part
56of the MIME standard, but described mainly 56of the MIME standard, but described mainly
57in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a> 57in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>.</p>
58 58
59<p> In the description below, good understanding of <a 59<p> In the description below, good understanding of <a
60href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters 60href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
61sources and sinks</a> and the <a href=mime.html>MIME</a> module is 61sources and sinks</a> and the <a href="mime.html">MIME</a> module is
62assumed. In fact, the SMTP module was the main reason for their 62assumed. In fact, the SMTP module was the main reason for their
63creation. </p> 63creation. </p>
64 64
65<p> 65<p>
66To obtain the <tt>smtp</tt> namespace, run: 66To obtain the <tt>smtp</tt> namespace, run:
67</p> 67</p>
68 68
69<pre class=example> 69<pre class="example">
70-- loads the SMTP module and everything it requires 70-- loads the SMTP module and everything it requires
71local smtp = require("socket.smtp") 71local smtp = require("socket.smtp")
72</pre> 72</pre>
@@ -92,31 +92,149 @@ headers = {<br>
92<p> 92<p>
93Field names are case insensitive (as specified by the standard) and all 93Field names are case insensitive (as specified by the standard) and all
94functions work with lowercase field names (but see 94functions work with lowercase field names (but see
95<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>). 95<a href="socket.html#headers.canonic"><tt>socket.headers.canonic</tt></a>).
96Field values are left unmodified. 96Field values are left unmodified.
97</p> 97</p>
98 98
99<p class=note> 99<p class="note">
100Note: MIME headers are independent of order. Therefore, there is no problem 100Note: MIME headers are independent of order. Therefore, there is no problem
101in representing them in a Lua table. 101in representing them in a Lua table.
102</p> 102</p>
103 103
104<p> 104<p>
105The following constants can be set to control the default behavior of 105The following constants can be set to control the default behavior of
106the SMTP module: 106the SMTP module:
107</p> 107</p>
108 108
109<ul> 109<ul>
110<li> <tt>DOMAIN</tt>: domain used to greet the server; 110<li> <tt>DOMAIN</tt>: domain used to greet the server;</li>
111<li> <tt>PORT</tt>: default port used for the connection; 111<li> <tt>PORT</tt>: default port used for the connection;</li>
112<li> <tt>SERVER</tt>: default server used for the connection; 112<li> <tt>SERVER</tt>: default server used for the connection;</li>
113<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations; 113<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations;</li>
114<li> <tt>ZONE</tt>: default time zone. 114<li> <tt>ZONE</tt>: default time zone.</li>
115</ul> 115</ul>
116 116
117<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
118
119<p class="name" id="message">
120smtp.<b>message(</b>mesgt<b>)</b>
121</p>
122
123<p class="description">
124Returns a <em>simple</em>
125<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
126</p>
127
128<p class="parameters">
129The only parameter of the function is a table describing the message.
130<tt>Mesgt</tt> has the following form (notice the recursive structure):
131</p>
132
133<blockquote>
134<table summary="Mesgt table structure">
135<tr><td><tt>
136mesgt = {<br>
137&nbsp;&nbsp;headers = <i>header-table</i>,<br>
138&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or
139<i>multipart-mesgt</i><br>
140}<br>
141&nbsp;<br>
142multipart-mesgt = {<br>
143&nbsp;&nbsp;[preamble = <i>string</i>,]<br>
144&nbsp;&nbsp;[1] = <i>mesgt</i>,<br>
145&nbsp;&nbsp;[2] = <i>mesgt</i>,<br>
146&nbsp;&nbsp;...<br>
147&nbsp;&nbsp;[<i>n</i>] = <i>mesgt</i>,<br>
148&nbsp;&nbsp;[epilogue = <i>string</i>,]<br>
149}<br>
150</tt></td></tr>
151</table>
152</blockquote>
153
154<p class="parameters">
155For a simple message, all that is needed is a set of <tt>headers</tt>
156and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
157or as a <em>simple</em>
158<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
159source. For multipart messages, the body is a table that
160recursively defines each part as an independent message, plus an optional
161<tt>preamble</tt> and <tt>epilogue</tt>.
162</p>
163
164<p class="return">
165The function returns a <em>simple</em>
166<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
167source that produces the
168message contents as defined by <tt>mesgt</tt>, chunk by chunk.
169Hopefully, the following
170example will make things clear. When in doubt, refer to the appropriate RFC
171as listed in the introduction. </p>
172
173<pre class="example">
174-- load the smtp support and its friends
175local smtp = require("socket.smtp")
176local mime = require("mime")
177local ltn12 = require("ltn12")
178
179-- creates a source to send a message with two parts. The first part is
180-- plain text, the second part is a PNG image, encoded as base64.
181source = smtp.message{
182 headers = {
183 -- Remember that headers are *ignored* by smtp.send.
184 from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
185 to = "Fulano da Silva &lt;fulano@example.com&gt;",
186 subject = "Here is a message with attachments"
187 },
188 body = {
189 preamble = "If your client doesn't understand attachments, \r\n" ..
190 "it will still display the preamble and the epilogue.\r\n" ..
191 "Preamble will probably appear even in a MIME enabled client.",
192 -- first part: no headers means plain text, us-ascii.
193 -- The mime.eol low-level filter normalizes end-of-line markers.
194 [1] = {
195 body = mime.eol(0, [[
196 Lines in a message body should always end with CRLF.
197 The smtp module will *NOT* perform translation. However, the
198 send function *DOES* perform SMTP stuffing, whereas the message
199 function does *NOT*.
200 ]])
201 },
202 -- second part: headers describe content to be a png image,
203 -- sent under the base64 transfer content encoding.
204 -- notice that nothing happens until the message is actually sent.
205 -- small chunks are loaded into memory right before transmission and
206 -- translation happens on the fly.
207 [2] = {
208 headers = {
209 ["content-type"] = 'image/png; name="image.png"',
210 ["content-disposition"] = 'attachment; filename="image.png"',
211 ["content-description"] = 'a beautiful image',
212 ["content-transfer-encoding"] = "BASE64"
213 },
214 body = ltn12.source.chain(
215 ltn12.source.file(io.open("image.png", "rb")),
216 ltn12.filter.chain(
217 mime.encode("base64"),
218 mime.wrap()
219 )
220 )
221 },
222 epilogue = "This might also show up, but after the attachments"
223 }
224}
225
226-- finally send it
227r, e = smtp.send{
228 from = "&lt;sicrano@example.com&gt;",
229 rcpt = "&lt;fulano@example.com&gt;",
230 source = source,
231}
232</pre>
233
234
117<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 235<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
118 236
119<p class=name id=send> 237<p class="name" id="send">
120smtp.<b>send{</b><br> 238smtp.<b>send{</b><br>
121&nbsp;&nbsp;from = <i>string</i>,<br> 239&nbsp;&nbsp;from = <i>string</i>,<br>
122&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br> 240&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br>
@@ -131,53 +249,53 @@ smtp.<b>send{</b><br>
131<b>}</b> 249<b>}</b>
132</p> 250</p>
133 251
134<p class=description> 252<p class="description">
135Sends a message to a recipient list. Since sending messages is not as 253Sends a message to a recipient list. Since sending messages is not as
136simple as downloading an URL from a FTP or HTTP server, this function 254simple as downloading an URL from a FTP or HTTP server, this function
137doesn't have a simple interface. However, see the 255doesn't have a simple interface. However, see the
138<a href=#message><tt>message</tt></a> source factory for 256<a href="#message"><tt>message</tt></a> source factory for
139a very powerful way to define the message contents. 257a very powerful way to define the message contents.
140</p> 258</p>
141 259
142 260
143<p class=parameters> 261<p class="parameters">
144The sender is given by the e-mail address in the <tt>from</tt> field. 262The sender is given by the e-mail address in the <tt>from</tt> field.
145<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail 263<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
146address, or a string 264address, or a string
147in case there is just one recipient. 265in case there is just one recipient.
148The contents of the message are given by a <em>simple</em> 266The contents of the message are given by a <em>simple</em>
149<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 267<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
150<tt>source</tt>. Several arguments are optional: 268<tt>source</tt>. Several arguments are optional:
151</p> 269</p>
152<ul> 270<ul>
153<li> <tt>user</tt>, <tt>password</tt>: User and password for 271<li> <tt>user</tt>, <tt>password</tt>: User and password for
154authentication. The function will attempt LOGIN and PLAIN authentication 272authentication. The function will attempt LOGIN and PLAIN authentication
155methods if supported by the server (both are unsafe); 273methods if supported by the server (both are unsafe);</li>
156<li> <tt>server</tt>: Server to connect to. Defaults to "localhost"; 274<li> <tt>server</tt>: Server to connect to. Defaults to "localhost";</li>
157<li> <tt>port</tt>: Port to connect to. Defaults to 25; 275<li> <tt>port</tt>: Port to connect to. Defaults to 25;</li>
158<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the 276<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
159local machine host name; 277local machine host name;</li>
160<li> <tt>step</tt>: 278<li> <tt>step</tt>:
161<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 279<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
162pump step function used to pass data from the 280pump step function used to pass data from the
163source to the server. Defaults to the LTN12 <tt>pump.step</tt> function; 281source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
164<li><tt>create</tt>: An optional function to be used instead of 282<li><tt>create</tt>: An optional function to be used instead of
165<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. 283<a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
166</ul> 284</ul>
167 285
168<p class=return> 286<p class="return">
169If successful, the function returns 1. Otherwise, the function returns 287If successful, the function returns 1. Otherwise, the function returns
170<b><tt>nil</tt></b> followed by an error message. 288<b><tt>nil</tt></b> followed by an error message.
171</p> 289</p>
172 290
173<p class=note> 291<p class="note">
174Note: SMTP servers can be very picky with the format of e-mail 292Note: SMTP servers can be very picky with the format of e-mail
175addresses. To be safe, use only addresses of the form 293addresses. To be safe, use only addresses of the form
176"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and 294"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and
177<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail 295<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
178addresses can take whatever form you like. </p> 296addresses can take whatever form you like. </p>
179 297
180<p class=note> 298<p class="note">
181Big note: There is a good deal of misconception with the use of the 299Big note: There is a good deal of misconception with the use of the
182destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>', 300destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
183and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a 301and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
@@ -185,68 +303,69 @@ and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
185exact opposite of what you expect. 303exact opposite of what you expect.
186</p> 304</p>
187 305
188<p class=note> 306<p class="note">
189Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the 307Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
190message. Each recipient of an SMTP mail message receives a copy of the 308message. Each recipient of an SMTP mail message receives a copy of the
191message body along with the headers, and nothing more. The headers 309message body along with the headers, and nothing more. The headers
192<em>are</em> part of the message and should be produced by the 310<em>are</em> part of the message and should be produced by the
193<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 311<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
194<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em> 312<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em>
195part of the message and will not be sent to anyone. 313part of the message and will not be sent to anyone.
196</p> 314</p>
197 315
198<p class=note> 316<p class="note">
199<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a> 317<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
200has two <em>important and short</em> sections, "3.6.3. Destination address 318has two <em>important and short</em> sections, "3.6.3. Destination address
201fields" and "5. Security considerations", explaining the proper 319fields" and "5. Security considerations", explaining the proper
202use of these headers. Here is a summary of what it says: 320use of these headers. Here is a summary of what it says:
203</p> 321</p>
204 322
205<ul> 323<ul>
206<li> <tt>To</tt>: contains the address(es) of the primary recipient(s) 324<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
207of the message; 325of the message;</li>
208<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of 326<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
209making a copy on a typewriter using carbon paper) contains the 327making a copy on a typewriter using carbon paper) contains the
210addresses of others who are to receive the message, though the 328addresses of others who are to receive the message, though the
211content of the message may not be directed at them; 329content of the message may not be directed at them;</li>
212<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon 330<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
213Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message. 331Copy") contains addresses of recipients of the message whose addresses are not
214</ul> 332to be revealed to other recipients of the message.</li>
333</ul>
215 334
216<p class=note> 335<p class="note">
217The LuaSocket <tt>send</tt> function does not care or interpret the 336The LuaSocket <tt>send</tt> function does not care or interpret the
218headers you send, but it gives you full control over what is sent and 337headers you send, but it gives you full control over what is sent and
219to whom it is sent: 338to whom it is sent:
220</p> 339</p>
221<ul> 340<ul>
222<li> If someone is to receive the message, the e-mail address <em>has</em> 341<li> If someone is to receive the message, the e-mail address <em>has</em>
223to be in the recipient list. This is the only parameter that controls who 342to be in the recipient list. This is the only parameter that controls who
224gets a copy of the message; 343gets a copy of the message;</li>
225<li> If there are multiple recipients, none of them will automatically 344<li> If there are multiple recipients, none of them will automatically
226know that someone else got that message. That is, the default behavior is 345know that someone else got that message. That is, the default behavior is
227similar to the <tt>Bcc</tt> field of popular e-mail clients; 346similar to the <tt>Bcc</tt> field of popular e-mail clients;</li>
228<li> It is up to you to add the <tt>To</tt> header with the list of primary 347<li> It is up to you to add the <tt>To</tt> header with the list of primary
229recipients so that other recipients can see it; 348recipients so that other recipients can see it;</li>
230<li> It is also up to you to add the <tt>Cc</tt> header with the 349<li> It is also up to you to add the <tt>Cc</tt> header with the
231list of additional recipients so that everyone else sees it; 350list of additional recipients so that everyone else sees it;</li>
232<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is 351<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
233empty. Otherwise, everyone receiving the message will see it and that is 352empty. Otherwise, everyone receiving the message will see it and that is
234exactly what you <em>don't</em> want to happen! 353exactly what you <em>don't</em> want to happen!</li>
235</ul> 354</ul>
236 355
237<p class=note> 356<p class="note">
238I hope this clarifies the issue. Otherwise, please refer to 357I hope this clarifies the issue. Otherwise, please refer to
239<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a> 358<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
240and 359and
241<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>. 360<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
242</p> 361</p>
243 362
244<pre class=example> 363<pre class="example">
245-- load the smtp support 364-- load the smtp support
246local smtp = require("socket.smtp") 365local smtp = require("socket.smtp")
247 366
248-- Connects to server "localhost" and sends a message to users 367-- Connects to server "localhost" and sends a message to users
249-- "fulano@example.com", "beltrano@example.com", 368-- "fulano@example.com", "beltrano@example.com",
250-- and "sicrano@example.com". 369-- and "sicrano@example.com".
251-- Note that "fulano" is the primary recipient, "beltrano" receives a 370-- Note that "fulano" is the primary recipient, "beltrano" receives a
252-- carbon copy and neither of them knows that "sicrano" received a blind 371-- carbon copy and neither of them knows that "sicrano" received a blind
@@ -270,134 +389,17 @@ mesgt = {
270 389
271r, e = smtp.send{ 390r, e = smtp.send{
272 from = from, 391 from = from,
273 rcpt = rcpt, 392 rcpt = rcpt,
274 source = smtp.message(mesgt) 393 source = smtp.message(mesgt)
275} 394}
276</pre> 395</pre>
277 396
278<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
279
280<p class=name id=message>
281smtp.<b>message(</b>mesgt<b>)</b>
282</p>
283
284<p class=description>
285Returns a <em>simple</em>
286<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
287</p>
288
289<p class=parameters>
290The only parameter of the function is a table describing the message.
291<tt>Mesgt</tt> has the following form (notice the recursive structure):
292</p>
293
294<blockquote>
295<table summary="Mesgt table structure">
296<tr><td><tt>
297mesgt = {<br>
298&nbsp;&nbsp;headers = <i>header-table</i>,<br>
299&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or
300<i>multipart-mesgt</i><br>
301}<br>
302&nbsp;<br>
303multipart-mesgt = {<br>
304&nbsp;&nbsp;[preamble = <i>string</i>,]<br>
305&nbsp;&nbsp;[1] = <i>mesgt</i>,<br>
306&nbsp;&nbsp;[2] = <i>mesgt</i>,<br>
307&nbsp;&nbsp;...<br>
308&nbsp;&nbsp;[<i>n</i>] = <i>mesgt</i>,<br>
309&nbsp;&nbsp;[epilogue = <i>string</i>,]<br>
310}<br>
311</tt></td></tr>
312</table>
313</blockquote>
314
315<p class=parameters>
316For a simple message, all that is needed is a set of <tt>headers</tt>
317and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
318or as a <em>simple</em>
319<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
320source. For multipart messages, the body is a table that
321recursively defines each part as an independent message, plus an optional
322<tt>preamble</tt> and <tt>epilogue</tt>.
323</p>
324
325<p class=return>
326The function returns a <em>simple</em>
327<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
328source that produces the
329message contents as defined by <tt>mesgt</tt>, chunk by chunk.
330Hopefully, the following
331example will make things clear. When in doubt, refer to the appropriate RFC
332as listed in the introduction. </p>
333
334<pre class=example>
335-- load the smtp support and its friends
336local smtp = require("socket.smtp")
337local mime = require("mime")
338local ltn12 = require("ltn12")
339
340-- creates a source to send a message with two parts. The first part is
341-- plain text, the second part is a PNG image, encoded as base64.
342source = smtp.message{
343 headers = {
344 -- Remember that headers are *ignored* by smtp.send.
345 from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
346 to = "Fulano da Silva &lt;fulano@example.com&gt;",
347 subject = "Here is a message with attachments"
348 },
349 body = {
350 preamble = "If your client doesn't understand attachments, \r\n" ..
351 "it will still display the preamble and the epilogue.\r\n" ..
352 "Preamble will probably appear even in a MIME enabled client.",
353 -- first part: no headers means plain text, us-ascii.
354 -- The mime.eol low-level filter normalizes end-of-line markers.
355 [1] = {
356 body = mime.eol(0, [[
357 Lines in a message body should always end with CRLF.
358 The smtp module will *NOT* perform translation. However, the
359 send function *DOES* perform SMTP stuffing, whereas the message
360 function does *NOT*.
361 ]])
362 },
363 -- second part: headers describe content to be a png image,
364 -- sent under the base64 transfer content encoding.
365 -- notice that nothing happens until the message is actually sent.
366 -- small chunks are loaded into memory right before transmission and
367 -- translation happens on the fly.
368 [2] = {
369 headers = {
370 ["content-type"] = 'image/png; name="image.png"',
371 ["content-disposition"] = 'attachment; filename="image.png"',
372 ["content-description"] = 'a beautiful image',
373 ["content-transfer-encoding"] = "BASE64"
374 },
375 body = ltn12.source.chain(
376 ltn12.source.file(io.open("image.png", "rb")),
377 ltn12.filter.chain(
378 mime.encode("base64"),
379 mime.wrap()
380 )
381 )
382 },
383 epilogue = "This might also show up, but after the attachments"
384 }
385}
386
387-- finally send it
388r, e = smtp.send{
389 from = "&lt;sicrano@example.com&gt;",
390 rcpt = "&lt;fulano@example.com&gt;",
391 source = source,
392}
393</pre>
394
395<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 397<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
396 398
397<div class=footer> 399<div class="footer">
398<hr> 400<hr>
399<center> 401<center>
400<p class=bar> 402<p class="bar">
401<a href="index.html">home</a> &middot; 403<a href="index.html">home</a> &middot;
402<a href="index.html#down">download</a> &middot; 404<a href="index.html#down">download</a> &middot;
403<a href="installation.html">installation</a> &middot; 405<a href="installation.html">installation</a> &middot;
diff --git a/doc/socket.html b/docs/socket.html
index e6a9bf8..c148114 100644
--- a/doc/socket.html
+++ b/docs/socket.html
@@ -1,10 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: The core namespace"> 6<meta name="description" content="LuaSocket: The core namespace">
7<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support"> 7<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support">
8<title>LuaSocket: The socket namespace</title> 8<title>LuaSocket: The socket namespace</title>
9<link rel="stylesheet" href="reference.css" type="text/css"> 9<link rel="stylesheet" href="reference.css" type="text/css">
10</head> 10</head>
@@ -13,22 +13,22 @@
13 13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="https://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,47 +36,71 @@
36 36
37<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id=socket>The socket namespace</h2> 39<h2 id="socket">The socket namespace</h2>
40 40
41<p> 41<p>
42The <tt>socket</tt> namespace contains the core functionality of LuaSocket. 42The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
43</p> 43</p>
44 44
45<p> 45<p>
46To obtain the <tt>socket</tt> namespace, run: 46To obtain the <tt>socket</tt> namespace, run:
47</p> 47</p>
48 48
49<pre class=example> 49<pre class="example">
50-- loads the socket module 50-- loads the socket module
51local socket = require("socket") 51local socket = require("socket")
52</pre> 52</pre>
53 53
54<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
55
56<p class="name" id="headers.canonic">
57socket.headers.<b>canonic</b></p>
58
59<p> The <tt>socket.headers.canonic</tt> table
60is used by the HTTP and SMTP modules to translate from
61lowercase field names back into their canonic
62capitalization. When a lowercase field name exists as a key
63in this table, the associated value is substituted in
64whenever the field name is sent out.
65</p>
66
67<p>
68You can obtain the <tt>headers</tt> namespace if case run-time
69modifications are required by running:
70</p>
71
72<pre class="example">
73-- loads the headers module
74local headers = require("headers")
75</pre>
76
77
54<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 78<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
55 79
56<p class=name id=bind> 80<p class="name" id="bind">
57socket.<b>bind(</b>address, port [, backlog]<b>)</b> 81socket.<b>bind(</b>address, port [, backlog]<b>)</b>
58</p> 82</p>
59 83
60<p class=description> 84<p class="description">
61This function is a shortcut that creates and returns a TCP server object 85This function is a shortcut that creates and returns a TCP server object
62bound to a local <tt>address</tt> and <tt>port</tt>, ready to 86bound to a local <tt>address</tt> and <tt>port</tt>, ready to
63accept client connections. Optionally, 87accept client connections. Optionally,
64user can also specify the <tt>backlog</tt> argument to the 88user can also specify the <tt>backlog</tt> argument to the
65<a href=tcp.html#listen><tt>listen</tt></a> method (defaults to 32). 89<a href="tcp.html#listen"><tt>listen</tt></a> method (defaults to 32).
66</p> 90</p>
67 91
68<p class=note> 92<p class="note">
69Note: The server object returned will have the option "<tt>reuseaddr</tt>" 93Note: The server object returned will have the option "<tt>reuseaddr</tt>"
70set to <tt><b>true</b></tt>. 94set to <tt><b>true</b></tt>.
71</p> 95</p>
72 96
73<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 97<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
74 98
75<p class=name id=connect> 99<p class="name" id="connect">
76socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b> 100socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
77</p> 101</p>
78 102
79<p class=description> 103<p class="description">
80This function is a shortcut that creates and returns a TCP client object 104This function is a shortcut that creates and returns a TCP client object
81connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally, 105connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
82the user can also specify the local address and port to bind 106the user can also specify the local address and port to bind
@@ -90,90 +114,79 @@ of connect are defined as simple helper functions that restrict the
90 114
91<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 115<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
92 116
93<p class=name id=debug> 117<p class="name" id="debug">
94socket.<b>_DEBUG</b> 118socket.<b>_DEBUG</b>
95</p> 119</p>
96 120
97<p class=description> 121<p class="description">
98This constant is set to <tt><b>true</b></tt> if the library was compiled 122This constant is set to <tt><b>true</b></tt> if the library was compiled
99with debug support. 123with debug support.
100</p> 124</p>
101 125
126<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
127
128<p class="name" id="datagramsize">
129socket.<b>_DATAGRAMSIZE</b>
130</p>
131
132<p class="description">
133Default datagram size used by calls to
134<a href="udp.html#receive"><tt>receive</tt></a> and
135<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
136(Unless changed in compile time, the value is 8192.)
137</p>
138
102<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 139<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
103 140
104<p class=name id=gettime> 141<p class="name" id="gettime">
105socket.<b>gettime()</b> 142socket.<b>gettime()</b>
106</p> 143</p>
107 144
108<p class=description> 145<p class="description">
109Returns the UNIX time in seconds. You should subtract the values returned by this function 146Returns the UNIX time in seconds. You should subtract the values returned by this function
110to get meaningful values. 147to get meaningful values.
111</p> 148</p>
112 149
113<pre class=example> 150<pre class="example">
114t = socket.gettime() 151t = socket.gettime()
115-- do stuff 152-- do stuff
116print(socket.gettime() - t .. " seconds elapsed") 153print(socket.gettime() - t .. " seconds elapsed")
117</pre> 154</pre>
118 155
119<!-- socket.headers ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
120
121<p class=name id="headers.canonic">
122socket.headers.<b>canonic</b></p>
123
124<p> The <tt>socket.headers.canonic</tt> table
125is used by the HTTP and SMTP modules to translate from
126lowercase field names back into their canonic
127capitalization. When a lowercase field name exists as a key
128in this table, the associated value is substituted in
129whenever the field name is sent out.
130</p>
131
132<p>
133You can obtain the <tt>headers</tt> namespace if case run-time
134modifications are required by running:
135</p>
136
137<pre class=example>
138-- loads the headers module
139local headers = require("headers")
140</pre>
141
142<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 156<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
143 157
144<p class=name id=newtry> 158<p class="name" id="newtry">
145socket.<b>newtry(</b>finalizer<b>)</b> 159socket.<b>newtry(</b>finalizer<b>)</b>
146</p> 160</p>
147 161
148<p class=description> 162<p class="description">
149Creates and returns a <em>clean</em> 163Creates and returns a <em>clean</em>
150<a href="#try"><tt>try</tt></a> 164<a href="#try"><tt>try</tt></a>
151function that allows for cleanup before the exception 165function that allows for cleanup before the exception
152is raised. 166is raised.
153</p> 167</p>
154 168
155<p class=parameters> 169<p class="parameters">
156<tt>Finalizer</tt> is a function that will be called before 170<tt>Finalizer</tt> is a function that will be called before
157<tt>try</tt> throws the exception. It will be called 171<tt>try</tt> throws the exception.
158in <em>protected</em> mode.
159</p> 172</p>
160 173
161<p class=return> 174<p class="return">
162The function returns your customized <tt>try</tt> function. 175The function returns your customized <tt>try</tt> function.
163</p> 176</p>
164 177
165<p class=note> 178<p class="note">
166Note: This idea saved a <em>lot</em> of work with the 179Note: This idea saved a <em>lot</em> of work with the
167implementation of protocols in LuaSocket: 180implementation of protocols in LuaSocket:
168</p> 181</p>
169 182
170<pre class=example> 183<pre class="example">
171foo = socket.protect(function() 184foo = socket.protect(function()
172 -- connect somewhere 185 -- connect somewhere
173 local c = socket.try(socket.connect("somewhere", 42)) 186 local c = socket.try(socket.connect("somewhere", 42))
174 -- create a try function that closes 'c' on error 187 -- create a try function that closes 'c' on error
175 local try = socket.newtry(function() c:close() end) 188 local try = socket.newtry(function() c:close() end)
176 -- do everything reassured c will be closed 189 -- do everything reassured c will be closed
177 try(c:send("hello there?\r\n")) 190 try(c:send("hello there?\r\n"))
178 local answer = try(c:receive()) 191 local answer = try(c:receive())
179 ... 192 ...
@@ -185,46 +198,40 @@ end)
185 198
186<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 199<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
187 200
188<p class=name id=protect> 201<p class="name" id="protect">
189socket.<b>protect(</b>func<b>)</b> 202socket.<b>protect(</b>func<b>)</b>
190</p> 203</p>
191 204
192<p class=description> 205<p class="description">
193Converts a function that throws exceptions into a safe function. This 206Converts a function that throws exceptions into a safe function. This
194function only catches exceptions thrown by the <a href=#try><tt>try</tt></a> 207function only catches exceptions thrown by the <a href="#try"><tt>try</tt></a>
195and <a href=#newtry><tt>newtry</tt></a> functions. It does not catch normal 208and <a href="#newtry"><tt>newtry</tt></a> functions. It does not catch normal
196Lua errors. 209Lua errors.
197</p> 210</p>
198 211
199<p class=parameters> 212<p class="parameters">
200<tt>Func</tt> is a function that calls 213<tt>Func</tt> is a function that calls
201<a href=#try><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>) 214<a href="#try"><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>)
202to throw exceptions. 215to throw exceptions.
203</p>
204
205<p class=return>
206Returns an equivalent function that instead of throwing exceptions,
207returns <tt><b>nil</b></tt> followed by an error message.
208</p> 216</p>
209 217
210<p class=note> 218<p class="return">
211Note: Beware that if your function performs some illegal operation that 219Returns an equivalent function that instead of throwing exceptions in case of
212raises an error, the protected function will catch the error and return it 220a failed <a href="#try"><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
213as a string. This is because the <a href=#try><tt>try</tt></a> function 221followed by an error message.
214uses errors as the mechanism to throw exceptions.
215</p> 222</p>
216 223
217<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 224<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
218 225
219<p class=name id=select> 226<p class="name" id="select">
220socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b> 227socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b>
221</p> 228</p>
222 229
223<p class=description> 230<p class="description">
224Waits for a number of sockets to change status. 231Waits for a number of sockets to change status.
225</p> 232</p>
226 233
227<p class=parameters> 234<p class="parameters">
228<tt>Recvt</tt> is an array with the sockets to test for characters 235<tt>Recvt</tt> is an array with the sockets to test for characters
229available for reading. Sockets in the <tt>sendt</tt> array are watched to 236available for reading. Sockets in the <tt>sendt</tt> array are watched to
230see if it is OK to immediately write on them. <tt>Timeout</tt> is the 237see if it is OK to immediately write on them. <tt>Timeout</tt> is the
@@ -235,208 +242,226 @@ be empty tables or <tt><b>nil</b></tt>. Non-socket values (or values with
235non-numeric indices) in the arrays will be silently ignored. 242non-numeric indices) in the arrays will be silently ignored.
236</p> 243</p>
237 244
238<p class=return> The function returns a list with the sockets ready for 245<p class="return"> The function returns a list with the sockets ready for
239reading, a list with the sockets ready for writing and an error message. 246reading, a list with the sockets ready for writing and an error message.
240The error message is "<tt>timeout</tt>" if a timeout condition was met and 247The error message is "<tt>timeout</tt>" if a timeout
248condition was met, "<tt>select failed</tt>" if the call
249to <tt>select</tt> failed, and
241<tt><b>nil</b></tt> otherwise. The returned tables are 250<tt><b>nil</b></tt> otherwise. The returned tables are
242doubly keyed both by integers and also by the sockets 251doubly keyed both by integers and also by the sockets
243themselves, to simplify the test if a specific socket has 252themselves, to simplify the test if a specific socket has
244changed status. 253changed status.
245</p> 254</p>
246 255
247<p class=note> 256<p class="note">
248<b>Note: </b>: <tt>select</tt> can monitor a limited number 257<b>Note:</b> <tt>select</tt> can monitor a limited number
249of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This 258of sockets, as defined by the constant <a href="#setsize">
259<tt>socket._SETSIZE</tt></a>. This
250number may be as high as 1024 or as low as 64 by default, 260number may be as high as 1024 or as low as 64 by default,
251depending on the system. It is usually possible to change this 261depending on the system. It is usually possible to change this
252at compile time. Invoking <tt>select</tt> with a larger 262at compile time. Invoking <tt>select</tt> with a larger
253number of sockets will raise an error. 263number of sockets will raise an error.
254</p> 264</p>
255 265
256<p class=note> 266<p class="note">
257<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail 267<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
258on non-blocking TCP sockets. The function may return a socket as 268on non-blocking TCP sockets. The function may return a socket as
259writable even though the socket is <em>not</em> ready for sending. 269writable even though the socket is <em>not</em> ready for sending.
260</p> 270</p>
261 271
262<p class=note> 272<p class="note">
263<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee 273<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee
264<a href=tcp.html#accept><tt>accept</tt></a> will return immediately. 274<a href="tcp.html#accept"><tt>accept</tt></a> will return immediately.
265Use the <a href=tcp.html#settimeout><tt>settimeout</tt></a> 275Use the <a href="tcp.html#settimeout"><tt>settimeout</tt></a>
266method or <tt>accept</tt> might block forever. 276method or <tt>accept</tt> might block forever.
267</p> 277</p>
268 278
269<p class=note> 279<p class="note">
270<b>Yet another note</b>: If you close a socket and pass 280<b>Yet another note</b>: If you close a socket and pass
271it to <tt>select</tt>, it will be ignored. 281it to <tt>select</tt>, it will be ignored.
272</p> 282</p>
273 283
274<p class=note> 284<p class="note">
275<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. 285<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.
276</p> 286</p>
277 287
288<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
289
290<p class="name" id="setsize">
291socket.<b>_SETSIZE</b>
292</p>
293
294<p class="description">
295The maximum number of sockets that the <a
296href="#select"><tt>select</tt></a> function can handle.
297</p>
298
299
278<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 300<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
279 301
280<p class=name id=sink> 302<p class="name" id="sink">
281socket.<b>sink(</b>mode, socket<b>)</b> 303socket.<b>sink(</b>mode, socket<b>)</b>
282</p> 304</p>
283 305
284<p class=description> 306<p class="description">
285Creates an 307Creates an
286<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 308<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
287sink from a stream socket object. 309sink from a stream socket object.
288</p> 310</p>
289 311
290<p class=parameters> 312<p class="parameters">
291<tt>Mode</tt> defines the behavior of the sink. The following 313<tt>Mode</tt> defines the behavior of the sink. The following
292options are available: 314options are available:
293</p> 315</p>
294<ul> 316<ul>
295<li> <tt>"http-chunked"</tt>: sends data through socket after applying the 317<li> <tt>"http-chunked"</tt>: sends data through socket after applying the
296<em>chunked transfer coding</em>, closing the socket when done; 318<em>chunked transfer coding</em>, closing the socket when done;</li>
297<li> <tt>"close-when-done"</tt>: sends all received data through the 319<li> <tt>"close-when-done"</tt>: sends all received data through the
298socket, closing the socket when done; 320socket, closing the socket when done;</li>
299<li> <tt>"keep-open"</tt>: sends all received data through the 321<li> <tt>"keep-open"</tt>: sends all received data through the
300socket, leaving it open when done. 322socket, leaving it open when done.</li>
301</ul> 323</ul>
302<p> 324<p>
303<tt>Socket</tt> is the stream socket object used to send the data. 325<tt>Socket</tt> is the stream socket object used to send the data.
304</p> 326</p>
305 327
306<p class=return> 328<p class="return">
307The function returns a sink with the appropriate behavior. 329The function returns a sink with the appropriate behavior.
308</p> 330</p>
309 331
310<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 332<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
311 333
312<p class=name id=skip> 334<p class="name" id="skip">
313socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b> 335socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
314</p> 336</p>
315 337
316<p class=description> 338<p class="description">
317Drops a number of arguments and returns the remaining. 339Drops a number of arguments and returns the remaining.
318</p> 340</p>
319 341
320<p class=parameters> 342<p class="parameters">
321<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to 343<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to
322<tt>ret<sub>N</sub></tt> are the arguments. 344<tt>ret<sub>N</sub></tt> are the arguments.
323</p> 345</p>
324 346
325<p class=return> 347<p class="return">
326The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>. 348The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
327</p> 349</p>
328 350
329<p class=note> 351<p class="note">
330Note: This function is useful to avoid creation of dummy variables: 352Note: This function is useful to avoid creation of dummy variables:
331</p> 353</p>
332 354
333<pre class=example> 355<pre class="example">
334-- get the status code and separator from SMTP server reply 356-- get the status code and separator from SMTP server reply
335local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 357local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
336</pre> 358</pre>
337 359
338<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 360<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
339 361
340<p class=name id=sleep> 362<p class="name" id="sleep">
341socket.<b>sleep(</b>time<b>)</b> 363socket.<b>sleep(</b>time<b>)</b>
342</p> 364</p>
343 365
344<p class=description> 366<p class="description">
345Freezes the program execution during a given amount of time. 367Freezes the program execution during a given amount of time.
346</p> 368</p>
347 369
348<p class=parameters> 370<p class="parameters">
349<tt>Time</tt> is the number of seconds to sleep for. If 371<tt>Time</tt> is the number of seconds to sleep for. If
350<tt>time</tt> is negative, the function returns immediately. 372<tt>time</tt> is negative, the function returns immediately.
351</p> 373</p>
352 374
353<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 375<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
354 376
355<p class=name id=source> 377<p class="name" id="source">
356socket.<b>source(</b>mode, socket [, length]<b>)</b> 378socket.<b>source(</b>mode, socket [, length]<b>)</b>
357</p> 379</p>
358 380
359<p class=description> 381<p class="description">
360Creates an 382Creates an
361<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 383<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
362source from a stream socket object. 384source from a stream socket object.
363</p> 385</p>
364 386
365<p class=parameters> 387<p class="parameters">
366<tt>Mode</tt> defines the behavior of the source. The following 388<tt>Mode</tt> defines the behavior of the source. The following
367options are available: 389options are available:
368</p> 390</p>
369<ul> 391<ul>
370<li> <tt>"http-chunked"</tt>: receives data from socket and removes the 392<li> <tt>"http-chunked"</tt>: receives data from socket and removes the
371<em>chunked transfer coding</em> before returning the data; 393<em>chunked transfer coding</em> before returning the data;</li>
372<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the 394<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the
373socket. This mode requires the extra argument <tt>length</tt>; 395socket. This mode requires the extra argument <tt>length</tt>;</li>
374<li> <tt>"until-closed"</tt>: receives data from a socket until the other 396<li> <tt>"until-closed"</tt>: receives data from a socket until the other
375side closes the connection. 397side closes the connection.</li>
376</ul> 398</ul>
377<p> 399<p>
378<tt>Socket</tt> is the stream socket object used to receive the data. 400<tt>Socket</tt> is the stream socket object used to receive the data.
379</p> 401</p>
380 402
381<p class=return> 403<p class="return">
382The function returns a source with the appropriate behavior. 404The function returns a source with the appropriate behavior.
383</p> 405</p>
384 406
385<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 407<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
386 408
387<p class=name id=setsize> 409<p class="name" id="socketinvalid">
388socket.<b>_SETSIZE</b> 410socket.<b>_SOCKETINVALID</b>
389</p> 411</p>
390 412
391<p class=description> 413<p class="description">
392The maximum number of sockets that the <a 414The OS value for an invalid socket. This can be used with <a href="tcp.html#getfd">
393href=#select><tt>select</tt></a> function can handle. 415<tt>tcp:getfd</tt></a> and <a href="tcp.html#setfd"><tt>tcp:setfd</tt></a> methods.
394</p> 416</p>
395 417
396<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 418<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
397 419
398<p class=name id=try> 420<p class="name" id="try">
399socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b> 421socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
400</p> 422</p>
401 423
402<p class=description> 424<p class="description">
403Throws an exception in case of error. The exception can only be caught 425Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
404by the <a href=#protect><tt>protect</tt></a> function. It does not explode 426<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
405into an error message. 427by a <a href="#protect"><tt>protect</tt></a>ed function only.
406</p> 428</p>
407 429
408<p class=parameters> 430<p class="parameters">
409<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary 431<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary
410arguments, but are usually the return values of a function call 432arguments, but are usually the return values of a function call
411nested with <tt>try</tt>. 433nested with <tt>try</tt>.
412</p> 434</p>
413 435
414<p class=return> 436<p class="return">
415The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if 437The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
416<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>. 438<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
439Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
440in a table with metatable used by <a href="#protect"><tt>protect</tt></a> to
441distinguish exceptions from runtime errors.
417</p> 442</p>
418 443
419<pre class=example> 444<pre class="example">
420-- connects or throws an exception with the appropriate error message 445-- connects or throws an exception with the appropriate error message
421c = socket.try(socket.connect("localhost", 80)) 446c = socket.try(socket.connect("localhost", 80))
422</pre> 447</pre>
423 448
424<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 449<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
425 450
426<p class=name id=version> 451<p class="name" id="version">
427socket.<b>_VERSION</b> 452socket.<b>_VERSION</b>
428</p> 453</p>
429 454
430<p class=description> 455<p class="description">
431This constant has a string describing the current LuaSocket version. 456This constant has a string describing the current LuaSocket version.
432</p> 457</p>
433 458
434<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 459<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
435 460
436<div class=footer> 461<div class="footer">
437<hr> 462<hr>
438<center> 463<center>
439<p class=bar> 464<p class="bar">
440<a href="index.html">home</a> &middot; 465<a href="index.html">home</a> &middot;
441<a href="index.html#down">download</a> &middot; 466<a href="index.html#down">download</a> &middot;
442<a href="installation.html">installation</a> &middot; 467<a href="installation.html">installation</a> &middot;
diff --git a/doc/tcp.html b/docs/tcp.html
index fb627a1..a26228d 100644
--- a/doc/tcp.html
+++ b/docs/tcp.html
@@ -13,17 +13,17 @@
13 13
14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
@@ -38,122 +38,45 @@
38 38
39<h2 id="tcp">TCP</h2> 39<h2 id="tcp">TCP</h2>
40 40
41<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
42
43<p class=name id="socket.tcp">
44socket.<b>tcp()</b>
45</p>
46
47<p class=description>
48Creates and returns an TCP master object. A master object can
49be transformed into a server object with the method
50<a href=#listen><tt>listen</tt></a> (after a call to <a
51href=#bind><tt>bind</tt></a>) or into a client object with
52the method <a href=#connect><tt>connect</tt></a>. The only other
53method supported by a master object is the
54<a href=#close><tt>close</tt></a> method.</p>
55
56<p class=return>
57In case of success, a new master object is returned. In case of error,
58<b><tt>nil</tt></b> is returned, followed by an error message.
59</p>
60
61<p class=note>
62Note: The choice between IPv4 and IPv6 happens during a call to
63<a href=#bind><tt>bind</tt></a> or <a
64href=#bind><tt>connect</tt></a>, depending on the address
65family obtained from the resolver.
66</p>
67
68<p class=note>
69Note: Before the choice between IPv4 and IPv6 happens,
70the internal socket object is invalid and therefore <a
71href=#setoption><tt>setoption</tt></a> will fail.
72</p>
73
74<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
75
76<p class=name id="socket.tcp4">
77socket.<b>tcp4()</b>
78</p>
79
80<p class=description>
81Creates and returns an IPv4 TCP master object. A master object can
82be transformed into a server object with the method
83<a href=#listen><tt>listen</tt></a> (after a call to <a
84href=#bind><tt>bind</tt></a>) or into a client object with
85the method <a href=#connect><tt>connect</tt></a>. The only other
86method supported by a master object is the
87<a href=#close><tt>close</tt></a> method.</p>
88
89<p class=return>
90In case of success, a new master object is returned. In case of error,
91<b><tt>nil</tt></b> is returned, followed by an error message.
92</p>
93
94<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
95
96<p class=name id="socket.tcp6">
97socket.<b>tcp6()</b>
98</p>
99
100<p class=description>
101Creates and returns an IPv6 TCP master object. A master object can
102be transformed into a server object with the method
103<a href=#listen><tt>listen</tt></a> (after a call to <a
104href=#bind><tt>bind</tt></a>) or into a client object with
105the method <a href=#connect><tt>connect</tt></a>. The only other
106method supported by a master object is the
107<a href=#close><tt>close</tt></a> method.</p>
108
109<p class=return>
110In case of success, a new master object is returned. In case of error,
111<b><tt>nil</tt></b> is returned, followed by an error message.
112</p>
113
114<p class=note>
115Note: The TCP object returned will have the option
116"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
117</p>
118
119<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 41<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
120 42
121<p class=name id="accept"> 43<p class="name" id="accept">
122server:<b>accept()</b> 44server:<b>accept()</b>
123</p> 45</p>
124 46
125<p class=description> 47<p class="description">
126Waits for a remote connection on the server 48Waits for a remote connection on the server
127object and returns a client object representing that connection. 49object and returns a client object representing that connection.
128</p> 50</p>
129 51
130<p class=return> 52<p class="return">
131If a connection is successfully initiated, a client object is returned. 53If a connection is successfully initiated, a client object is returned.
132If a timeout condition is met, the method returns <b><tt>nil</tt></b> 54If a timeout condition is met, the method returns <b><tt>nil</tt></b>
133followed by the error string '<tt>timeout</tt>'. Other errors are 55followed by the error string '<tt>timeout</tt>'. Other errors are
134reported by <b><tt>nil</tt></b> followed by a message describing the error. 56reported by <b><tt>nil</tt></b> followed by a message describing the error.
135</p> 57</p>
136 58
137<p class=note> 59<p class="note">
138Note: calling <a href=socket.html#select><tt>socket.select</tt></a> 60Note: calling <a href="socket.html#select"><tt>socket.select</tt></a>
139with a server object in 61with a server object in
140the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does 62the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
141<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a 63<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
142href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt> 64href="#settimeout"><tt>settimeout</tt></a> method or <tt>accept</tt>
143might block until <em>another</em> client shows up. 65might block until <em>another</em> client shows up.
144</p> 66</p>
145 67
146<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 68<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
147 69
148<p class=name id="bind"> 70<p class="name" id="bind">
149master:<b>bind(</b>address, port<b>)</b> 71master:<b>bind(</b>address, port<b>)</b>
150</p> 72</p>
151 73
152<p class=description> 74<p class="description">
153Binds a master object to <tt>address</tt> and <tt>port</tt> on the 75Binds a master object to <tt>address</tt> and <tt>port</tt> on the
154local host. 76local host.
77</p>
155 78
156<p class=parameters> 79<p class="parameters">
157<tt>Address</tt> can be an IP address or a host name. 80<tt>Address</tt> can be an IP address or a host name.
158<tt>Port</tt> must be an integer number in the range [0..64K). 81<tt>Port</tt> must be an integer number in the range [0..64K).
159If <tt>address</tt> 82If <tt>address</tt>
@@ -164,25 +87,25 @@ If <tt>port</tt> is 0, the system automatically
164chooses an ephemeral port. 87chooses an ephemeral port.
165</p> 88</p>
166 89
167<p class=return> 90<p class="return">
168In case of success, the method returns 1. In case of error, the 91In case of success, the method returns 1. In case of error, the
169method returns <b><tt>nil</tt></b> followed by an error message. 92method returns <b><tt>nil</tt></b> followed by an error message.
170</p> 93</p>
171 94
172<p class=note> 95<p class="note">
173Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> 96Note: The function <a href="socket.html#bind"><tt>socket.bind</tt></a>
174is available and is a shortcut for the creation of server sockets. 97is available and is a shortcut for the creation of server sockets.
175</p> 98</p>
176 99
177<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 100<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
178 101
179<p class=name id="close"> 102<p class="name" id="close">
180master:<b>close()</b><br> 103master:<b>close()</b><br>
181client:<b>close()</b><br> 104client:<b>close()</b><br>
182server:<b>close()</b> 105server:<b>close()</b>
183</p> 106</p>
184 107
185<p class=description> 108<p class="description">
186Closes a TCP object. The internal socket used by the object is closed 109Closes a TCP object. The internal socket used by the object is closed
187and the local address to which the object was 110and the local address to which the object was
188bound is made available to other applications. No further operations 111bound is made available to other applications. No further operations
@@ -190,7 +113,7 @@ bound is made available to other applications. No further operations
190a closed socket. 113a closed socket.
191</p> 114</p>
192 115
193<p class=note> 116<p class="note">
194Note: It is important to close all used sockets once they are not 117Note: It is important to close all used sockets once they are not
195needed, since, in many systems, each socket uses a file descriptor, 118needed, since, in many systems, each socket uses a file descriptor,
196which are limited system resources. Garbage-collected objects are 119which are limited system resources. Garbage-collected objects are
@@ -199,90 +122,166 @@ automatically closed before destruction, though.
199 122
200<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 123<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
201 124
202<p class=name id="connect"> 125<p class="name" id="connect">
203master:<b>connect(</b>address, port<b>)</b> 126master:<b>connect(</b>address, port<b>)</b>
204</p> 127</p>
205 128
206<p class=description> 129<p class="description">
207Attempts to connect a master object to a remote host, transforming it into a 130Attempts to connect a master object to a remote host, transforming it into a
208client object. 131client object.
209Client objects support methods 132Client objects support methods
210<a href=#send><tt>send</tt></a>, 133<a href="#send"><tt>send</tt></a>,
211<a href=#receive><tt>receive</tt></a>, 134<a href="#receive"><tt>receive</tt></a>,
212<a href=#getsockname><tt>getsockname</tt></a>, 135<a href="#getsockname"><tt>getsockname</tt></a>,
213<a href=#getpeername><tt>getpeername</tt></a>, 136<a href="#getpeername"><tt>getpeername</tt></a>,
214<a href=#settimeout><tt>settimeout</tt></a>, 137<a href="#settimeout"><tt>settimeout</tt></a>,
215and <a href=#close><tt>close</tt></a>. 138and <a href="#close"><tt>close</tt></a>.
216</p> 139</p>
217 140
218<p class=parameters> 141<p class="parameters">
219<tt>Address</tt> can be an IP address or a host name. 142<tt>Address</tt> can be an IP address or a host name.
220<tt>Port</tt> must be an integer number in the range [1..64K). 143<tt>Port</tt> must be an integer number in the range [1..64K).
221</p> 144</p>
222 145
223<p class=return> 146<p class="return">
224In case of error, the method returns <b><tt>nil</tt></b> followed by a string 147In case of error, the method returns <b><tt>nil</tt></b> followed by a string
225describing the error. In case of success, the method returns 1. 148describing the error. In case of success, the method returns 1.
226</p> 149</p>
227 150
228<p class=note> 151<p class="note">
229Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> 152Note: The function <a href="socket.html#connect"><tt>socket.connect</tt></a>
230is available and is a shortcut for the creation of client sockets. 153is available and is a shortcut for the creation of client sockets.
231</p> 154</p>
232 155
233<p class=note> 156<p class="note">
234Note: Starting with LuaSocket 2.0, 157Note: Starting with LuaSocket 2.0,
235the <a href=#settimeout><tt>settimeout</tt></a> 158the <a href="#settimeout"><tt>settimeout</tt></a>
236method affects the behavior of <tt>connect</tt>, causing it to return 159method affects the behavior of <tt>connect</tt>, causing it to return
237with an error in case of a timeout. If that happens, you can still call <a 160with an error in case of a timeout. If that happens, you can still call <a
238href=socket.html#select><tt>socket.select</tt></a> with the socket in the 161href="socket.html#select"><tt>socket.select</tt></a> with the socket in the
239<tt>sendt</tt> table. The socket will be writable when the connection is 162<tt>sendt</tt> table. The socket will be writable when the connection is
240established. 163established.
241</p> 164</p>
242 165
243<p class=note> 166<p class="note">
244Note: Starting with LuaSocket 3.0, the host name resolution 167Note: Starting with LuaSocket 3.0, the host name resolution
245depends on whether the socket was created by <a 168depends on whether the socket was created by
246href=#socket.tcp><tt>socket.tcp</tt></a> or <a 169<a href="#socket.tcp"><tt>socket.tcp</tt></a>,
247href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from 170<a href="#socket.tcp4"><tt>socket.tcp4</tt></a> or
248the appropriate family are tried in succession until the 171<a href="#socket.tcp6"><tt>socket.tcp6</tt></a>. Addresses from
249first success or until the last failure. 172the appropriate family (or both) are tried in the order
173returned by the resolver until the
174first success or until the last failure. If the timeout was
175set to zero, only the first address is tried.
176</p>
177
178<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
179
180<p class="name" id="dirty">
181master:<b>dirty()</b><br>
182client:<b>dirty()</b><br>
183server:<b>dirty()</b>
184</p>
185
186<p class="description">
187Check the read buffer status.
188</p>
189
190<p class="return">
191Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
192</p>
193
194<p class="note">
195Note: <b>This is an internal method, use at your own risk.</b>
196</p>
197
198
199<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
200
201<p class="name" id="getfd">
202master:<b>getfd()</b><br>
203client:<b>getfd()</b><br>
204server:<b>getfd()</b>
205</p>
206
207<p class="description">
208Returns the underling socket descriptor or handle associated to the object.
209</p>
210
211<p class="return">
212The descriptor or handle. In case the object has been closed, the return value
213will be -1. For an invalid socket it will be <a href="socket.html#socketinvalid">
214<tt>_SOCKETINVALID</tt></a>.
215</p>
216
217<p class="note">
218Note: <b>This is an internal method. Unlikely to be
219portable. Use at your own risk. </b>
220</p>
221
222
223<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
224
225<p class="name" id="getoption">
226client:<b>getoption(option)</b><br>
227server:<b>getoption(option)</b>
228</p>
229
230<p class="description">
231Gets options for the TCP object.
232See <a href="#setoption"><tt>setoption</tt></a> for description of the
233option names and values.
234</p>
235
236<p class="parameters">
237<tt>Option</tt> is a string with the option name.</p>
238<ul>
239<li> '<tt>keepalive</tt>'</li>
240<li> '<tt>linger</tt>'</li>
241<li> '<tt>reuseaddr</tt>'</li>
242<li> '<tt>tcp-nodelay</tt>'</li>
243</ul>
244
245<p class="return">
246The method returns the option <tt>value</tt> in case of success, or
247<b><tt>nil</tt></b> followed by an error message otherwise.
250</p> 248</p>
251 249
250
252<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 251<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
253 252
254<p class=name id="getpeername"> 253<p class="name" id="getpeername">
255client:<b>getpeername()</b> 254client:<b>getpeername()</b>
256</p> 255</p>
257 256
258<p class=description> 257<p class="description">
259Returns information about the remote side of a connected client object. 258Returns information about the remote side of a connected client object.
260</p> 259</p>
261 260
262<p class=return> 261<p class="return">
263Returns a string with the IP address of the peer, the 262Returns a string with the IP address of the peer, the
264port number that peer is using for the connection, 263port number that peer is using for the connection,
265and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 264and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
266In case of error, the method returns <b><tt>nil</tt></b>. 265In case of error, the method returns <b><tt>nil</tt></b>.
267</p> 266</p>
268 267
269<p class=note> 268<p class="note">
270Note: It makes no sense to call this method on server objects. 269Note: It makes no sense to call this method on server objects.
271</p> 270</p>
272 271
273<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 272<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
274 273
275<p class=name id="getsockname"> 274<p class="name" id="getsockname">
276master:<b>getsockname()</b><br> 275master:<b>getsockname()</b><br>
277client:<b>getsockname()</b><br> 276client:<b>getsockname()</b><br>
278server:<b>getsockname()</b> 277server:<b>getsockname()</b>
279</p> 278</p>
280 279
281<p class=description> 280<p class="description">
282Returns the local address information associated to the object. 281Returns the local address information associated to the object.
283</p> 282</p>
284 283
285<p class=return> 284<p class="return">
286The method returns a string with local IP address, a number with 285The method returns a string with local IP address, a number with
287the local port, 286the local port,
288and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 287and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@@ -291,83 +290,97 @@ In case of error, the method returns <b><tt>nil</tt></b>.
291 290
292<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 291<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
293 292
294<p class=name id="getstats"> 293<p class="name" id="getstats">
295master:<b>getstats()</b><br> 294master:<b>getstats()</b><br>
296client:<b>getstats()</b><br> 295client:<b>getstats()</b><br>
297server:<b>getstats()</b><br> 296server:<b>getstats()</b><br>
298</p> 297</p>
299 298
300<p class=description> 299<p class="description">
301Returns accounting information on the socket, useful for throttling 300Returns accounting information on the socket, useful for throttling
302of bandwidth. 301of bandwidth.
303</p> 302</p>
304 303
305<p class=return> 304<p class="return">
306The method returns the number of bytes received, the number of bytes sent, 305The method returns the number of bytes received, the number of bytes sent,
307and the age of the socket object in seconds. 306and the age of the socket object in seconds.
308</p> 307</p>
309 308
309<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
310
311<p class="name" id="gettimeout">
312master:<b>gettimeout()</b><br>
313client:<b>gettimeout()</b><br>
314server:<b>gettimeout()</b>
315</p>
316
317<p class="description">
318Returns the current block timeout followed by the curent
319total timeout.
320</p>
321
322
310<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 323<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
311 324
312<p class=name id="listen"> 325<p class="name" id="listen">
313master:<b>listen(</b>backlog<b>)</b> 326master:<b>listen(</b>backlog<b>)</b>
314</p> 327</p>
315 328
316<p class=description> 329<p class="description">
317Specifies the socket is willing to receive connections, transforming the 330Specifies the socket is willing to receive connections, transforming the
318object into a server object. Server objects support the 331object into a server object. Server objects support the
319<a href=#accept><tt>accept</tt></a>, 332<a href="#accept"><tt>accept</tt></a>,
320<a href=#getsockname><tt>getsockname</tt></a>, 333<a href="#getsockname"><tt>getsockname</tt></a>,
321<a href=#setoption><tt>setoption</tt></a>, 334<a href="#setoption"><tt>setoption</tt></a>,
322<a href=#settimeout><tt>settimeout</tt></a>, 335<a href="#settimeout"><tt>settimeout</tt></a>,
323and <a href=#close><tt>close</tt></a> methods. 336and <a href="#close"><tt>close</tt></a> methods.
324</p> 337</p>
325 338
326<p class=parameters> 339<p class="parameters">
327The parameter <tt>backlog</tt> specifies the number of client 340The parameter <tt>backlog</tt> specifies the number of client
328connections that can 341connections that can
329be queued waiting for service. If the queue is full and another client 342be queued waiting for service. If the queue is full and another client
330attempts connection, the connection is refused. 343attempts connection, the connection is refused.
331</p> 344</p>
332 345
333<p class=return> 346<p class="return">
334In case of success, the method returns 1. In case of error, the 347In case of success, the method returns 1. In case of error, the
335method returns <b><tt>nil</tt></b> followed by an error message. 348method returns <b><tt>nil</tt></b> followed by an error message.
336</p> 349</p>
337 350
338<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 351<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
339 352
340<p class=name id="receive"> 353<p class="name" id="receive">
341client:<b>receive(</b>[pattern [, prefix]]<b>)</b> 354client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
342</p> 355</p>
343 356
344<p class=description> 357<p class="description">
345Reads data from a client object, according to the specified <em>read 358Reads data from a client object, according to the specified <em>read
346pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. 359pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
347</p> 360</p>
348 361
349<p class=parameters> 362<p class="parameters">
350<tt>Pattern</tt> can be any of the following: 363<tt>Pattern</tt> can be any of the following:
351</p> 364</p>
352 365
353<ul> 366<ul>
354<li> '<tt>*a</tt>': reads from the socket until the connection is 367<li> '<tt>*a</tt>': reads from the socket until the connection is
355closed. No end-of-line translation is performed; 368closed. No end-of-line translation is performed;</li>
356<li> '<tt>*l</tt>': reads a line of text from the socket. The line is 369<li> '<tt>*l</tt>': reads a line of text from the socket. The line is
357terminated by a LF character (ASCII&nbsp;10), optionally preceded by a 370terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
358CR character (ASCII&nbsp;13). The CR and LF characters are not included in 371CR character (ASCII&nbsp;13). The CR and LF characters are not included in
359the returned line. In fact, <em>all</em> CR characters are 372the returned line. In fact, <em>all</em> CR characters are
360ignored by the pattern. This is the default pattern; 373ignored by the pattern. This is the default pattern;</li>
361<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> 374<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
362of bytes from the socket. 375of bytes from the socket.</li>
363</ul> 376</ul>
364 377
365<p class=parameters> 378<p class="parameters">
366<tt>Prefix</tt> is an optional string to be concatenated to the beginning 379<tt>Prefix</tt> is an optional string to be concatenated to the beginning
367of any received data before return. 380of any received data before return.
368</p> 381</p>
369 382
370<p class=return> 383<p class="return">
371If successful, the method returns the received pattern. In case of error, 384If successful, the method returns the received pattern. In case of error,
372the method returns <tt><b>nil</b></tt> followed by an error 385the method returns <tt><b>nil</b></tt> followed by an error
373message, followed by a (possibly empty) string containing 386message, followed by a (possibly empty) string containing
@@ -377,7 +390,7 @@ closed before the transmission was completed or the string
377'<tt>timeout</tt>' in case there was a timeout during the operation. 390'<tt>timeout</tt>' in case there was a timeout during the operation.
378</p> 391</p>
379 392
380<p class=note> 393<p class="note">
381<b>Important note</b>: This function was changed <em>severely</em>. It used 394<b>Important note</b>: This function was changed <em>severely</em>. It used
382to support multiple patterns (but I have never seen this feature used) and 395to support multiple patterns (but I have never seen this feature used) and
383now it doesn't anymore. Partial results used to be returned in the same 396now it doesn't anymore. Partial results used to be returned in the same
@@ -388,22 +401,22 @@ too.
388 401
389<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 402<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
390 403
391<p class=name id="send"> 404<p class="name" id="send">
392client:<b>send(</b>data [, i [, j]]<b>)</b> 405client:<b>send(</b>data [, i [, j]]<b>)</b>
393</p> 406</p>
394 407
395<p class=description> 408<p class="description">
396Sends <tt>data</tt> through client object. 409Sends <tt>data</tt> through client object.
397</p> 410</p>
398 411
399<p class=parameters> 412<p class="parameters">
400<tt>Data</tt> is the string to be sent. The optional arguments 413<tt>Data</tt> is the string to be sent. The optional arguments
401<tt>i</tt> and <tt>j</tt> work exactly like the standard 414<tt>i</tt> and <tt>j</tt> work exactly like the standard
402<tt>string.sub</tt> Lua function to allow the selection of a 415<tt>string.sub</tt> Lua function to allow the selection of a
403substring to be sent. 416substring to be sent.
404</p> 417</p>
405 418
406<p class=return> 419<p class="return">
407If successful, the method returns the index of the last byte 420If successful, the method returns the index of the last byte
408within <tt>[i, j]</tt> that has been sent. Notice that, if 421within <tt>[i, j]</tt> that has been sent. Notice that, if
409<tt>i</tt> is 1 or absent, this is effectively the total 422<tt>i</tt> is 1 or absent, this is effectively the total
@@ -417,7 +430,7 @@ was completed or the string '<tt>timeout</tt>' in case
417there was a timeout during the operation. 430there was a timeout during the operation.
418</p> 431</p>
419 432
420<p class=note> 433<p class="note">
421Note: Output is <em>not</em> buffered. For small strings, 434Note: Output is <em>not</em> buffered. For small strings,
422it is always better to concatenate them in Lua 435it is always better to concatenate them in Lua
423(with the '<tt>..</tt>' operator) and send the result in one call 436(with the '<tt>..</tt>' operator) and send the result in one call
@@ -426,27 +439,27 @@ instead of calling the method several times.
426 439
427<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 440<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
428 441
429<p class=name id="setoption"> 442<p class="name" id="setoption">
430client:<b>setoption(</b>option [, value]<b>)</b><br> 443client:<b>setoption(</b>option [, value]<b>)</b><br>
431server:<b>setoption(</b>option [, value]<b>)</b> 444server:<b>setoption(</b>option [, value]<b>)</b>
432</p> 445</p>
433 446
434<p class=description> 447<p class="description">
435Sets options for the TCP object. Options are only needed by low-level or 448Sets options for the TCP object. Options are only needed by low-level or
436time-critical applications. You should only modify an option if you 449time-critical applications. You should only modify an option if you
437are sure you need it. 450are sure you need it.
438</p> 451</p>
439 452
440<p class=parameters> 453<p class="parameters">
441<tt>Option</tt> is a string with the option name, and <tt>value</tt> 454<tt>Option</tt> is a string with the option name, and <tt>value</tt>
442depends on the option being set: 455depends on the option being set:</p>
443 456
444<ul> 457<ul>
445 458
446<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables 459<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
447the periodic transmission of messages on a connected socket. Should the 460the periodic transmission of messages on a connected socket. Should the
448connected party fail to respond to these messages, the connection is 461connected party fail to respond to these messages, the connection is
449considered broken and processes using the socket are notified; 462considered broken and processes using the socket are notified;</li>
450 463
451<li> '<tt>linger</tt>': Controls the action taken when unsent data are 464<li> '<tt>linger</tt>': Controls the action taken when unsent data are
452queued on a socket and a close is performed. The value is a table with a 465queued on a socket and a close is performed. The value is a table with a
@@ -457,101 +470,85 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
457'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will 470'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
458process the close in a manner that allows the process to continue as 471process the close in a manner that allows the process to continue as
459quickly as possible. I do not advise you to set this to anything other than 472quickly as possible. I do not advise you to set this to anything other than
460zero; 473zero;</li>
461 474
462<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules 475<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
463used in validating addresses supplied in a call to 476used in validating addresses supplied in a call to
464<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses; 477<a href="#bind"><tt>bind</tt></a> should allow reuse of local addresses;</li>
465 478
466<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> 479<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
467disables the Nagle's algorithm for the connection; 480disables the Nagle's algorithm for the connection;</li>
481
482<li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!!</li>
483
484<li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!!</li>
485
486<li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!!</li>
487
488<li> '<tt>tcp-defer-accept</tt>': value for <tt>TCP_DEFER_ACCEPT</tt> Linux only!!</li>
489
490<li> '<tt>tcp-fastopen</tt>': value for <tt>TCP_FASTOPEN</tt> Linux only!!</li>
491
492<li> '<tt>tcp-fastopen-connect</tt>': value for <tt>TCP_FASTOPEN_CONNECT</tt> Linux only!!</li>
468 493
469<li> '<tt>ipv6-v6only</tt>': 494<li> '<tt>ipv6-v6only</tt>':
470Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to 495Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
471sending and receiving only IPv6 packets. 496sending and receiving only IPv6 packets.</li>
472</ul> 497</ul>
473 498
474<p class=return> 499<p class="return">
475The method returns 1 in case of success, or <b><tt>nil</tt></b> 500The method returns 1 in case of success, or <b><tt>nil</tt></b>
476followed by an error message otherwise. 501followed by an error message otherwise.
477</p> 502</p>
478 503
479<p class=note> 504<p class="note">
480Note: The descriptions above come from the man pages. 505Note: The descriptions above come from the man pages.
481</p> 506</p>
482 507
483<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
484
485<p class=name id="getoption">
486client:<b>getoption(</b>option)</b><br>
487server:<b>getoption(</b>option)</b>
488</p>
489
490<p class=description>
491Gets options for the TCP object.
492See <a href=#setoption><tt>setoption</tt></a> for description of the
493option names and values.
494</p>
495
496<p class=parameters>
497<tt>Option</tt> is a string with the option name.
498<ul>
499
500<li> '<tt>keepalive</tt>'
501<li> '<tt>linger</tt>'
502<li> '<tt>reuseaddr</tt>'
503<li> '<tt>tcp-nodelay</tt>'
504</ul>
505
506<p class=return>
507The method returns the option <tt>value</tt> in case of success, or
508<b><tt>nil</tt></b> followed by an error message otherwise.
509</p>
510
511<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 508<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
512 509
513<p class=name id="setstats"> 510<p class="name" id="setstats">
514master:<b>setstats(</b>received, sent, age<b>)</b><br> 511master:<b>setstats(</b>received, sent, age<b>)</b><br>
515client:<b>setstats(</b>received, sent, age<b>)</b><br> 512client:<b>setstats(</b>received, sent, age<b>)</b><br>
516server:<b>setstats(</b>received, sent, age<b>)</b><br> 513server:<b>setstats(</b>received, sent, age<b>)</b><br>
517</p> 514</p>
518 515
519<p class=description> 516<p class="description">
520Resets accounting information on the socket, useful for throttling 517Resets accounting information on the socket, useful for throttling
521of bandwidth. 518of bandwidth.
522</p> 519</p>
523 520
524<p class=parameters> 521<p class="parameters">
525<tt>Received</tt> is a number with the new number of bytes received. 522<tt>Received</tt> is a number with the new number of bytes received.
526<tt>Sent</tt> is a number with the new number of bytes sent. 523<tt>Sent</tt> is a number with the new number of bytes sent.
527<tt>Age</tt> is the new age in seconds. 524<tt>Age</tt> is the new age in seconds.
528</p> 525</p>
529 526
530<p class=return> 527<p class="return">
531The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. 528The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
532</p> 529</p>
533 530
534<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 531<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
535 532
536<p class=name id="settimeout"> 533<p class="name" id="settimeout">
537master:<b>settimeout(</b>value [, mode]<b>)</b><br> 534master:<b>settimeout(</b>value [, mode]<b>)</b><br>
538client:<b>settimeout(</b>value [, mode]<b>)</b><br> 535client:<b>settimeout(</b>value [, mode]<b>)</b><br>
539server:<b>settimeout(</b>value [, mode]<b>)</b> 536server:<b>settimeout(</b>value [, mode]<b>)</b>
540</p> 537</p>
541 538
542<p class=description> 539<p class="description">
543Changes the timeout values for the object. By default, 540Changes the timeout values for the object. By default,
544all I/O operations are blocking. That is, any call to the methods 541all I/O operations are blocking. That is, any call to the methods
545<a href=#send><tt>send</tt></a>, 542<a href="#send"><tt>send</tt></a>,
546<a href=#receive><tt>receive</tt></a>, and 543<a href="#receive"><tt>receive</tt></a>, and
547<a href=#accept><tt>accept</tt></a> 544<a href="#accept"><tt>accept</tt></a>
548will block indefinitely, until the operation completes. The 545will block indefinitely, until the operation completes. The
549<tt>settimeout</tt> method defines a limit on the amount of time the 546<tt>settimeout</tt> method defines a limit on the amount of time the
550I/O methods can block. When a timeout is set and the specified amount of 547I/O methods can block. When a timeout is set and the specified amount of
551time has elapsed, the affected methods give up and fail with an error code. 548time has elapsed, the affected methods give up and fail with an error code.
552</p> 549</p>
553 550
554<p class=parameters> 551<p class="parameters">
555The amount of time to wait is specified as the 552The amount of time to wait is specified as the
556<tt>value</tt> parameter, in seconds. There are two timeout modes and 553<tt>value</tt> parameter, in seconds. There are two timeout modes and
557both can be used together for fine tuning: 554both can be used together for fine tuning:
@@ -568,12 +565,12 @@ the amount of time LuaSocket can block a Lua script before returning from
568a call.</li> 565a call.</li>
569</ul> 566</ul>
570 567
571<p class=parameters> 568<p class="parameters">
572The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block 569The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block
573indefinitely. Negative timeout values have the same effect. 570indefinitely. Negative timeout values have the same effect.
574</p> 571</p>
575 572
576<p class=note> 573<p class="note">
577Note: although timeout values have millisecond precision in LuaSocket, 574Note: although timeout values have millisecond precision in LuaSocket,
578large blocks can cause I/O functions not to respect timeout values due 575large blocks can cause I/O functions not to respect timeout values due
579to the time the library takes to transfer blocks to and from the OS 576to the time the library takes to transfer blocks to and from the OS
@@ -582,7 +579,7 @@ and perform automatic name resolution might be blocked by the resolver for
582longer than the specified timeout value. 579longer than the specified timeout value.
583</p> 580</p>
584 581
585<p class=note> 582<p class="note">
586Note: The old <tt>timeout</tt> method is deprecated. The name has been 583Note: The old <tt>timeout</tt> method is deprecated. The name has been
587changed for sake of uniformity, since all other method names already 584changed for sake of uniformity, since all other method names already
588contained verbs making their imperative nature obvious. 585contained verbs making their imperative nature obvious.
@@ -590,94 +587,138 @@ contained verbs making their imperative nature obvious.
590 587
591<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 588<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
592 589
593<p class=name id="shutdown"> 590<p class="name" id="shutdown">
594client:<b>shutdown(</b>mode<b>)</b><br> 591client:<b>shutdown(</b>mode<b>)</b><br>
595</p> 592</p>
596 593
597<p class=description> 594<p class="description">
598Shuts down part of a full-duplex connection. 595Shuts down part of a full-duplex connection.
599</p> 596</p>
600 597
601<p class=parameters> 598<p class="parameters">
602Mode tells which way of the connection should be shut down and can 599Mode tells which way of the connection should be shut down and can
603take the value: 600take the value:
604<ul> 601<ul>
605<li>"<tt>both</tt>": disallow further sends and receives on the object. 602<li>"<tt>both</tt>": disallow further sends and receives on the object.
606This is the default mode; 603This is the default mode;</li>
607<li>"<tt>send</tt>": disallow further sends on the object; 604<li>"<tt>send</tt>": disallow further sends on the object;</li>
608<li>"<tt>receive</tt>": disallow further receives on the object. 605<li>"<tt>receive</tt>": disallow further receives on the object.</li>
609</ul> 606</ul>
607</p>
610 608
611<p class=return> 609<p class="return">
612This function returns 1. 610This function returns 1.
613</p> 611</p>
614 612
615<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 613<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
616 614
617<p class=name id="dirty"> 615<p class="name" id="setfd">
618master:<b>dirty()</b><br> 616master:<b>setfd(</b>fd<b>)</b><br>
619client:<b>dirty()</b><br> 617client:<b>setfd(</b>fd<b>)</b><br>
620server:<b>dirty()</b> 618server:<b>setfd(</b>fd<b>)</b>
621</p> 619</p>
622 620
623<p class=description> 621<p class="description">
624Check the read buffer status. 622Sets the underling socket descriptor or handle associated to the object. The current one
623is simply replaced, not closed, and no other change to the object state is made.
624To set it as invalid use <a href="socket.html#socketinvalid"><tt>_SOCKETINVALID</tt></a>.
625</p> 625</p>
626 626
627<p class=return> 627<p class="return">
628Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise. 628No return value.
629</p> 629</p>
630 630
631<p class=note> 631<p class="note">
632Note: <b>This is an internal method, any use is unlikely to be portable.</b> 632Note: <b>This is an internal method. Unlikely to be
633portable. Use at your own risk. </b>
633</p> 634</p>
634 635
635<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 636<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
636 637
637<p class=name id="getfd"> 638<p class="name" id="socket.tcp">
638master:<b>getfd()</b><br> 639socket.<b>tcp()</b>
639client:<b>getfd()</b><br>
640server:<b>getfd()</b>
641</p> 640</p>
642 641
643<p class=description> 642<p class="description">
644Returns the underling socket descriptor or handle associated to the object. 643Creates and returns an TCP master object. A master object can
644be transformed into a server object with the method
645<a href="#listen"><tt>listen</tt></a> (after a call to <a
646href="#bind"><tt>bind</tt></a>) or into a client object with
647the method <a href="#connect"><tt>connect</tt></a>. The only other
648method supported by a master object is the
649<a href="#close"><tt>close</tt></a> method.</p>
650
651<p class="return">
652In case of success, a new master object is returned. In case of error,
653<b><tt>nil</tt></b> is returned, followed by an error message.
645</p> 654</p>
646 655
647<p class=return> 656<p class="note">
648The descriptor or handle. In case the object has been closed, the return will be -1. 657Note: The choice between IPv4 and IPv6 happens during a call to
658<a href="#bind"><tt>bind</tt></a> or <a
659href="#bind"><tt>connect</tt></a>, depending on the address
660family obtained from the resolver.
649</p> 661</p>
650 662
651<p class=note> 663<p class="note">
652Note: <b>This is an internal method, any use is unlikely to be portable.</b> 664Note: Before the choice between IPv4 and IPv6 happens,
665the internal socket object is invalid and therefore <a
666href="#setoption"><tt>setoption</tt></a> will fail.
653</p> 667</p>
654 668
655<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 669<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
656 670
657<p class=name id="setfd"> 671<p class="name" id="socket.tcp4">
658master:<b>setfd(</b>fd<b>)</b><br> 672socket.<b>tcp4()</b>
659client:<b>setfd(</b>fd<b>)</b><br>
660server:<b>setfd(</b>fd<b>)</b>
661</p> 673</p>
662 674
663<p class=description> 675<p class="description">
664Sets 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. 676Creates and returns an IPv4 TCP master object. A master object can
677be transformed into a server object with the method
678<a href="#listen"><tt>listen</tt></a> (after a call to <a
679href="#bind"><tt>bind</tt></a>) or into a client object with
680the method <a href="#connect"><tt>connect</tt></a>. The only other
681method supported by a master object is the
682<a href="#close"><tt>close</tt></a> method.</p>
683
684<p class="return">
685In case of success, a new master object is returned. In case of error,
686<b><tt>nil</tt></b> is returned, followed by an error message.
665</p> 687</p>
666 688
667<p class=return> 689<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
668No return value. 690
691<p class="name" id="socket.tcp6">
692socket.<b>tcp6()</b>
669</p> 693</p>
670 694
671<p class=note> 695<p class="description">
672Note: <b>This is an internal method, any use is unlikely to be portable.</b> 696Creates and returns an IPv6 TCP master object. A master object can
697be transformed into a server object with the method
698<a href="#listen"><tt>listen</tt></a> (after a call to <a
699href="#bind"><tt>bind</tt></a>) or into a client object with
700the method <a href="#connect"><tt>connect</tt></a>. The only other
701method supported by a master object is the
702<a href="#close"><tt>close</tt></a> method.</p>
703
704<p class="return">
705In case of success, a new master object is returned. In case of error,
706<b><tt>nil</tt></b> is returned, followed by an error message.
673</p> 707</p>
674 708
709<p class="note">
710Note: The TCP object returned will have the option
711"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
712</p>
713
714
715
675<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 716<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
676 717
677<div class=footer> 718<div class="footer">
678<hr> 719<hr>
679<center> 720<center>
680<p class=bar> 721<p class="bar">
681<a href="index.html">home</a> &middot; 722<a href="index.html">home</a> &middot;
682<a href="index.html#down">download</a> &middot; 723<a href="index.html#down">download</a> &middot;
683<a href="installation.html">installation</a> &middot; 724<a href="installation.html">installation</a> &middot;
diff --git a/doc/udp.html b/docs/udp.html
index a300f2f..db711cb 100644
--- a/doc/udp.html
+++ b/docs/udp.html
@@ -13,17 +13,17 @@
13 13
14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 14<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
15 15
16<div class=header> 16<div class="header">
17<hr> 17<hr>
18<center> 18<center>
19<table summary="LuaSocket logo"> 19<table summary="LuaSocket logo">
20<tr><td align=center><a href="http://www.lua.org"> 20<tr><td align="center"><a href="http://www.lua.org">
21<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> 21<img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
22</a></td></tr> 22</a></td></tr>
23<tr><td align=center valign=top>Network support for the Lua language 23<tr><td align="center" valign="top">Network support for the Lua language
24</td></tr> 24</td></tr>
25</table> 25</table>
26<p class=bar> 26<p class="bar">
27<a href="index.html">home</a> &middot; 27<a href="index.html">home</a> &middot;
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
@@ -39,112 +39,6 @@
39 39
40<h2 id="udp">UDP</h2> 40<h2 id="udp">UDP</h2>
41 41
42<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
43
44<p class="name" id="socket.udp">
45socket.<b>udp()</b>
46</p>
47
48<p class="description">
49Creates and returns an unconnected UDP object.
50Unconnected objects support the
51<a href="#sendto"><tt>sendto</tt></a>,
52<a href="#receive"><tt>receive</tt></a>,
53<a href="#receivefrom"><tt>receivefrom</tt></a>,
54<a href="#getoption"><tt>getoption</tt></a>,
55<a href="#getsockname"><tt>getsockname</tt></a>,
56<a href="#setoption"><tt>setoption</tt></a>,
57<a href="#settimeout"><tt>settimeout</tt></a>,
58<a href="#setpeername"><tt>setpeername</tt></a>,
59<a href="#setsockname"><tt>setsockname</tt></a>, and
60<a href="#close"><tt>close</tt></a>.
61The <a href="#setpeername"><tt>setpeername</tt></a>
62is used to connect the object.
63</p>
64
65<p class="return">
66In case of success, a new unconnected UDP object
67returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
68an error message.
69</p>
70
71<p class=note>
72Note: The choice between IPv4 and IPv6 happens during a call to
73<a href=#sendto><tt>sendto</tt></a>, <a
74href=#setpeername><tt>setpeername</tt></a>, or <a
75href=#setsockname><tt>sockname</tt></a>, depending on the address
76family obtained from the resolver.
77</p>
78
79<p class=note>
80Note: Before the choice between IPv4 and IPv6 happens,
81the internal socket object is invalid and therefore <a
82href=#setoption><tt>setoption</tt></a> will fail.
83</p>
84
85<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
86
87<p class="name" id="socket.udp">
88socket.<b>udp4()</b>
89</p>
90
91<p class="description">
92Creates and returns an unconnected IPv4 UDP object.
93Unconnected objects support the
94<a href="#sendto"><tt>sendto</tt></a>,
95<a href="#receive"><tt>receive</tt></a>,
96<a href="#receivefrom"><tt>receivefrom</tt></a>,
97<a href="#getoption"><tt>getoption</tt></a>,
98<a href="#getsockname"><tt>getsockname</tt></a>,
99<a href="#setoption"><tt>setoption</tt></a>,
100<a href="#settimeout"><tt>settimeout</tt></a>,
101<a href="#setpeername"><tt>setpeername</tt></a>,
102<a href="#setsockname"><tt>setsockname</tt></a>, and
103<a href="#close"><tt>close</tt></a>.
104The <a href="#setpeername"><tt>setpeername</tt></a>
105is used to connect the object.
106</p>
107
108<p class="return">
109In case of success, a new unconnected UDP object
110returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
111an error message.
112</p>
113
114<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
115
116<p class="name" id="socket.udp6">
117socket.<b>udp6()</b>
118</p>
119
120<p class="description">
121Creates and returns an unconnected IPv6 UDP object.
122Unconnected objects support the
123<a href="#sendto"><tt>sendto</tt></a>,
124<a href="#receive"><tt>receive</tt></a>,
125<a href="#receivefrom"><tt>receivefrom</tt></a>,
126<a href="#getoption"><tt>getoption</tt></a>,
127<a href="#getsockname"><tt>getsockname</tt></a>,
128<a href="#setoption"><tt>setoption</tt></a>,
129<a href="#settimeout"><tt>settimeout</tt></a>,
130<a href="#setpeername"><tt>setpeername</tt></a>,
131<a href="#setsockname"><tt>setsockname</tt></a>, and
132<a href="#close"><tt>close</tt></a>.
133The <a href="#setpeername"><tt>setpeername</tt></a>
134is used to connect the object.
135</p>
136
137<p class="return">
138In case of success, a new unconnected UDP object
139returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
140an error message.
141</p>
142
143<p class=note>
144Note: The TCP object returned will have the option
145"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
146</p>
147
148<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 42<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
149 43
150<p class="name" id="close"> 44<p class="name" id="close">
@@ -168,6 +62,40 @@ Garbage-collected objects are automatically closed before
168destruction, though. 62destruction, though.
169</p> 63</p>
170 64
65<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
66
67<p class="name" id="getoption">
68connected:<b>getoption()</b><br>
69unconnected:<b>getoption()</b>
70</p>
71
72<p class="description">
73Gets an option value from the UDP object.
74See <a href="#setoption"><tt>setoption</tt></a> for
75description of the option names and values.
76</p>
77
78<p class="parameters"><tt>Option</tt> is a string with the option name.
79<ul>
80<li> '<tt>dontroute</tt>'</li>
81<li> '<tt>broadcast</tt>'</li>
82<li> '<tt>reuseaddr</tt>'</li>
83<li> '<tt>reuseport</tt>'</li>
84<li> '<tt>ip-multicast-loop</tt>'</li>
85<li> '<tt>ipv6-v6only</tt>'</li>
86<li> '<tt>ip-multicast-if</tt>'</li>
87<li> '<tt>ip-multicast-ttl</tt>'</li>
88<li> '<tt>ip-add-membership</tt>'</li>
89<li> '<tt>ip-drop-membership</tt>'</li>
90</ul>
91</p>
92
93<p class="return">
94The method returns the option <tt>value</tt> in case of
95success, or
96<b><tt>nil</tt></b> followed by an error message otherwise.
97</p>
98
171<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 99<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
172 100
173<p class="name" id="getpeername"> 101<p class="name" id="getpeername">
@@ -180,7 +108,7 @@ associated with a connected UDP object.
180</p> 108</p>
181 109
182 110
183<p class=return> 111<p class="return">
184Returns a string with the IP address of the peer, the 112Returns a string with the IP address of the peer, the
185port number that peer is using for the connection, 113port number that peer is using for the connection,
186and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 114and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@@ -203,7 +131,7 @@ Returns the local address information associated to the object.
203</p> 131</p>
204 132
205 133
206<p class=return> 134<p class="return">
207The method returns a string with local IP address, a number with 135The method returns a string with local IP address, a number with
208the local port, 136the local port,
209and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 137and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@@ -218,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the
218wild-card address). 146wild-card address).
219</p> 147</p>
220 148
149<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
150
151<p class="name" id="gettimeout">
152connected:<b>settimeout(</b>value<b>)</b><br>
153unconnected:<b>settimeout(</b>value<b>)</b>
154</p>
155
156<p class="description">
157Returns the current timeout value.
158</p>
159
160
221<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 161<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
222 162
223<p class="name" id="receive"> 163<p class="name" id="receive">
@@ -238,9 +178,12 @@ specifies the maximum size of the datagram to be retrieved. If
238there are more than <tt>size</tt> bytes available in the datagram, 178there are more than <tt>size</tt> bytes available in the datagram,
239the excess bytes are discarded. If there are less then 179the excess bytes are discarded. If there are less then
240<tt>size</tt> bytes available in the current datagram, the 180<tt>size</tt> bytes available in the current datagram, the
241available bytes are returned. If <tt>size</tt> is omitted, the 181available bytes are returned.
242maximum datagram size is used (which is currently limited by the 182If <tt>size</tt> is omitted, the
243implementation to 8192 bytes). 183compile-time constant <a href="socket.html#datagramsize">
184<tt>socket._DATAGRAMSIZE</tt></a> is used
185(it defaults to 8192 bytes). Larger sizes will cause a
186temporary buffer to be allocated for the operation.
244</p> 187</p>
245 188
246<p class="return"> 189<p class="return">
@@ -262,40 +205,6 @@ address and port as extra return values (and is therefore slightly less
262efficient). 205efficient).
263</p> 206</p>
264 207
265<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
266
267<p class="name" id="getoption">
268connected:<b>getoption()</b><br>
269unconnected:<b>getoption()</b>
270</p>
271
272<p class="description">
273Gets an option value from the UDP object.
274See <a href=#setoption><tt>setoption</tt></a> for
275description of the option names and values.
276</p>
277
278<p class="parameters"><tt>Option</tt> is a string with the option name.
279<ul>
280<li> '<tt>dontroute</tt>'
281<li> '<tt>broadcast</tt>'
282<li> '<tt>reuseaddr</tt>'
283<li> '<tt>reuseport</tt>'
284<li> '<tt>ip-multicast-loop</tt>'
285<li> '<tt>ipv6-v6only</tt>'
286<li> '<tt>ip-multicast-if</tt>'
287<li> '<tt>ip-multicast-ttl</tt>'
288<li> '<tt>ip-add-membership</tt>'
289<li> '<tt>ip-drop-membership</tt>'
290</ul>
291</p>
292
293<p class=return>
294The method returns the option <tt>value</tt> in case of
295success, or
296<b><tt>nil</tt></b> followed by an error message otherwise.
297</p>
298
299<!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 208<!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
300 209
301<p class="name" id="send"> 210<p class="name" id="send">
@@ -359,6 +268,75 @@ refuses to send a message to the specified address (i.e. no
359interface accepts the address). 268interface accepts the address).
360</p> 269</p>
361 270
271<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
272
273<p class="name" id="setoption">
274connected:<b>setoption(</b>option [, value]<b>)</b><br>
275unconnected:<b>setoption(</b>option [, value]<b>)</b>
276</p>
277
278<p class="description">
279Sets options for the UDP object. Options are
280only needed by low-level or time-critical applications. You should
281only modify an option if you are sure you need it.</p>
282<p class="parameters"><tt>Option</tt> is a string with the option
283name, and <tt>value</tt> depends on the option being set:
284</p>
285
286<ul>
287<li> '<tt>dontroute</tt>': Indicates that outgoing
288messages should bypass the standard routing facilities.
289Receives a boolean value;</li>
290<li> '<tt>broadcast</tt>': Requests permission to send
291broadcast datagrams on the socket.
292Receives a boolean value;</li>
293<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
294validating addresses supplied in a <tt>bind()</tt> call
295should allow reuse of local addresses.
296Receives a boolean value;</li>
297<li> '<tt>reuseport</tt>': Allows completely duplicate
298bindings by multiple processes if they all set
299'<tt>reuseport</tt>' before binding the port.
300Receives a boolean value;</li>
301<li> '<tt>ip-multicast-loop</tt>':
302Specifies whether or not a copy of an outgoing multicast
303datagram is delivered to the sending host as long as it is a
304member of the multicast group.
305Receives a boolean value;</li>
306<li> '<tt>ipv6-v6only</tt>':
307Specifies whether to restrict <tt>inet6</tt> sockets to
308sending and receiving only IPv6 packets.
309Receive a boolean value;</li>
310<li> '<tt>ip-multicast-if</tt>':
311Sets the interface over which outgoing multicast datagrams
312are sent.
313Receives an IP address;</li>
314<li> '<tt>ip-multicast-ttl</tt>':
315Sets the Time To Live in the IP header for outgoing
316multicast datagrams.
317Receives a number;</li>
318<li> '<tt>ip-add-membership</tt>':
319Joins the multicast group specified.
320Receives a table with fields
321<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
322IP address;</li>
323<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
324group specified.
325Receives a table with fields
326<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
327IP address.</li>
328</ul>
329
330<p class="return">
331The method returns 1 in case of success, or
332<b><tt>nil</tt></b> followed by an error message otherwise.
333</p>
334
335<p class="note">
336Note: The descriptions above come from the man pages.
337</p>
338
339
362<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 340<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
363 341
364<p class="name" id="setpeername"> 342<p class="name" id="setpeername">
@@ -403,11 +381,11 @@ is recommended when the same peer is used for several transmissions
403and can result in up to 30% performance gains. 381and can result in up to 30% performance gains.
404</p> 382</p>
405 383
406<p class=note> 384<p class="note">
407Note: Starting with LuaSocket 3.0, the host name resolution 385Note: Starting with LuaSocket 3.0, the host name resolution
408depends on whether the socket was created by <a 386depends on whether the socket was created by <a
409href=#socket.udp><tt>socket.udp</tt></a> or <a 387href="#socket.udp"><tt>socket.udp</tt></a> or <a
410href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from 388href="#socket.udp6"><tt>socket.udp6</tt></a>. Addresses from
411the appropriate family are tried in succession until the 389the appropriate family are tried in succession until the
412first success or until the last failure. 390first success or until the last failure.
413</p> 391</p>
@@ -445,74 +423,6 @@ system or explicitly by <tt>setsockname</tt>, it cannot be
445changed. 423changed.
446</p> 424</p>
447 425
448<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
449
450<p class="name" id="setoption">
451connected:<b>setoption(</b>option [, value]<b>)</b><br>
452unconnected:<b>setoption(</b>option [, value]<b>)</b>
453</p>
454
455<p class="description">
456Sets options for the UDP object. Options are
457only needed by low-level or time-critical applications. You should
458only modify an option if you are sure you need it.</p>
459<p class="parameters"><tt>Option</tt> is a string with the option
460name, and <tt>value</tt> depends on the option being set:
461</p>
462
463<ul>
464<li> '<tt>dontroute</tt>': Indicates that outgoing
465messages should bypass the standard routing facilities.
466Receives a boolean value;
467<li> '<tt>broadcast</tt>': Requests permission to send
468broadcast datagrams on the socket.
469Receives a boolean value;
470<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
471validating addresses supplied in a <tt>bind()</tt> call
472should allow reuse of local addresses.
473Receives a boolean value;
474<li> '<tt>reuseport</tt>': Allows completely duplicate
475bindings by multiple processes if they all set
476'<tt>reuseport</tt>' before binding the port.
477Receives a boolean value;
478<li> '<tt>ip-multicast-loop</tt>':
479Specifies whether or not a copy of an outgoing multicast
480datagram is delivered to the sending host as long as it is a
481member of the multicast group.
482Receives a boolean value;
483<li> '<tt>ipv6-v6only</tt>':
484Specifies whether to restrict <tt>inet6</tt> sockets to
485sending and receiving only IPv6 packets.
486Receive a boolean value;
487<li> '<tt>ip-multicast-if</tt>':
488Sets the interface over which outgoing multicast datagrams
489are sent.
490Receives an IP address;
491<li> '<tt>ip-multicast-ttl</tt>':
492Sets the Time To Live in the IP header for outgoing
493multicast datagrams.
494Receives a number;
495<li> '<tt>ip-add-membership</tt>':
496Joins the multicast group specified.
497Receives a table with fields
498<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
499IP address;
500<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
501group specified.
502Receives a table with fields
503<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
504IP address.
505</ul>
506
507<p class="return">
508The method returns 1 in case of success, or
509<b><tt>nil</tt></b> followed by an error message otherwise.
510</p>
511
512<p class=note>
513Note: The descriptions above come from the man pages.
514</p>
515
516<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 426<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
517 427
518<p class="name" id="settimeout"> 428<p class="name" id="settimeout">
@@ -553,12 +463,120 @@ all other method names already contained verbs making their
553imperative nature obvious. 463imperative nature obvious.
554</p> 464</p>
555 465
466<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
467
468<p class="name" id="socket.udp">
469socket.<b>udp()</b>
470</p>
471
472<p class="description">
473Creates and returns an unconnected UDP object.
474Unconnected objects support the
475<a href="#sendto"><tt>sendto</tt></a>,
476<a href="#receive"><tt>receive</tt></a>,
477<a href="#receivefrom"><tt>receivefrom</tt></a>,
478<a href="#getoption"><tt>getoption</tt></a>,
479<a href="#getsockname"><tt>getsockname</tt></a>,
480<a href="#setoption"><tt>setoption</tt></a>,
481<a href="#settimeout"><tt>settimeout</tt></a>,
482<a href="#setpeername"><tt>setpeername</tt></a>,
483<a href="#setsockname"><tt>setsockname</tt></a>, and
484<a href="#close"><tt>close</tt></a>.
485The <a href="#setpeername"><tt>setpeername</tt></a>
486is used to connect the object.
487</p>
488
489<p class="return">
490In case of success, a new unconnected UDP object
491returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
492an error message.
493</p>
494
495<p class="note">
496Note: The choice between IPv4 and IPv6 happens during a call to
497<a href="#sendto"><tt>sendto</tt></a>, <a
498href="#setpeername"><tt>setpeername</tt></a>, or <a
499href="#setsockname"><tt>sockname</tt></a>, depending on the address
500family obtained from the resolver.
501</p>
502
503<p class="note">
504Note: Before the choice between IPv4 and IPv6 happens,
505the internal socket object is invalid and therefore <a
506href="#setoption"><tt>setoption</tt></a> will fail.
507</p>
508
509<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
510
511<p class="name" id="socket.udp4">
512socket.<b>udp4()</b>
513</p>
514
515<p class="description">
516Creates and returns an unconnected IPv4 UDP object.
517Unconnected objects support the
518<a href="#sendto"><tt>sendto</tt></a>,
519<a href="#receive"><tt>receive</tt></a>,
520<a href="#receivefrom"><tt>receivefrom</tt></a>,
521<a href="#getoption"><tt>getoption</tt></a>,
522<a href="#getsockname"><tt>getsockname</tt></a>,
523<a href="#setoption"><tt>setoption</tt></a>,
524<a href="#settimeout"><tt>settimeout</tt></a>,
525<a href="#setpeername"><tt>setpeername</tt></a>,
526<a href="#setsockname"><tt>setsockname</tt></a>, and
527<a href="#close"><tt>close</tt></a>.
528The <a href="#setpeername"><tt>setpeername</tt></a>
529is used to connect the object.
530</p>
531
532<p class="return">
533In case of success, a new unconnected UDP object
534returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
535an error message.
536</p>
537
538<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
539
540<p class="name" id="socket.udp6">
541socket.<b>udp6()</b>
542</p>
543
544<p class="description">
545Creates and returns an unconnected IPv6 UDP object.
546Unconnected objects support the
547<a href="#sendto"><tt>sendto</tt></a>,
548<a href="#receive"><tt>receive</tt></a>,
549<a href="#receivefrom"><tt>receivefrom</tt></a>,
550<a href="#getoption"><tt>getoption</tt></a>,
551<a href="#getsockname"><tt>getsockname</tt></a>,
552<a href="#setoption"><tt>setoption</tt></a>,
553<a href="#settimeout"><tt>settimeout</tt></a>,
554<a href="#setpeername"><tt>setpeername</tt></a>,
555<a href="#setsockname"><tt>setsockname</tt></a>, and
556<a href="#close"><tt>close</tt></a>.
557The <a href="#setpeername"><tt>setpeername</tt></a>
558is used to connect the object.
559</p>
560
561<p class="return">
562In case of success, a new unconnected UDP object
563returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
564an error message.
565</p>
566
567<p class="note">
568Note: The TCP object returned will have the option
569"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
570</p>
571
572
573
556<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 574<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
557 575
558<div class=footer> 576<div class="footer">
559<hr> 577<hr>
560<center> 578<center>
561<p class=bar> 579<p class="bar">
562<a href="index.html">home</a> &middot; 580<a href="index.html">home</a> &middot;
563<a href="index.html#download">download</a> &middot; 581<a href="index.html#download">download</a> &middot;
564<a href="installation.html">installation</a> &middot; 582<a href="installation.html">installation</a> &middot;
diff --git a/doc/url.html b/docs/url.html
index 6ff673d..6ff673d 100644
--- a/doc/url.html
+++ b/docs/url.html
diff --git a/etc/README b/etc/README
deleted file mode 100644
index cfd3e37..0000000
--- a/etc/README
+++ /dev/null
@@ -1,89 +0,0 @@
1This directory contains code that is more useful than the
2samples. This code *is* supported.
3
4 tftp.lua -- Trivial FTP client
5
6This module implements file retrieval by the TFTP protocol.
7Its main use was to test the UDP code, but since someone
8found it usefull, I turned it into a module that is almost
9official (no uploads, yet).
10
11 dict.lua -- Dict client
12
13The dict.lua module started with a cool simple client
14for the DICT protocol, written by Luiz Henrique Figueiredo.
15This new version has been converted into a library, similar
16to the HTTP and FTP libraries, that can be used from within
17any luasocket application. Take a look on the source code
18and you will be able to figure out how to use it.
19
20 lp.lua -- LPD client library
21
22The lp.lua module implements the client part of the Line
23Printer Daemon protocol, used to print files on Unix
24machines. It is courtesy of David Burgess! See the source
25code and the lpr.lua in the examples directory.
26
27 b64.lua
28 qp.lua
29 eol.lua
30
31These are tiny programs that perform Base64,
32Quoted-Printable and end-of-line marker conversions.
33
34 get.lua -- file retriever
35
36This little program is a client that uses the FTP and
37HTTP code to implement a command line file graber. Just
38run
39
40 lua get.lua <remote-file> [<local-file>]
41
42to download a remote file (either ftp:// or http://) to
43the specified local file. The program also prints the
44download throughput, elapsed time, bytes already downloaded
45etc during download.
46
47 check-memory.lua -- checks memory consumption
48
49This is just to see how much memory each module uses.
50
51 dispatch.lua -- coroutine based dispatcher
52
53This is a first try at a coroutine based non-blocking
54dispatcher for LuaSocket. Take a look at 'check-links.lua'
55and at 'forward.lua' to see how to use it.
56
57 check-links.lua -- HTML link checker program
58
59This little program scans a HTML file and checks for broken
60links. It is similar to check-links.pl by Jamie Zawinski,
61but uses all facilities of the LuaSocket library and the Lua
62language. It has not been thoroughly tested, but it should
63work. Just run
64
65 lua check-links.lua [-n] {<url>} > output
66
67and open the result to see a list of broken links. Make sure
68you check the '-n' switch. It runs in non-blocking mode,
69using coroutines, and is MUCH faster!
70
71 forward.lua -- coroutine based forward server
72
73This is a forward server that can accept several connections
74and transfers simultaneously using non-blocking I/O and the
75coroutine-based dispatcher. You can run, for example
76
77 lua forward.lua 8080:proxy.com:3128
78
79to redirect all local conections to port 8080 to the host
80'proxy.com' at port 3128.
81
82 unix.c and unix.h
83
84This is an implementation of Unix local domain sockets and
85demonstrates how to extend LuaSocket with a new type of
86transport. It has been tested on Linux and on Mac OS X.
87
88Good luck,
89Diego.
diff --git a/gem/ex1.lua b/gem/ex1.lua
deleted file mode 100644
index 327a542..0000000
--- a/gem/ex1.lua
+++ /dev/null
@@ -1,4 +0,0 @@
1local CRLF = "\013\010"
2local input = source.chain(source.file(io.stdin), normalize(CRLF))
3local output = sink.file(io.stdout)
4pump.all(input, output)
diff --git a/gem/ex10.lua b/gem/ex10.lua
deleted file mode 100644
index 2b1b98f..0000000
--- a/gem/ex10.lua
+++ /dev/null
@@ -1,17 +0,0 @@
1function pump.step(src, snk)
2 local chunk, src_err = src()
3 local ret, snk_err = snk(chunk, src_err)
4 if chunk and ret then return 1
5 else return nil, src_err or snk_err end
6end
7
8function pump.all(src, snk, step)
9 step = step or pump.step
10 while true do
11 local ret, err = step(src, snk)
12 if not ret then
13 if err then return nil, err
14 else return 1 end
15 end
16 end
17end
diff --git a/gem/ex11.lua b/gem/ex11.lua
deleted file mode 100644
index 1cbf01f..0000000
--- a/gem/ex11.lua
+++ /dev/null
@@ -1,7 +0,0 @@
1local input = source.chain(
2 source.file(io.open("input.bin", "rb")),
3 encode("base64"))
4local output = sink.chain(
5 wrap(76),
6 sink.file(io.open("output.b64", "w")))
7pump.all(input, output)
diff --git a/gem/ex12.lua b/gem/ex12.lua
deleted file mode 100644
index de17d76..0000000
--- a/gem/ex12.lua
+++ /dev/null
@@ -1,34 +0,0 @@
1local smtp = require"socket.smtp"
2local mime = require"mime"
3local ltn12 = require"ltn12"
4
5CRLF = "\013\010"
6
7local message = smtp.message{
8 headers = {
9 from = "Sicrano <sicrano@example.com>",
10 to = "Fulano <fulano@example.com>",
11 subject = "A message with an attachment"},
12 body = {
13 preamble = "Hope you can see the attachment" .. CRLF,
14 [1] = {
15 body = "Here is our logo" .. CRLF},
16 [2] = {
17 headers = {
18 ["content-type"] = 'image/png; name="luasocket.png"',
19 ["content-disposition"] =
20 'attachment; filename="luasocket.png"',
21 ["content-description"] = 'LuaSocket logo',
22 ["content-transfer-encoding"] = "BASE64"},
23 body = ltn12.source.chain(
24 ltn12.source.file(io.open("luasocket.png", "rb")),
25 ltn12.filter.chain(
26 mime.encode("base64"),
27 mime.wrap()))}}}
28
29assert(smtp.send{
30 rcpt = "<diego@cs.princeton.edu>",
31 from = "<diego@cs.princeton.edu>",
32 server = "localhost",
33 port = 2525,
34 source = message})
diff --git a/gem/ex2.lua b/gem/ex2.lua
deleted file mode 100644
index 94bde66..0000000
--- a/gem/ex2.lua
+++ /dev/null
@@ -1,11 +0,0 @@
1function filter.cycle(lowlevel, context, extra)
2 return function(chunk)
3 local ret
4 ret, context = lowlevel(context, chunk, extra)
5 return ret
6 end
7end
8
9function normalize(marker)
10 return filter.cycle(eol, 0, marker)
11end
diff --git a/gem/ex3.lua b/gem/ex3.lua
deleted file mode 100644
index a43fefa..0000000
--- a/gem/ex3.lua
+++ /dev/null
@@ -1,15 +0,0 @@
1local function chainpair(f1, f2)
2 return function(chunk)
3 local ret = f2(f1(chunk))
4 if chunk then return ret
5 else return (ret or "") .. (f2() or "") end
6 end
7end
8
9function filter.chain(...)
10 local f = select(1, ...)
11 for i = 2, select('#', ...) do
12 f = chainpair(f, select(i, ...))
13 end
14 return f
15end
diff --git a/gem/ex4.lua b/gem/ex4.lua
deleted file mode 100644
index c670e0e..0000000
--- a/gem/ex4.lua
+++ /dev/null
@@ -1,5 +0,0 @@
1local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
2 wrap("quoted-printable"))
3local input = source.chain(source.file(io.stdin), qp)
4local output = sink.file(io.stdout)
5pump.all(input, output)
diff --git a/gem/ex5.lua b/gem/ex5.lua
deleted file mode 100644
index 196b30a..0000000
--- a/gem/ex5.lua
+++ /dev/null
@@ -1,15 +0,0 @@
1function source.empty(err)
2 return function()
3 return nil, err
4 end
5end
6
7function source.file(handle, io_err)
8 if handle then
9 return function()
10 local chunk = handle:read(20)
11 if not chunk then handle:close() end
12 return chunk
13 end
14 else return source.empty(io_err or "unable to open file") end
15end
diff --git a/gem/ex6.lua b/gem/ex6.lua
deleted file mode 100644
index a3fdca0..0000000
--- a/gem/ex6.lua
+++ /dev/null
@@ -1,14 +0,0 @@
1function source.chain(src, f)
2 return function()
3 if not src then
4 return nil
5 end
6 local chunk, err = src()
7 if not chunk then
8 src = nil
9 return f(nil)
10 else
11 return f(chunk)
12 end
13 end
14end
diff --git a/gem/ex7.lua b/gem/ex7.lua
deleted file mode 100644
index c766988..0000000
--- a/gem/ex7.lua
+++ /dev/null
@@ -1,16 +0,0 @@
1function sink.table(t)
2 t = t or {}
3 local f = function(chunk, err)
4 if chunk then table.insert(t, chunk) end
5 return 1
6 end
7 return f, t
8end
9
10local function null()
11 return 1
12end
13
14function sink.null()
15 return null
16end
diff --git a/gem/ex8.lua b/gem/ex8.lua
deleted file mode 100644
index 81e288c..0000000
--- a/gem/ex8.lua
+++ /dev/null
@@ -1,5 +0,0 @@
1local input = source.file(io.stdin)
2local output, t = sink.table()
3output = sink.chain(normalize(CRLF), output)
4pump.all(input, output)
5io.write(table.concat(t))
diff --git a/gem/ex9.lua b/gem/ex9.lua
deleted file mode 100644
index b857698..0000000
--- a/gem/ex9.lua
+++ /dev/null
@@ -1,3 +0,0 @@
1for chunk in source.file(io.stdin) do
2 io.write(chunk)
3end
diff --git a/gem/gem.c b/gem/gem.c
deleted file mode 100644
index 976f74d..0000000
--- a/gem/gem.c
+++ /dev/null
@@ -1,54 +0,0 @@
1#include "lua.h"
2#include "lauxlib.h"
3
4#define CR '\xD'
5#define LF '\xA'
6#define CRLF "\xD\xA"
7
8#define candidate(c) (c == CR || c == LF)
9static int pushchar(int c, int last, const char *marker,
10 luaL_Buffer *buffer) {
11 if (candidate(c)) {
12 if (candidate(last)) {
13 if (c == last)
14 luaL_addstring(buffer, marker);
15 return 0;
16 } else {
17 luaL_addstring(buffer, marker);
18 return c;
19 }
20 } else {
21 luaL_putchar(buffer, c);
22 return 0;
23 }
24}
25
26static int eol(lua_State *L) {
27 int context = luaL_checkint(L, 1);
28 size_t isize = 0;
29 const char *input = luaL_optlstring(L, 2, NULL, &isize);
30 const char *last = input + isize;
31 const char *marker = luaL_optstring(L, 3, CRLF);
32 luaL_Buffer buffer;
33 luaL_buffinit(L, &buffer);
34 if (!input) {
35 lua_pushnil(L);
36 lua_pushnumber(L, 0);
37 return 2;
38 }
39 while (input < last)
40 context = pushchar(*input++, context, marker, &buffer);
41 luaL_pushresult(&buffer);
42 lua_pushnumber(L, context);
43 return 2;
44}
45
46static luaL_reg func[] = {
47 { "eol", eol },
48 { NULL, NULL }
49};
50
51int luaopen_gem(lua_State *L) {
52 luaL_openlib(L, "gem", func, 0);
53 return 0;
54}
diff --git a/gem/gt.b64 b/gem/gt.b64
deleted file mode 100644
index a74c0b3..0000000
--- a/gem/gt.b64
+++ /dev/null
@@ -1,206 +0,0 @@
1iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAtU0lEQVR42u19eXRURdb4rarXa5LO
2RshKEshC2MLOBIjsCoMLGJhRPnUEcUGZEX7j4Iw6zqd+zjkzzowL6gzKMOoBRHAAPyQKUZQlxLAk
3EIEkQkhCyEoISegs3f1eVf3+qPTj0Z3udEJImN/Pe/rkdF6/V6/q3qp7b92tEOccfoT+A9zfHfj/
4HX4kQD/DjwToZ/iRAP0MPxKgn+FHAvQz/EiAfgapvzvQQ3DfviCE+rtTPYH/AAKouEYIcc4ForUX
5tXeKexhj6k8IIe2DvdUl0SYAcN7RGYQ63oAQ4hx8fBu6BXfC6vBcsHyDeNRi7cYboZQjBIRgl/lB
6KQcAQnyl+q1IAC9YU7/s2bOnsrKSUupwOHQ63cMPP2wymRhjGOOrV6/m5ORYLJbg4OABAwZYLBaD
7waBtQUsD34mqRT0hHc/abEpNjbWlxYEQCgw0RET463QEABjjjHFfyND/LEg737XsQpblhoaGioqK
8CxcunD9/fv78+ampqepgZFk2mUwBAQEYY6PRSAhRG7Tb7cXFxXa73W63W63Wn/zkJ4sXL1YfVHGB
9EFI5VZc0EDcwxjnnkoRbWhw7dxZt316Yn19TW9siyxQADAZddHRAWlrMffeNnDcvUa8nlDKEAGNv
107ffbClCnoYoFFRFiIufn53/88cfBwcERERERERHjxo2LjIz0ZbaqFLXb7ZcuXZIkKSoqShAYY7xn
11z576+vpJkybFxcUZjUZfOJKKfQBACP75z/yXXtpfXX0JAAFIAAQAAXAADsAAZAA0dGjMa6/Nueee
12FEoZQsgLDfqTAFqWIstyRUVFXFycJEniJ6vV2tTUFBUVRQhxkb0q2TTS7xr9tNxG/bdjtAjl5eXl
135ubW1dUhhJKTkzMyMkwmk0p4AMAYq91Tv1DKCMENDW0PPLBj797vEdJjrAfgjF2HP+d8B8YcAMry
145VP//vf5Oh3h3OM66P8V0NTU9N133+Xl5SmKsnr16qCgIBc8MsbE5HXXgjqdU9oRie8YY5c2W1tb
15CwsLS0tLFy5cqEoILWnFI84rHGNUXW29/fYPCwsvSpI/pQLxntYNxxhjDIpinTNn1K5d/2Uy6Zwd
16cNWO+o4A7mjFGOfk5OzcuTMsLGzixInjxo2zWCwqIlSpAL2k47tMc+18FN8vXLgAAHFxce4Cqa1N
17njlzw9GjZZLkryiK6KP3twEgnY7I8tWf/WzCtm33McZVJVV7H3nppZf6BvXaL+rAFEVJSEhYvHjx
184MGDDQaDykxAw1h6S38XLxUcRnRGnXyiM4cOHdqyZUtDQ0N0dLSfn5/4SUz/Z57Zs3PnCZ0uQFEU
19ANQV9jvIwxiTJOPp0xdCQgLS0gZRyjF2Hc5NXwEu866lpUWv1+v1enVBqFsnwWS0dLrZ4K7dlpSU
20ZGZmVlVVpaen33PPPYL1HzlSOXnyewCk+6gSo2OhocaCgl9GR1vEOtCO7qbbglQsY4yPHj366quv
21nj59GjScWtBGq0f2mVHBZbVxzhMSElatWvXzn//cORUAANau/Y5zB8YYoLsUQJxzQqSGhqb1648D
22gFClXO+4eSNUZ9alS5e2b99eXl4+d+7cqVOnCrl361hvOt2LCNWlttY6bNjbTU22Hk9WhBDnjhEj
23IgoKVoqdc1+vAFmW//WvfymK8uyzz86aNUvlP72HPrjBWaR2RkgIoXeJ2ZqbW9nUdBVj0uPGOecA
24ujNn6s+cuQRui6CXd8JaJUedSsJUEBoaqtfrtdd9p4HQ3rTGL9UE1ik2BZ/trmnMRePinAFAQUEt
25AMMYuXMP34EQRKnjzJlLqakRLr3uTQJoJarLzigyMpIxJiStVr/0pTXOQdgAMEaEYACOEPb+tKCU
26UOEVhYq9qKCKTwYyzW0XL169cUaNEAJglZVXwc2Q3msE0GKfEFJYWGg2m+Pj41UtyMeJr8W7olCB
27dFVS2mxKZeXVqqqrFRXN9fVtDQ1tbW2yw0EBQK8nJpNuwABTWJjfoEGB0dEBMTEWk0mHEBYPU8oY
28Y04S+roEbTalt1Bkt1P3i728AjjnhJCjR49u3rw5IyNDEACcvBW8ajgqRhSFCUsvQhghVF/fmptb
29efjwxWPHqs6da6iutlLqAFA86yQIQCJEHxkZkJQUMnFi9JQpg9LSYsLD/THusCtw3mHR7JIMfn66
303sKP2dxJU70sAzDGBw4c2Llz5/333z958mRVqfD+lBb1GCNhxa2oaP788x8++6z4yJFKq9UKQAGI
31+CCkw1jvqVkhPylllZVXKivrv/22EID4+wdMmhS9YEHKggVD4+KCxAqjlHkig9DfASA+PkismO7r
32oNeAMQ6A4+ODwG0K9o4aqtoajx07tnnz5mXLlo0ePVplO12iXhjZMUYYI1mme/aUrF+f/9VXJTZb
33CwAG0GFMhDHLxfjlHQTTF/KTMQogAzCDwW/27ITHHhs/f36SXk+8GO4VhUkSzsoqmTv3XxgbbkQI
34A3BJQmfO/DI5eYAQhL1JAK0l68qVK1euXElMTOyS6av6EqViI4bb2+WNGwveeCO3uLgSAAAMhBCA
35Dh/TjQMhCABRSgHsAJCUFL16ddrDD4/289OrfQDNahBGiKYm2/Dha2tqrAj1YCcMAIAxYsw+aVLs
36kSMr3G2IN7QPcOqFXJ3IISEhCQkJvmBfaIeKIqQifPDBiREj3n3iiW3FxTUYmwgxCWT1FvYBgFJO
37KQVAhJgwNp07V7ty5afDh7+7fn0e50AIVhTGmNZiCIrCgoKMixYNB7D3aCcMTvalPPjgGNEHl597
38vgI8Gd8FL/JkLnaf+IcPV6xatScv7zxCEsYGdQd0k6HDvs2Yg3PH6NFD3npr3vTp8Wqv1D0Hxqik
395MrYse+0tFCn48X3LSTHGDMmJySEnDjxy4AAfa+tAK1yWVpampubqxJDMLhOub9W2BKC29uVX/7y
40i/T09/LyygjxQ0hPKe0T7AMAYoxTShGSCPEvKKiYMWP9E0/sbm11iKXgHAIoCktMDHnxxVkAbTpd
41t9DFnahW/vSneQEBHYzOBS09IYA62THGra2tmzZtOnfunO9PCeF25Ejl+PHr3n13PyE6jI1O1Pex
42dQgxBpRSjA2E6N9//+DYseuysyskCVPKBTsiBDHGn302ffHiCbJs1ekkJ3K7GC5CSKfDlFrXrJm1
43ePFwShnGnYyuJwTQ+vk2bdrk5+e3ZMkS9Scv2GeMU8p1OvLOO0enTn3v7Nk6QvwpFQbRfjTMIcYY
44pZwQ/9LS+mnT3n/99e8kCQtmKNYB53zTpkV33jlGlpslSWzIPZFBhKUQjLksW596auZrr92hYt8d
45Pz1cAQKhmZmZpaWlS5culSRJsKNOJYrWqY0xeuKJz3/1q38DYIz1lIrNYT9gHyFXAxGlFGM9xtIz
46z+xctuwzYUESXnXOQacj//u/S3796zsUxU6pDSGQJEKIsHB0fAhBkkQQ4pS2Ygyvv77o3XfvFNjv
47zagIVZLs27cvMDBwwoQJqpHHE98Xno3WVvlnP9v65ZcFkhSgKKybAu0GgQMgse2iVIQviIFjjDHG
48YnvccZskYUWxzp49cseO+y0Wg+i82DFIEj58uOL55/cdPFgKYHfuDcUoGAAFYISY77572B//OGv4
498DBFYd6jg3pIAE8hCF6w39xsu+uuTdnZZyXJv2+x34F6xhjndgAOoPfzM5nNEqXcarXLsg1AAdBh
50rIcOB5GgQcukSQlffPGL0FCTGIJgSmI65+VV79xZnJNzsby8UQ3MSkgImT49PiNjWHJyqBrC5d3u
511A0CuHstvOv7KufBGFmtjnnzPsrJKZEkP0WhfTnxnV1t0+mMs2YlLVyYMnFiVHS0xWzWUcqammzn
52zl359tuyf/+7sKSkGiEJIT1jFAAkiShK68SJg7OylgYFGcVAAECrqiKEZJm2tysIgdmsc14EWRY2
53FY/q+A0RQG3Re2yIerMsszvv3Pj114WS5N/n2McACufKz38+/uWXZ6SkDHDvs4rH7duLXnjh69LS
54GkLMlHIALmgwbVry3r0PGwwd4T3gNDcJkqiUUC8SgjEWPoyuba6+CmFtAMH+/ftra2s7COjVuim0
55iEcf/axfsI8x5twRGGjYufPhrVsXJyeHUsrEdlf7oZTLMiUE33//yFOnVj7yyBRK2wgBAKQoVJL8
56Dh78YenSHerqV13cOl2HhUr1DmGMdDpSX3/p22/3C1+3FnU3RAC1obNnz+7atau9vd1L007WzwnB
57r756YOPGI/0y9xmTo6IsBw8+vnBhiixT4dIRWNN+CEE6HRF7LoOBbNiw4JVX5lNqwxg5aeC/deux
58F1/cRwimVJV/AM79ppAK6opvb2/ftWtXSUlJl9iHbsUFiXds2rQpOTl52rRpnoydzoAfJkk4M/Ps
59Y4/twNjotIH0ndQFYP7+ur17l40ZEyHLVJKwpy26+q/Q7hWFzZw5uKVFyck5R4gwjQDGhgMHzqam
60Ro8YMVBs472YuYKDg69cuVJQUJCWlubi5nQHn1aAuu5OnDhRU1MzZ84c7/cLda2mpuWJJz4DQJx3
6114Ryo4AxAnC8+ead48dHORxUhIx7R4Rzb48IwYyx116bm56eRGm7sMFxDgDSU0/9b0VFsyRhL/YS
628Yrbb7+9trY2Ly9Pxd4NEUCFc+fOTZgwYeDAgWL6u9+g2kcB4Omnd1dVNRCi57wvN7rC/mWbNWvo
638uXjKWU6He5SErrQQAjb116bCyAJAwnnjBBdXV3jr36122WY7sAYCwsLGz9+vOBCXbzURy3Iydap
64oijafIfr7+kw4UoS3rLl1H/912ZCTJT2tZkBIcS5PTNz6fz5yaIzvicMqWillEsSzsjYsnNnASEm
65oRQRgilt+/DD+x9+eKyzZe6GhA7M2O12Qoga7O3pdb6yIPEXY+w1qodzziUJNzXZXnghC0ByKgJ9
66BxgD546UlIjbb08AAEKuCUwfQTu0hx4aDYDUKcoYB9D9/vdfX77c5oURiZWk1+tFYD14FcVdEECr
67fbq8wH36g9Ph8Ne/ZpeV1fU581HRp8ycOVinI6pVuQftCH1/6tTYoCALY1SIUs45IfrKyvo///mQ
68kx6uyHVHTqc49JUA2na1Ar2zUXHOQZJweXnTO+/kAhj7nvmoMG5c9I08rlpABw70T0oKBVCc4xV+
69JNM//nHk3LkGwdw6fVz7txc2YoyxrVu3lpaWImecs4fbOACsXftdc7OVEOlGwgh6DJwDAImNDdTi
70omcghhMTYwFg2glNCGltbX3jjRzoLNhWizSEUHl5+datW51G307AGwFU/amqqur48eOSJHm9EyQJ
71V1Vd/fDDEwCG/jLxc84BkNEoAXRD8HpoCgDAZNJdP5PEIjBs2lRQXt4kFoEXFi9J0vHjxysrK8GD
72PurTCvj+++9jYmJiY2O9CHQxFz766ERjYxMh0s1OO/AEIoDH4VBUDN4g2GyK20zihEhW69UPPsgD
73z4tACIOYmJiYmBgRkd8pdEEAsXssKioaOnQoeBAj4pokYYeDbtpUAKDrD+eiOmwAoCIKE3ywBHgd
74OwKAqqqrAC68XvBh/ebN37e3y5KEPWOGA0BycnJRURFowgOve0uX/bBarYqiCAJ4gI44hm++KS0q
75qkVI31/TX2AHAPLza26kCTU5oKGhraTkCgBxGRHngLHu/PlLWVkl0FmwiRaGDx8uy3JTU1Onv3at
76hgYEBKxevTo2NhY8y3TRvU8/PQ1ARZbnTcaytw4DSPv3lzHGvMxN39qB3NyLDQ3NGEvubYjYrU8/
77PeOpBRVXMTExq1evDgwM7PQ2bwRQce2Siu4OkoStVntW1vn+5T8AwBhHSHfqVPWBAxfAq5biCdSg
78MQDYvPl7pwrE3V8EoP/669LGxnZP+qgAQojJZPLkG/BIAHXiMK/bWTWO6tixqsrKKwjp+rv2hBgk
79FWqi6Ex3nU6UMknCBQW1//73GQADpZ1MKc4BY6murik3txKgI4PBS8ue3ANdywDkBPDo/AIA2Lev
80FEDpNPSlbwExxhEyff756W3bTksSVhSP4RpuA7mWmgAAzz2XJcs2LxGJgtL79p33gjoXBLpDFwRo
81bGwsLi7W1gXopAmMACAn56K7sOonEGUbpJUrPz93rkGnI7JMVX+Wx2ec2JdlJkn4j3888OWXZwgx
82ednQcM4ByHffXVSR4OEeYIz98MMPjY2N3SCAQHphYeG2bdu8+h0BY9TY2H7mzCUA7+o/BwBJwuKD
838Q1F3HsFYVWWLl+23nXXxoqKZkED1UnrptJ0/KsojFKu15O///3Y73+/F2NTp8zn+gelwsLLly61
84CiO2xw4htHXr1sLCQnBj6dhz0wAADQ0N4eHhXpawuF5aeqW+vsVrKnOHl0pRWsSHMYcz1vWm0IAx
85hrHh7NlLU6a8n51dIXwyAsXOND+uutFlmQonEsbouee+XrlyB8Z6sey9vINzQAg3NbWWlDQAeHMP
86IIQiIyMvXboE18cVgpcMGTHrm5qagoKCwHMqj2iqqOgygEyI5FkjRgA0JMT/oYemMMbNZik7u+Lw
874dKbKbQ7aFBV1Txjxvqnnpry/PO3RUT4u3gyEOpYxAihb74pW7MmKz+/lBATpeCLFw9jRKlcVHR5
88ypRY7wMJCQnpdCvQBQFqampGjRrllQAcAM6fvwLAvOTxYIwYYxER/m++OU+WqU5H/vzn7MOHfyDE
89IIzGN48GCOk452+/vf/DD/MXLhy+cGHK2LER4eH+BgNhjLe0OMrKmg4evLBly+mjR0sBgBA/Sn2N
90GxNDPn/+CnheAeK62WwWDjIXNHZBgGnTpkVFRUFX4ebl5U2+ONc45yIwRKcjvZh54R1FnDPOESF+
91Vqt948bcjRuP6HTmsDA/k0lijDc12RsbW0SQIcZGABBJHD5uZYTtr7y8CTy4SVS8DR8+XPASn1iQ
922sqUKVPUnAsPdwIA1Na2+DhfCMGS1FHWrk8IAKJjlFIATIiZc5BlWl3d6JzjCIBIkr8QBt0NHhDR
93QLW1LeDZ9C2iZuPi4uLj413Q65EAmjypTqrruOAUABobbW4Wq1sN1KhCBIAQujZwkSmlva27LTc2
942gDAwxS9LoPapRwXdOkPgK58GkL/bWlx9GuAfzeQ5RyaWu/gWnC5Om7fmxMsqLXVIaLYfbv/OvDG
95grR830vrjHFZ7gPvu8hX6ZhBIkyhM6q73MY830Mo5ZxTkQ/sXBmYENJVRTJXbMkyY4x7spZ5R6a3
96fUBLS8uWLVvq6+vBqzlFNQfdzG2wCM6hYg9BaZsT+7yz2xTnbe2aeobqDYKjUkVp4dxuNOojI4Ni
97YkIiIgJNJj3nsqK0cE67lRPp3RAkfrpy5cqWLVuam5tdEOUtU16W5ZMnT6alpYWFhXnxhWGMhOHX
98R5NLDwAhxLmSmDhw6dIxisIaG9vffvuou5EAIcS5nJoac999IxWFVVdffe+945p7OIDI226LjBzw
994INjfvrTxKSk0MBAA8ZI5AqUlFzZu/f8Bx/k1dZewdjkm2OVq3GPngiAEGptbT1x4oQIKtQi0xsB
100JEkym83ecSra0uvJTfUBYIwoVZKSQl54YRoAlJc3/f3vx9yttOK21NTw55+/DQAKCmrfe++YBoMI
101IWDM9sQT6X/961x/f9cAJ4vFEBUVMH16/G9/O3X58s+2by/A2OidBsJwrdcTX5Q6s9ks/Oq+pqmK
102ux0Oh1cCdHS9D5wwKsZFioTnLl2z7WgvY4w4t/2f/zNt3bq7jUZJWEnb2uTy8qZz5xpqaqxCkDoc
1031GIxbNt23223JTDmS342t1gMahKcJ7DZbACg07nW6/C2AvR6vUhE7Wq0KDTUBNC9ALQegLrKnUmK
104ncO11S1h7UXG5Li4ga+8MotzTgi6etX+4ovf7thRePlyG6XcYCCDBwc//fRPHntsvMNB9Xry7LO3
105HTpUKp72/C4AYCEhRuiq8Ep7eztCSK/Xd4MAGOPHHntM1PL0nH8KABAdbfEgFW8VEEabO+5I9Pc3
106tLXJZrPu/vs/3bPnBMZ+jImodKWwsOrxxz9ubZVXr04DgPHjowIC/K1WG0Letzg8OtqiosIdBOqS
107kpIef/xx99CeLvwB4eHhQgx42oWJ9e6s6dLfaO4KxoyJBACzWXfgQNmePWckKciZ44gAMCEGAOMn
108n5wUN1ssBn9/PYA3didsQaIOjXcsmUymiIgI9xsk762L8nVqRpj78+JKSkooAOmrKgM9AcY6nPWt
109rQ4AyM4uBxD7gA59X5hFAXBbm+K7QUIUAkpJGQDXMwltipxKg04R6G0jxjVlNzyB2AkPHTqAEEM/
110BoN2CZxzAN2nn5749NPjAICQjhADAEeoo2QQ54xzBaAlPn6okyRdj4UxBmBwEuAa6kGjC6hGuk43
111Yt6iDcUKsFqtfn5+nuISRVNxcUFxcUGlpZcRkm5VixAC4BgbCUGEYIdDobTdyV4wgC4gwBgVFTB9
112+k9efHG6ry0i4JzGxAQPHhwMzrmoTSRV+YdLQrX2YhcEqK+vX7du3YoVK8LDwz3xOEqZwSCNHRtR
113WlqLsa6v7Mw9Ac5BURRZtpnNAWPHJo0eHT506IDBg4NiYizh4f4DBpj1euKJV7iD2HaMGRMhSj6p
114GawIIVGhua2tbefOnQ888IBIquCaepLqsujCHxAYGMg5r62tDQ8PBw9iQEz5GTPit28/0d8Y9oZ8
115hDDnsr+/Yc2a2cuXj42OtrjkPAuk1NW1DhhgliRfeCkC4NOnx6tI4M6ikQcPHszOzo6MjLRarcXF
116xXFxcRaLRSS3MsbKysqioqLE8RHehDDn3Gg0hoWFlZeXjx492jOlOABMnz4Yof7MCegCVQhxLkdF
117WfbsWTpq1EBhvUEItbfLVVXWysqrZWWNZ8827N9fTik7cuQx8MG0RSkD0M+cORg6WLHgchgApkyZ
118Eh8fn5WVxRj7/PPPbTabxWKJiopKTEwMDAz8+OOPn3zySXEgiDcCCGIOGjSouLgYPAgl9YyUUaPC
119x42LyMu7eMP17W4UtPsvFUSm0IYN944aNdBmU4xG6fDhin/841hOzsXKyquybAdQMAbG6MiR8T7y
120H8Yco0ZFjh0bKf510gA45xaLJSgoqLq6OiIiYuTIkefPn7948eKFCxf279/f0NCQkpISGRkJLn6J
121zpArVMyU9vZ2tR5Kp3dSyiUJ3XNPSl5eGUJGgJu7DrwkmwLwyEg/l6uEIErtkycPmTcvyeGgRqP0
122t79995vf7EKIca5T62ASgh0Ouyj02hWIIgjyXXcNxRiJkihOSndwaUrpnDlzBMYSEhKGDBkixHJj
123Y6PZbAY199UL9gVPTEpKSk5O9u6cEZczMob/z/8cuHkZ8S6ntbj/DsABsJiSLmMBoGlpMQCg15Pq
124auvLL2cBSJKkUxQm3DLCNwDABUftCkSahnHx4hHunXGWLcCHDh3Ky8tDCA0aNGjq1KkiwCc0NFSV
12585zzLjxiWsekp4Q/5KzNOXJk+OzZgwEcvgQoIoQAsBqn5eXj3CJdA6NRMplc3B8dWbQDBwbOnDmk
12609GEh/uLb+XlV6xWGWNJRGupN0gSAXAMGxaqGbtHCzyAfcaM+HHjotQCNi5427VrV2ZmZnJycmJi
127Yk5OjsPhOHnypOpcUbUgn6xa2mM/PBn9Bd9/9NEJaje8E4BzGaBFUVrVUC1PH84V56JmAKAoLDzc
128f9y4CACbXt9R+EGSCCEYoPU3v7ltwACzqCbtAlZrh1k3IiJAr8ecc0lSH0eSRByOlvDw0Fdeud05
129duHkwm7hNuI7f/TR8eAWgC12r3V1dceOHVuxYsX8+fMTEhLi4uIGDRqUm5u7bds2uD5+ouvSxej6
1302kyeQDDBBQuGjRoVfepUDcZ6T6JYrI/x4wc98sjtAQEGr1l/YDJJu3efLS6uA5AqKpplmYrH//Sn
131eXPm1FitzSK0i3PKOaxcOXvNmnS1sI8WKQD4++9rAcDhoEOGhDz2WNq77+5jTM8YEtoj5zBpUuLG
132jfeKoiqEYEIwxgqAnXOjtmAlQpgxx9ChkYsWjQC38A6BpbKystDQUBEGcezYsYSEBAC4995733nn
133ncrKypiYGLXUQBcEUGNSDh482NzcfPfdd3dapAA5yyHqdHjVqsmPProNIYO7KBaF6MUsnjVryJw5
134CV62PMLxK0m4vr61uPiiJPn98EPd4cMVM2YMttuVSZOi8/OfWrs2Ny+vRlFYQkLwL34xZt68RADY
135uLHgrruSQ0PN6pZQxPLv23e+pKQhMTFUlunatT/9yU+it207U1fXoteThISQBQtS7rwzyWCQGhvb
136jUbJaEQGg/SrX6W/8UZua6ujudnmHAvHGFOqPP30ZOFUEDWxtKgAAD8/v6tXrzocDs55ZWXlrFmz
137AMBisRiNRhf/iq95wnq9/rvvvrNarWpghadF8NBDY1JTB1HaiStD6KyEYEKQpyqCngBjBMDWrNnb
1380uIwGCRZpoMHB61dOz87+5EjRx7bvHnRHXckAMBf/5rzyiv7goONoIlY5hwwJm1tbatXfymyORnj
139Dz00eteuJUeOPJ6dvfzDDxcuXJhiMEj5+TXp6RvKyhoRQna7smpVWlXVMw8/PAbARggSyg+l9pSU
140qGXLxrlMf62eMmzYMKPRuHXr1ry8vIEDB0ZHRwPA6dOnKaXiu08uSe1948aNy8rKOnny5G233ebJ
141LCoWgV5P/vCHmYsXb3KZzgCorU0+dOiC78YixlhgoLG2tgUAKwrD2HD8+IVZsz745z8XpqaGq3HO
142oj/Nze0vv3zgzTe/iY+PPHSowmzWnTp1SdsUxsbMzNNz5360bt09Q4YEO+cQF1HTly+3vv320ddf
143P9Ta2rxhw4m//W2uWoxAOFydwQ3AOX3xxZkmk+v0V3l1W1ub2Wx+5JFHNm7cKPhPTk5OTU1Nbm5u
144RkaGwWDQchGf4gkFF9q9e/fJkyefe+457dmCbljukEJ33bUxM/MMIWZnpJ/qrunBeQgEAKsBDYzZ
145JUmaPj1xxoy4uLggnY5cvtyan1+7e/cP9fUNGJsZY863IAA1XxyphVSMRuOcOUnp6bExMRaEUG2t
1469ejR6qysksbGKxibADBjjgULRt5zT4rJJFVVWf/1r/yiolqEJIQQY+1z5qR89dVS7cFsKkIF9r/4
1474osFCxbodDpZlk+dOnXq1Kn6+nqz2Zyeni7OI9VObp8IIO6ur6/funXrkiVLhCbrKVZXBBsXFdVP
148nPiP1lbFibsOGvTAaaNWkxT/OQ9BsQOoQZxC2OjV8Gz1LW7hPeJxUT6ROTmw+rhOhOUihDi3qSH1
149AHonq+BGI8rNXTF6dIRaDVQb+EYIaWxsfOutt1asWBEREUEpdT8IE67Hgk8pSuJLaGjok08+6QX7
150HS1ipChs2LCwV16ZA2BzMQyIXU+3Pi7dYYxxDoQYJcmfEDMhJvEFIaI66zXPos4eR86nTNc/TtXH
151CTGpjSMkidgTgPY//GHW6NERatF3AfX19QL7lNLg4OCwsDCRGAwaxb2trU1dKNpJ373kKRfC+MaI
152ThPi52RE/6HACSGUtt1+e0pW1jXmI5Bgs9lef/31gICABQsWDBo0CCH0zTffHDlyJCUlpbGx0Waz
153ORyOpqamMWPGLFy40L3OW/fKVoLGeOuJBiLaUj2BdPLkdRUVTRjr+7tAdM+xL0rQR0YG5OauiI0N
154FEPT8pPa2tq9e/eeOXNm6NChCxcuBIC33norPDw8MDDQZDL5+fkZDIbU1NROmUf3YtmcWZy0tbU1
155ICDAMw2u1e07ePDCnDkbZFn1Cv1n0aDj9BiEWFbWstmzh7gXylLnYmVl5e7du0tLS8ePH19RUbFg
156wYLk5GRtbdtO0dW9mnGilYKCgrffflsEunRKvw5nm4QVhU2bFrdhwyIAu6hZeMvGrXQ6XBHKyLn9
157/ffvnT17iKi+6C5UBURHR69YsWLFihX19fXV1dUHDhxoaWkRKoOQLp1O1m4fZ4sQCgkJOXz4cFNT
1580/Dhw9UW3TNDOOeEYEWhY8dG+vub9+49TYj+epXmVgYOgCQJUdr6xz/euWpVmkjs6TQHpr29/bPP
159PtuxY0dRUdGkSZOmTZsWExNTVFSUlZVlt9tjY2NFPFanWUbdI4DQeXU6XVhY2K5duxISEgRf8xCa
160isQ5RpTy9PRYQvTffHNGkv4jaNCBfUVpfeGFef/93zO0ey4XwwNj7P33329sbExPT9fr9YmJiQI/
161aWlpFoslPz9/xIgRJpMJPOjg3ZYB4NRwPv7448rKymeffRa8pvAh5ylVkoT/9Kfs5577nBAjY7jv
162y8n5PkqEMMac0vaXX57/hz9M91SCXjipjh07lpWVtWbNGrWcoSzLe/bsSU9PDw4OppS6HMbuAt07
163yE3b0J133nnlirfsQO39hICi0N/9Lj0kxLRixQ7OMSG6W1I35RgTzmVK6TvvLF65cqIn7KuGkKqq
164qoiICL1eL8syxlhUNTlx4oSiKPfee2+X7+v5ESYWi2Xw4MEuEqlTd42TBliW6eOPj//yy0eCg42U
165tkuScKrcImJZJPITxtoDAgyff7505cqJskxdsK8OkznPlIuKiqqoqGhtbRWRz4qi6HS66dOni6TU
166Ls9w7DYBtL1Rjy1xiezw9IgkYVmmc+cmHD/+1MSJgxWlhRDo6flcvYx9jDEhoCgtY8bEHj/+5F13
167JQudx9MACSFiso8dO9ZsNn/44YeiUqu48/Lly2qCu/cXd1sLguvLMoovly5dUhTFZDJ5OstE02+s
168KCwkxLRs2Vi7nWRnn+dcIUTv9Oj2PUfqyBdjzME5Xb165iefLB440F/oPNrxav2INpvt8OHDR48e
169tVqt0dHRI0eOzM7OPnjwoF6vlyQpNzf38OHD9913X1BQkJcM347GbySpSDWUbtiwwWq1Pv300ypt
170vItlcWCLOI9lxYrdp0+XI2TEWHKu674hA3dGSimc21JSYtetu+v6s9w6hgiaEAWEUGNj4/r16yml
171AwcOLCsrE5bnkJCQL7/8sqCgQJZlPz+/u+++e8SIEVor6U0hgIrQq1evvvHGG3FxcUuXLgXPSpH2
172EVU1stuVd9459uqr+5uaGvuKDNeh3mIJfP756atWpQkPl/ASg5PBqtNfDeh8//33CSHLly8HgLa2
173to8//ri0tHTVqlXh4eF2u729vT0gIEA1gnYZ5dgTFnQdARFijBmNxmHDhu3Zs+fixYujR4/2/mIt
174OxJG3alTY5ctGwugP3WqzmazAiCMJe8FYHqGdwDkFKoK5+1+fuaVK9O3bFk8b16SKJWrMn2xshlj
175Fy9erK2t9fPz0+v1CKGmpqY9e/YsWrQoKCiIUmowGMaNG1dcXHzmzJlJkyYRQoxGI3Kecuc9lkfA
176jZ4nrHY0PDx8+fLl3377rcPhMBgM4HUdqNNKnISgKCwszO8vf7n9179Oe++9vPXr86qr6wEAQC8E
177XbdOse3sdcI9KU4HdQBARMSARx8dt2LFhOhoC2PcRdcUgyopKdm5c6fVahWCbfHixampqeJXNW1L
178WPx/+tOfrl+/vq6uLjw8XCj+XmoL9DIBtNSOj49ftmyZOgzBSbyXOVBrjgosRET4v/TSjDVrpmRm
179nvvoo5P795e1tVkBAEAHIKk4UvPcPaFbcA6V0XGuUKoAcJMpYNq05IcfHn333UNFlqTgOcLCIxoU
1806M7Pz//kk09mzJiRnp5OCMnMzBTFZgIDA+Pi4r766qvhw4cTQhRFAYCgoCBCiN1uB429wUffU68d
1816KyuXK28cr/i4XEQfFk9XlkMoLraundvyZ49JTk5FysrmwDEKWDCQyk+1zXpNHIw50ds9PRRUUFT
182pgyaNy9x7tzEmJiOoGj1CGn3GOnGxsa//OUv99xzT1pamjYmU8yn+vr6N998MyEh4cEHH9TpdAih
183L7/88uTJk7/97W99n/i9TACVDNfaRSgvLy8iIiI6OrrL7bg7ISnlCF07q6u9Xf7hh4a8vOrvv68r
184LKyvrLx66VKr1eqQZVlzJh4CwDqd5O+vHzjQLybGMmxYWGpq+PjxUcOGDTCZdFoFzNP5aoKlZGdn
185Hzhw4He/+506lxFCLS0ttbW1JpMpOjq6srLygw8+UBRlxIgRjY2NFy9efOSRR4YMGeLLIeIu0Jtn
186yrsYab///vtt27YtW7YsJSVFXQq+tAAA6lmaooSM0SiNGRMxenQ4dIh93txsa262NzfbbDZFVKrQ
1876bDRKAUGGi0WQ1CQ0WVqi7P7xKmFWut8px0wGAytra1NTU2hoaGKopSXlx85cqS4uNhms1FKp0yZ
188snjx4meeeSY3N/f8+fMhISH33nvvwIEDuQ8ZXZ0MuRdXgArq8L744ouvvvrqjjvumD17ttejNzy1
189I8JAROHBDtYv+IYXh6jTRX7tLFRN8lAXJdWdC679jTfeYIwlJiaWl5c3NDRERUVNmDBhyJAhZWVl
19027dv/8UvfjF27NgunS39QwAt98cYnzlzZvPmzUuWLBk1apSWn/asu2pvPVVkVaN3tP92t32EUHV1
191dWZmZnNzc0JCwsSJE0U0lfhp3bp1gYGBS5YsURRF3eX2gPvfLAK406ClpcVgMOh0Og361KolXWvK
192fQlaa4/LF+HVkiTp7bffjo6OzsjIELLtBvvfwyPNvYM6u4Uyqk2yFIYUdffgyX7Xl6BqONq9K3cm
1931MmyzJ1nF0qSdOjQocrKysmTJ4NTON/g7OlNIawFtVtaHU5c+eijjzDGGRkZAwYM8FE43yTQmnVB
194M+XVBVpXV/fBBx/Mnj07NTX16tWr+/bty8vLe+CBByIjIz2dpNZtRPXZ7FOXc2lp6RdffFFRUTF2
1957NhZs2aJBNjr+tQj8dDdzqjTXFWRtdtGZ2CHsmvXrtzcXJPJpChKWFhYRkZGbGyslwOsuwt9vfxV
196Mpw9e3bHjh1JSUmLFi1y2eyoJtxep4SLyFH/LS8vz8zMHD16dHp6urtuc+nSpbq6uuDg4KioKME5
197u9xa3ooEUMejVmJUFEVRFJEuK8Zjs9lUY1ZH/9yQ1bP3goa0Ku7sdntOTk5+fn59fX1CQsIdd9wR
198FxenfbX7svDdyuYj3CwZ4A7qNk0MQARTqmfNAYDNZlu7dq3FYpkwYUJSUpI4ckKrh2hnnIvBw9O7
199tPeD2ykuIm8rMTHxoYceEjsp7SMuEkIVxb27KPtHA3HX9gTDPXv27MmTJ8+fP2+1WtPS0jIyMnqw
200uXdRIgU0NzdXVlYWFhaOHz8+ISFBZXoqu+uyQupNgr5bAVpwd2oCgCRJw4YNGz58uKIo586dcxED
201R44cqampGTRoUGBgoMViCQ4OFhsLLaIZY4qiUEpFjSN1J7hjxw5ZlgkhgYGBqampLj1RVaA+EP6d
202oKJ/dXABWg4LTkah5d0iSe3YsWMOh8Nms8myvHLlyujoaDGR29vb169f39LSIqwI4eHhK1euBKdh
203ubq6uqioaMiQIZGRkULegJvZqh93grcEAQRop7N2q6xlVoyx1tZWq9U6YMAAbSDU8ePHEULiANOg
204oKDY2FithHCRFv0y0z3BLUQAT6C6d7TaIfiAR5c9bZcBA/0C/wEEEKDtZ6duHy1a3Wtk37LwH0OA
205/1fhphjjfgTf4f8C4VLHz/5KLxoAAAA8dEVYdGNvbW1lbnQAIEltYWdlIGdlbmVyYXRlZCBieSBH
206TlUgR2hvc3RzY3JpcHQgKGRldmljZT1wbm1yYXcpCvqLFvMAAAAASUVORK5CYII=
diff --git a/gem/input.bin b/gem/input.bin
deleted file mode 100644
index d24a954..0000000
--- a/gem/input.bin
+++ /dev/null
Binary files differ
diff --git a/gem/ltn012.tex b/gem/ltn012.tex
deleted file mode 100644
index 8027ecc..0000000
--- a/gem/ltn012.tex
+++ /dev/null
@@ -1,695 +0,0 @@
1\documentclass[10pt]{article}
2\usepackage{fancyvrb}
3\usepackage{url}
4\DefineVerbatimEnvironment{lua}{Verbatim}{fontsize=\small,commandchars=\@\#\%}
5\DefineVerbatimEnvironment{C}{Verbatim}{fontsize=\small,commandchars=\@\#\%}
6\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
7\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
8\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
9\newcommand{\CR}{\texttt{CR}}
10\newcommand{\LF}{\texttt{LF}}
11\newcommand{\CRLF}{\texttt{CR~LF}}
12\newcommand{\nil}{\texttt{nil}}
13
14\title{Filters, sources, sinks, and pumps\\
15 {\large or Functional programming for the rest of us}}
16\author{Diego Nehab}
17
18\begin{document}
19
20\maketitle
21
22\begin{abstract}
23Certain data processing operations can be implemented in the
24form of filters. A filter is a function that can process
25data received in consecutive invocations, returning partial
26results each time it is called. Examples of operations that
27can be implemented as filters include the end-of-line
28normalization for text, Base64 and Quoted-Printable transfer
29content encodings, the breaking of text into lines, SMTP
30dot-stuffing, and there are many others. Filters become
31even more powerful when we allow them to be chained together
32to create composite filters. In this context, filters can be
33seen as the internal links in a chain of data transformations.
34Sources and sinks are the corresponding end points in these
35chains. A source is a function that produces data, chunk by
36chunk, and a sink is a function that takes data, chunk by
37chunk. Finally, pumps are procedures that actively drive
38data from a source to a sink, and indirectly through all
39intervening filters. In this article, we describe the design of an
40elegant interface for filters, sources, sinks, chains, and
41pumps, and we illustrate each step with concrete examples.
42\end{abstract}
43
44\section{Introduction}
45
46Within the realm of networking applications, we are often
47required to apply transformations to streams of data. Examples
48include the end-of-line normalization for text, Base64 and
49Quoted-Printable transfer content encodings, breaking text
50into lines with a maximum number of columns, SMTP
51dot-stuffing, \texttt{gzip} compression, HTTP chunked
52transfer coding, and the list goes on.
53
54Many complex tasks require a combination of two or more such
55transformations, and therefore a general mechanism for
56promoting reuse is desirable. In the process of designing
57\texttt{LuaSocket~2.0}, we repeatedly faced this problem.
58The solution we reached proved to be very general and
59convenient. It is based on the concepts of filters, sources,
60sinks, and pumps, which we introduce below.
61
62\emph{Filters} are functions that can be repeatedly invoked
63with chunks of input, successively returning processed
64chunks of output. Naturally, the result of
65concatenating all the output chunks must be the same as the
66result of applying the filter to the concatenation of all
67input chunks. In fancier language, filters \emph{commute}
68with the concatenation operator. More importantly, filters
69must handle input data correctly no matter how the stream
70has been split into chunks.
71
72A \emph{chain} is a function that transparently combines the
73effect of one or more filters. The interface of a chain is
74indistinguishable from the interface of its component
75filters. This allows a chained filter to be used wherever
76an atomic filter is accepted. In particular, chains can be
77themselves chained to create arbitrarily complex operations.
78
79Filters can be seen as internal nodes in a network through
80which data will flow, potentially being transformed many
81times along the way. Chains connect these nodes together.
82The initial and final nodes of the network are
83\emph{sources} and \emph{sinks}, respectively. Less
84abstractly, a source is a function that produces new chunks
85of data every time it is invoked. Conversely, sinks are
86functions that give a final destination to the chunks of
87data they receive in sucessive calls. Naturally, sources
88and sinks can also be chained with filters to produce
89filtered sources and sinks.
90
91Finally, filters, chains, sources, and sinks are all passive
92entities: they must be repeatedly invoked in order for
93anything to happen. \emph{Pumps} provide the driving force
94that pushes data through the network, from a source to a
95sink, and indirectly through all intervening filters.
96
97In the following sections, we start with a simplified
98interface, which we later refine. The evolution we present
99is not contrived: it recreates the steps we ourselves
100followed as we consolidated our understanding of these
101concepts within our application domain.
102
103\subsection{A simple example}
104
105The end-of-line normalization of text is a good
106example to motivate our initial filter interface.
107Assume we are given text in an unknown end-of-line
108convention (including possibly mixed conventions) out of the
109commonly found Unix (\LF), Mac OS (\CR), and
110DOS (\CRLF) conventions. We would like to be able to
111use the folowing code to normalize the end-of-line markers:
112\begin{quote}
113\begin{lua}
114@stick#
115local CRLF = "\013\010"
116local input = source.chain(source.file(io.stdin), normalize(CRLF))
117local output = sink.file(io.stdout)
118pump.all(input, output)
119%
120\end{lua}
121\end{quote}
122
123This program should read data from the standard input stream
124and normalize the end-of-line markers to the canonic
125\CRLF\ marker, as defined by the MIME standard.
126Finally, the normalized text should be sent to the standard output
127stream. We use a \emph{file source} that produces data from
128standard input, and chain it with a filter that normalizes
129the data. The pump then repeatedly obtains data from the
130source, and passes it to the \emph{file sink}, which sends
131it to the standard output.
132
133In the code above, the \texttt{normalize} \emph{factory} is a
134function that creates our normalization filter, which
135replaces any end-of-line marker with the canonic marker.
136The initial filter interface is
137trivial: a filter function receives a chunk of input data,
138and returns a chunk of processed data. When there are no
139more input data left, the caller notifies the filter by invoking
140it with a \nil\ chunk. The filter responds by returning
141the final chunk of processed data (which could of course be
142the empty string).
143
144Although the interface is extremely simple, the
145implementation is not so obvious. A normalization filter
146respecting this interface needs to keep some kind of context
147between calls. This is because a chunk boundary may lie between
148the \CR\ and \LF\ characters marking the end of a single line. This
149need for contextual storage motivates the use of
150factories: each time the factory is invoked, it returns a
151filter with its own context so that we can have several
152independent filters being used at the same time. For
153efficiency reasons, we must avoid the obvious solution of
154concatenating all the input into the context before
155producing any output chunks.
156
157To that end, we break the implementation into two parts:
158a low-level filter, and a factory of high-level filters. The
159low-level filter is implemented in C and does not maintain
160any context between function calls. The high-level filter
161factory, implemented in Lua, creates and returns a
162high-level filter that maintains whatever context the low-level
163filter needs, but isolates the user from its internal
164details. That way, we take advantage of C's efficiency to
165perform the hard work, and take advantage of Lua's
166simplicity for the bookkeeping.
167
168\subsection{The Lua part of the filter}
169
170Below is the complete implementation of the factory of high-level
171end-of-line normalization filters:
172\begin{quote}
173\begin{lua}
174@stick#
175function filter.cycle(lowlevel, context, extra)
176 return function(chunk)
177 local ret
178 ret, context = lowlevel(context, chunk, extra)
179 return ret
180 end
181end
182%
183
184@stick#
185function normalize(marker)
186 return filter.cycle(eol, 0, marker)
187end
188%
189\end{lua}
190\end{quote}
191
192The \texttt{normalize} factory simply calls a more generic
193factory, the \texttt{cycle}~factory, passing the low-level
194filter~\texttt{eol}. The \texttt{cycle}~factory receives a
195low-level filter, an initial context, and an extra
196parameter, and returns a new high-level filter. Each time
197the high-level filer is passed a new chunk, it invokes the
198low-level filter with the previous context, the new chunk,
199and the extra argument. It is the low-level filter that
200does all the work, producing the chunk of processed data and
201a new context. The high-level filter then replaces its
202internal context, and returns the processed chunk of data to
203the user. Notice that we take advantage of Lua's lexical
204scoping to store the context in a closure between function
205calls.
206
207\subsection{The C part of the filter}
208
209As for the low-level filter, we must first accept
210that there is no perfect solution to the end-of-line marker
211normalization problem. The difficulty comes from an
212inherent ambiguity in the definition of empty lines within
213mixed input. However, the following solution works well for
214any consistent input, as well as for non-empty lines in
215mixed input. It also does a reasonable job with empty lines
216and serves as a good example of how to implement a low-level
217filter.
218
219The idea is to consider both \CR\ and~\LF\ as end-of-line
220\emph{candidates}. We issue a single break if any candidate
221is seen alone, or if it is followed by a different
222candidate. In other words, \CR~\CR~and \LF~\LF\ each issue
223two end-of-line markers, whereas \CR~\LF~and \LF~\CR\ issue
224only one marker each. It is easy to see that this method
225correctly handles the most common end-of-line conventions.
226
227With this in mind, we divide the low-level filter into two
228simple functions. The inner function~\texttt{pushchar} performs the
229normalization itself. It takes each input character in turn,
230deciding what to output and how to modify the context. The
231context tells if the last processed character was an
232end-of-line candidate, and if so, which candidate it was.
233For efficiency, we use Lua's auxiliary library's buffer
234interface:
235\begin{quote}
236\begin{C}
237@stick#
238@#define candidate(c) (c == CR || c == LF)
239static int pushchar(int c, int last, const char *marker,
240 luaL_Buffer *buffer) {
241 if (candidate(c)) {
242 if (candidate(last)) {
243 if (c == last)
244 luaL_addstring(buffer, marker);
245 return 0;
246 } else {
247 luaL_addstring(buffer, marker);
248 return c;
249 }
250 } else {
251 luaL_pushchar(buffer, c);
252 return 0;
253 }
254}
255%
256\end{C}
257\end{quote}
258
259The outer function~\texttt{eol} simply interfaces with Lua.
260It receives the context and input chunk (as well as an
261optional custom end-of-line marker), and returns the
262transformed output chunk and the new context.
263Notice that if the input chunk is \nil, the operation
264is considered to be finished. In that case, the loop will
265not execute a single time and the context is reset to the
266initial state. This allows the filter to be reused many
267times:
268\begin{quote}
269\begin{C}
270@stick#
271static int eol(lua_State *L) {
272 int context = luaL_checkint(L, 1);
273 size_t isize = 0;
274 const char *input = luaL_optlstring(L, 2, NULL, &isize);
275 const char *last = input + isize;
276 const char *marker = luaL_optstring(L, 3, CRLF);
277 luaL_Buffer buffer;
278 luaL_buffinit(L, &buffer);
279 if (!input) {
280 lua_pushnil(L);
281 lua_pushnumber(L, 0);
282 return 2;
283 }
284 while (input < last)
285 context = pushchar(*input++, context, marker, &buffer);
286 luaL_pushresult(&buffer);
287 lua_pushnumber(L, context);
288 return 2;
289}
290%
291\end{C}
292\end{quote}
293
294When designing filters, the challenging part is usually
295deciding what to store in the context. For line breaking, for
296instance, it could be the number of bytes that still fit in the
297current line. For Base64 encoding, it could be a string
298with the bytes that remain after the division of the input
299into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
300distribution has many other examples.
301
302\section{Filter chains}
303
304Chains greatly increase the power of filters. For example,
305according to the standard for Quoted-Printable encoding,
306text should be normalized to a canonic end-of-line marker
307prior to encoding. After encoding, the resulting text must
308be broken into lines of no more than 76 characters, with the
309use of soft line breaks (a line terminated by the \texttt{=}
310sign). To help specifying complex transformations like
311this, we define a chain factory that creates a composite
312filter from one or more filters. A chained filter passes
313data through all its components, and can be used wherever a
314primitive filter is accepted.
315
316The chaining factory is very simple. The auxiliary
317function~\texttt{chainpair} chains two filters together,
318taking special care if the chunk is the last. This is
319because the final \nil\ chunk notification has to be
320pushed through both filters in turn:
321\begin{quote}
322\begin{lua}
323@stick#
324local function chainpair(f1, f2)
325 return function(chunk)
326 local ret = f2(f1(chunk))
327 if chunk then return ret
328 else return ret .. f2() end
329 end
330end
331%
332
333@stick#
334function filter.chain(...)
335 local f = select(1, ...)
336 for i = 2, select('@#', ...) do
337 f = chainpair(f, select(i, ...))
338 end
339 return f
340end
341%
342\end{lua}
343\end{quote}
344
345Thanks to the chain factory, we can
346define the Quoted-Printable conversion as such:
347\begin{quote}
348\begin{lua}
349@stick#
350local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
351 wrap("quoted-printable"))
352local input = source.chain(source.file(io.stdin), qp)
353local output = sink.file(io.stdout)
354pump.all(input, output)
355%
356\end{lua}
357\end{quote}
358
359\section{Sources, sinks, and pumps}
360
361The filters we introduced so far act as the internal nodes
362in a network of transformations. Information flows from node
363to node (or rather from one filter to the next) and is
364transformed along the way. Chaining filters together is our
365way to connect nodes in this network. As the starting point
366for the network, we need a source node that produces the
367data. In the end of the network, we need a sink node that
368gives a final destination to the data.
369
370\subsection{Sources}
371
372A source returns the next chunk of data each time it is
373invoked. When there is no more data, it simply returns~\nil.
374In the event of an error, the source can inform the
375caller by returning \nil\ followed by the error message.
376
377Below are two simple source factories. The \texttt{empty} source
378returns no data, possibly returning an associated error
379message. The \texttt{file} source yields the contents of a file
380in a chunk by chunk fashion:
381\begin{quote}
382\begin{lua}
383@stick#
384function source.empty(err)
385 return function()
386 return nil, err
387 end
388end
389%
390
391@stick#
392function source.file(handle, io_err)
393 if handle then
394 return function()
395 local chunk = handle:read(2048)
396 if not chunk then handle:close() end
397 return chunk
398 end
399 else return source.empty(io_err or "unable to open file") end
400end
401%
402\end{lua}
403\end{quote}
404
405\subsection{Filtered sources}
406
407A filtered source passes its data through the
408associated filter before returning it to the caller.
409Filtered sources are useful when working with
410functions that get their input data from a source (such as
411the pumps in our examples). By chaining a source with one or
412more filters, such functions can be transparently provided
413with filtered data, with no need to change their interfaces.
414Here is a factory that does the job:
415\begin{quote}
416\begin{lua}
417@stick#
418function source.chain(src, f)
419 return function()
420 if not src then
421 return nil
422 end
423 local chunk, err = src()
424 if not chunk then
425 src = nil
426 return f(nil)
427 else
428 return f(chunk)
429 end
430 end
431end
432%
433\end{lua}
434\end{quote}
435
436\subsection{Sinks}
437
438Just as we defined an interface for a source of data, we can
439also define an interface for a data destination. We call
440any function respecting this interface a sink. In our first
441example, we used a file sink connected to the standard
442output.
443
444Sinks receive consecutive chunks of data, until the end of
445data is signaled by a \nil\ input chunk. A sink can be
446notified of an error with an optional extra argument that
447contains the error message, following a \nil\ chunk.
448If a sink detects an error itself, and
449wishes not to be called again, it can return \nil,
450followed by an error message. A return value that
451is not \nil\ means the sink will accept more data.
452
453Below are two useful sink factories.
454The table factory creates a sink that stores
455individual chunks into an array. The data can later be
456efficiently concatenated into a single string with Lua's
457\texttt{table.concat} library function. The \texttt{null} sink
458simply discards the chunks it receives:
459\begin{quote}
460\begin{lua}
461@stick#
462function sink.table(t)
463 t = t or {}
464 local f = function(chunk, err)
465 if chunk then table.insert(t, chunk) end
466 return 1
467 end
468 return f, t
469end
470%
471
472@stick#
473local function null()
474 return 1
475end
476
477function sink.null()
478 return null
479end
480%
481\end{lua}
482\end{quote}
483
484Naturally, filtered sinks are just as useful as filtered
485sources. A filtered sink passes each chunk it receives
486through the associated filter before handing it down to the
487original sink. In the following example, we use a source
488that reads from the standard input. The input chunks are
489sent to a table sink, which has been coupled with a
490normalization filter. The filtered chunks are then
491concatenated from the output array, and finally sent to
492standard out:
493\begin{quote}
494\begin{lua}
495@stick#
496local input = source.file(io.stdin)
497local output, t = sink.table()
498output = sink.chain(normalize(CRLF), output)
499pump.all(input, output)
500io.write(table.concat(t))
501%
502\end{lua}
503\end{quote}
504
505\subsection{Pumps}
506
507Although not on purpose, our interface for sources is
508compatible with Lua iterators. That is, a source can be
509neatly used in conjunction with \texttt{for} loops. Using
510our file source as an iterator, we can write the following
511code:
512\begin{quote}
513\begin{lua}
514@stick#
515for chunk in source.file(io.stdin) do
516 io.write(chunk)
517end
518%
519\end{lua}
520\end{quote}
521
522Loops like this will always be present because everything
523we designed so far is passive. Sources, sinks, filters: none
524of them can do anything on their own. The operation of
525pumping all data a source can provide into a sink is so
526common that it deserves its own function:
527\begin{quote}
528\begin{lua}
529@stick#
530function pump.step(src, snk)
531 local chunk, src_err = src()
532 local ret, snk_err = snk(chunk, src_err)
533 if chunk and ret then return 1
534 else return nil, src_err or snk_err end
535end
536%
537
538@stick#
539function pump.all(src, snk, step)
540 step = step or pump.step
541 while true do
542 local ret, err = step(src, snk)
543 if not ret then
544 if err then return nil, err
545 else return 1 end
546 end
547 end
548end
549%
550\end{lua}
551\end{quote}
552
553The \texttt{pump.step} function moves one chunk of data from
554the source to the sink. The \texttt{pump.all} function takes
555an optional \texttt{step} function and uses it to pump all the
556data from the source to the sink.
557Here is an example that uses the Base64 and the
558line wrapping filters from the \texttt{LuaSocket}
559distribution. The program reads a binary file from
560disk and stores it in another file, after encoding it to the
561Base64 transfer content encoding:
562\begin{quote}
563\begin{lua}
564@stick#
565local input = source.chain(
566 source.file(io.open("input.bin", "rb")),
567 encode("base64"))
568local output = sink.chain(
569 wrap(76),
570 sink.file(io.open("output.b64", "w")))
571pump.all(input, output)
572%
573\end{lua}
574\end{quote}
575
576The way we split the filters here is not intuitive, on
577purpose. Alternatively, we could have chained the Base64
578encode filter and the line-wrap filter together, and then
579chain the resulting filter with either the file source or
580the file sink. It doesn't really matter.
581
582\section{Exploding filters}
583
584Our current filter interface has one serious shortcoming.
585Consider for example a \texttt{gzip} decompression filter.
586During decompression, a small input chunk can be exploded
587into a huge amount of data. To address this problem, we
588decided to change the filter interface and allow exploding
589filters to return large quantities of output data in a chunk
590by chunk manner.
591
592More specifically, after passing each chunk of input to
593a filter, and collecting the first chunk of output, the
594user must now loop to receive other chunks from the filter until no
595filtered data is left. Within these secondary calls, the
596caller passes an empty string to the filter. The filter
597responds with an empty string when it is ready for the next
598input chunk. In the end, after the user passes a
599\nil\ chunk notifying the filter that there is no
600more input data, the filter might still have to produce too
601much output data to return in a single chunk. The user has
602to loop again, now passing \nil\ to the filter each time,
603until the filter itself returns \nil\ to notify the
604user it is finally done.
605
606Fortunately, it is very easy to modify a filter to respect
607the new interface. In fact, the end-of-line translation
608filter we presented earlier already conforms to it. The
609complexity is encapsulated within the chaining functions,
610which must now include a loop. Since these functions only
611have to be written once, the user is rarely affected.
612Interestingly, the modifications do not have a measurable
613negative impact in the performance of filters that do
614not need the added flexibility. On the other hand, for a
615small price in complexity, the changes make exploding
616filters practical.
617
618\section{A complex example}
619
620The LTN12 module in the \texttt{LuaSocket} distribution
621implements all the ideas we have described. The MIME
622and SMTP modules are tightly integrated with LTN12,
623and can be used to showcase the expressive power of filters,
624sources, sinks, and pumps. Below is an example
625of how a user would proceed to define and send a
626multipart message, with attachments, using \texttt{LuaSocket}:
627\begin{quote}
628\begin{mime}
629local smtp = require"socket.smtp"
630local mime = require"mime"
631local ltn12 = require"ltn12"
632
633local message = smtp.message{
634 headers = {
635 from = "Sicrano <sicrano@example.com>",
636 to = "Fulano <fulano@example.com>",
637 subject = "A message with an attachment"},
638 body = {
639 preamble = "Hope you can see the attachment" .. CRLF,
640 [1] = {
641 body = "Here is our logo" .. CRLF},
642 [2] = {
643 headers = {
644 ["content-type"] = 'image/png; name="luasocket.png"',
645 ["content-disposition"] =
646 'attachment; filename="luasocket.png"',
647 ["content-description"] = 'LuaSocket logo',
648 ["content-transfer-encoding"] = "BASE64"},
649 body = ltn12.source.chain(
650 ltn12.source.file(io.open("luasocket.png", "rb")),
651 ltn12.filter.chain(
652 mime.encode("base64"),
653 mime.wrap()))}}}
654
655assert(smtp.send{
656 rcpt = "<fulano@example.com>",
657 from = "<sicrano@example.com>",
658 source = message})
659\end{mime}
660\end{quote}
661
662The \texttt{smtp.message} function receives a table
663describing the message, and returns a source. The
664\texttt{smtp.send} function takes this source, chains it with the
665SMTP dot-stuffing filter, connects a socket sink
666with the server, and simply pumps the data. The message is never
667assembled in memory. Everything is produced on demand,
668transformed in small pieces, and sent to the server in chunks,
669including the file attachment which is loaded from disk and
670encoded on the fly. It just works.
671
672\section{Conclusions}
673
674In this article, we introduced the concepts of filters,
675sources, sinks, and pumps to the Lua language. These are
676useful tools for stream processing in general. Sources provide
677a simple abstraction for data acquisition. Sinks provide an
678abstraction for final data destinations. Filters define an
679interface for data transformations. The chaining of
680filters, sources and sinks provides an elegant way to create
681arbitrarily complex data transformations from simpler
682components. Pumps simply push the data through.
683
684\section{Acknowledgements}
685
686The concepts described in this text are the result of long
687discussions with David Burgess. A version of this text has
688been released on-line as the Lua Technical Note 012, hence
689the name of the corresponding LuaSocket module, LTN12. Wim
690Couwenberg contributed to the implementation of the module,
691and Adrian Sietsma was the first to notice the
692correspondence between sources and Lua iterators.
693
694
695\end{document}
diff --git a/gem/luasocket.png b/gem/luasocket.png
deleted file mode 100644
index d24a954..0000000
--- a/gem/luasocket.png
+++ /dev/null
Binary files differ
diff --git a/gem/makefile b/gem/makefile
deleted file mode 100644
index a4287c2..0000000
--- a/gem/makefile
+++ /dev/null
@@ -1,14 +0,0 @@
1ltn012.pdf: ltn012.ps
2 ./myps2pdf ltn012.ps
3
4ltn012.ps: ltn012.dvi
5 dvips -G0 -t letter -o ltn012.ps ltn012.dvi
6
7ltn012.dvi: ltn012.tex
8 latex ltn012
9
10clean:
11 rm -f *~ *.log *.aux *.bbl *.blg ltn012.pdf ltn012.ps ltn012.dvi ltn012.lof ltn012.toc ltn012.lot
12
13pdf: ltn012.pdf
14 open ltn012.pdf
diff --git a/gem/myps2pdf b/gem/myps2pdf
deleted file mode 100755
index 78c23e5..0000000
--- a/gem/myps2pdf
+++ /dev/null
@@ -1,113 +0,0 @@
1#!/bin/sh -
2do_opt=1
3best=0
4rot=0
5a4=0
6eps=0
7usage="Usage: $0 [-no_opt] [-best] [-rot] [-a4] [-eps] in.ps [out.pdf]"
8
9case "x$1" in
10"x-no_opt") do_opt=0 ; shift ;;
11esac
12
13case "x$1" in
14"x-best") best=1 ; shift ;;
15esac
16
17case "x$1" in
18"x-rot") rot=1 ; shift ;;
19esac
20
21case "x$1" in
22"x-a4") a4=1 ; shift ;;
23esac
24
25case "x$1" in
26"x-eps") eps=1 ; shift ;;
27esac
28
29case $# in
302) ifilename=$1 ; ofilename=$2 ;;
311) ifilename=$1
32 if `echo $1 | grep -i '\.e*ps$' > /dev/null`
33 then
34 ofilename=`echo $1 | sed 's/\..*$/.pdf/'`
35 else
36 echo "$usage" 1>&2
37 exit 1
38 fi ;;
39*) echo "$usage" 1>&2 ; exit 1 ;;
40esac
41
42if [ $best == 1 ]
43then
44 options="-dPDFSETTINGS=/prepress \
45 -r1200 \
46 -dMonoImageResolution=1200 \
47 -dGrayImageResolution=1200 \
48 -dColorImageResolution=1200 \
49 -dDownsampleMonoImages=false \
50 -dDownsampleGrayImages=false \
51 -dDownsampleColorImages=false \
52 -dAutoFilterMonoImages=false \
53 -dAutoFilterGrayImages=false \
54 -dAutoFilterColorImages=false \
55 -dMonoImageFilter=/FlateEncode \
56 -dGrayImageFilter=/FlateEncode \
57 -dColorImageFilter=/FlateEncode"
58else
59 options="-dPDFSETTINGS=/prepress \
60 -r600 \
61 -dDownsampleMonoImages=true \
62 -dDownsampleGrayImages=true \
63 -dDownsampleColorImages=true \
64 -dMonoImageDownsampleThreshold=2.0 \
65 -dGrayImageDownsampleThreshold=1.5 \
66 -dColorImageDownsampleThreshold=1.5 \
67 -dMonoImageResolution=600 \
68 -dGrayImageResolution=600 \
69 -dColorImageResolution=600 \
70 -dAutoFilterMonoImages=false \
71 -dMonoImageFilter=/FlateEncode \
72 -dAutoFilterGrayImages=true \
73 -dAutoFilterColorImages=true"
74fi
75
76if [ $rot == 1 ]
77then
78 options="$options -dAutoRotatePages=/PageByPage"
79fi
80
81if [ $eps == 1 ]
82then
83 options="$options -dEPSCrop"
84fi
85
86set -x
87
88if [ $a4 == 1 ]
89then
90 # Resize from A4 to letter size
91 psresize -Pa4 -pletter "$ifilename" myps2pdf.temp.ps
92 ifilename=myps2pdf.temp.ps
93fi
94
95gs -q -dSAFER -dNOPAUSE -dBATCH \
96 -sDEVICE=pdfwrite -sPAPERSIZE=letter -sOutputFile=myps2pdf.temp.pdf \
97 -dCompatibilityLevel=1.3 \
98 $options \
99 -dMaxSubsetPct=100 \
100 -dSubsetFonts=true \
101 -dEmbedAllFonts=true \
102 -dColorConversionStrategy=/LeaveColorUnchanged \
103 -dDoThumbnails=true \
104 -dPreserveEPSInfo=true \
105 -c .setpdfwrite -f "$ifilename"
106
107if [ $do_opt == 1 ]
108then
109 pdfopt myps2pdf.temp.pdf $ofilename
110else
111 mv myps2pdf.temp.pdf $ofilename
112fi
113rm -f myps2pdf.temp.pdf myps2pdf.temp.ps
diff --git a/gem/t1.lua b/gem/t1.lua
deleted file mode 100644
index 0c054c9..0000000
--- a/gem/t1.lua
+++ /dev/null
@@ -1,25 +0,0 @@
1source = {}
2sink = {}
3pump = {}
4filter = {}
5
6-- source.chain
7dofile("ex6.lua")
8
9-- source.file
10dofile("ex5.lua")
11
12-- normalize
13require"gem"
14eol = gem.eol
15dofile("ex2.lua")
16
17-- sink.file
18require"ltn12"
19sink.file = ltn12.sink.file
20
21-- pump.all
22dofile("ex10.lua")
23
24-- run test
25dofile("ex1.lua")
diff --git a/gem/t1lf.txt b/gem/t1lf.txt
deleted file mode 100644
index 8cddd1b..0000000
--- a/gem/t1lf.txt
+++ /dev/null
@@ -1,5 +0,0 @@
1this is a test file
2it should have been saved as lf eol
3but t1.lua will convert it to crlf eol
4otherwise it is broken!
5
diff --git a/gem/t2.lua b/gem/t2.lua
deleted file mode 100644
index a81ed73..0000000
--- a/gem/t2.lua
+++ /dev/null
@@ -1,36 +0,0 @@
1source = {}
2sink = {}
3pump = {}
4filter = {}
5
6-- filter.chain
7dofile("ex3.lua")
8
9-- normalize
10require"gem"
11eol = gem.eol
12dofile("ex2.lua")
13
14-- encode
15require"mime"
16encode = mime.encode
17
18-- wrap
19wrap = mime.wrap
20
21-- source.chain
22dofile("ex6.lua")
23
24-- source.file
25dofile("ex5.lua")
26
27-- sink.file
28require"ltn12"
29sink.file = ltn12.sink.file
30
31-- pump.all
32dofile("ex10.lua")
33
34-- run test
35CRLF = "\013\010"
36dofile("ex4.lua")
diff --git a/gem/t2.txt b/gem/t2.txt
deleted file mode 100644
index f484fe8..0000000
--- a/gem/t2.txt
+++ /dev/null
@@ -1,4 +0,0 @@
1esse é um texto com acentos
2quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de texto
3fora que as quebras de linhas têm que ser normalizadas
4vamos ver o que dá isso aqui
diff --git a/gem/t2gt.qp b/gem/t2gt.qp
deleted file mode 100644
index 355a845..0000000
--- a/gem/t2gt.qp
+++ /dev/null
@@ -1,5 +0,0 @@
1esse =E9 um texto com acentos
2quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de t=
3exto
4fora que as quebras de linhas t=EAm que ser normalizadas
5vamos ver o que d=E1 isso aqui
diff --git a/gem/t3.lua b/gem/t3.lua
deleted file mode 100644
index 4bb98ba..0000000
--- a/gem/t3.lua
+++ /dev/null
@@ -1,25 +0,0 @@
1source = {}
2sink = {}
3pump = {}
4filter = {}
5
6-- source.file
7dofile("ex5.lua")
8
9-- sink.table
10dofile("ex7.lua")
11
12-- sink.chain
13require"ltn12"
14sink.chain = ltn12.sink.chain
15
16-- normalize
17require"gem"
18eol = gem.eol
19dofile("ex2.lua")
20
21-- pump.all
22dofile("ex10.lua")
23
24-- run test
25dofile("ex8.lua")
diff --git a/gem/t4.lua b/gem/t4.lua
deleted file mode 100644
index 8b8071c..0000000
--- a/gem/t4.lua
+++ /dev/null
@@ -1,10 +0,0 @@
1source = {}
2sink = {}
3pump = {}
4filter = {}
5
6-- source.file
7dofile("ex5.lua")
8
9-- run test
10dofile("ex9.lua")
diff --git a/gem/t5.lua b/gem/t5.lua
deleted file mode 100644
index 7c569ea..0000000
--- a/gem/t5.lua
+++ /dev/null
@@ -1,30 +0,0 @@
1source = {}
2sink = {}
3pump = {}
4filter = {}
5
6-- source.chain
7dofile("ex6.lua")
8
9-- source.file
10dofile("ex5.lua")
11
12-- encode
13require"mime"
14encode = mime.encode
15
16-- sink.chain
17require"ltn12"
18sink.chain = ltn12.sink.chain
19
20-- wrap
21wrap = mime.wrap
22
23-- sink.file
24sink.file = ltn12.sink.file
25
26-- pump.all
27dofile("ex10.lua")
28
29-- run test
30dofile("ex11.lua")
diff --git a/gem/test.lua b/gem/test.lua
deleted file mode 100644
index a937b9a..0000000
--- a/gem/test.lua
+++ /dev/null
@@ -1,46 +0,0 @@
1function readfile(n)
2 local f = io.open(n, "rb")
3 local s = f:read("*a")
4 f:close()
5 return s
6end
7
8lf = readfile("t1lf.txt")
9os.remove("t1crlf.txt")
10os.execute("lua t1.lua < t1lf.txt > t1crlf.txt")
11crlf = readfile("t1crlf.txt")
12assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
13
14gt = readfile("t2gt.qp")
15os.remove("t2.qp")
16os.execute("lua t2.lua < t2.txt > t2.qp")
17t2 = readfile("t2.qp")
18assert(gt == t2, "broken")
19
20os.remove("t1crlf.txt")
21os.execute("lua t3.lua < t1lf.txt > t1crlf.txt")
22crlf = readfile("t1crlf.txt")
23assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
24
25t = readfile("test.lua")
26os.execute("lua t4.lua < test.lua > t")
27t2 = readfile("t")
28assert(t == t2, "broken")
29
30os.remove("output.b64")
31gt = readfile("gt.b64")
32os.execute("lua t5.lua")
33t5 = readfile("output.b64")
34assert(gt == t5, "failed")
35
36print("1 2 5 6 10 passed")
37print("2 3 4 5 6 10 passed")
38print("2 5 6 7 8 10 passed")
39print("5 9 passed")
40print("5 6 10 11 passed")
41
42os.remove("t")
43os.remove("t2.qp")
44os.remove("t1crlf.txt")
45os.remove("t11.b64")
46os.remove("output.b64")
diff --git a/linux.cmd b/linux.cmd
index bd59adc..6c6636b 100644
--- a/linux.cmd
+++ b/linux.cmd
@@ -1 +1 @@
make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/linux/include LUAPREFIX_linux=/home/diego/build/linux make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/ubuntu/include LUAPREFIX_linux=/home/diego/build/ubuntu
diff --git a/ltn012.md b/ltn012.md
new file mode 100644
index 0000000..fa26b4a
--- /dev/null
+++ b/ltn012.md
@@ -0,0 +1,390 @@
1# Filters, sources and sinks: design, motivation and examples
2### or Functional programming for the rest of us
3by DiegoNehab
4
5## Abstract
6
7Certain operations can be implemented in the form of filters. A filter is a function that processes data received in consecutive function calls, returning partial results chunk by chunk. Examples of operations that can be implemented as filters include the end-of-line normalization for text, Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and there are many others. Filters become even more powerful when we allow them to be chained together to create composite filters. Filters can be seen as middle nodes in a chain of data transformations. Sources an sinks are the corresponding end points of these chains. A source is a function that produces data, chunk by chunk, and a sink is a function that takes data, chunk by chunk. In this technical note, we define an elegant interface for filters, sources, sinks and chaining. We evolve our interface progressively, until we reach a high degree of generality. We discuss difficulties that arise during the implementation of this interface and we provide solutions and examples.
8
9## Introduction
10
11Applications sometimes have too much information to process to fit in memory and are thus forced to process data in smaller parts. Even when there is enough memory, processing all the data atomically may take long enough to frustrate a user that wants to interact with the application. Furthermore, complex transformations can often be defined as series of simpler operations. Several different complex transformations might share the same simpler operations, so that an uniform interface to combine them is desirable. The following concepts constitute our solution to these problems.
12
13"Filters" are functions that accept successive chunks of input, and produce successive chunks of output. Furthermore, the result of concatenating all the output data is the same as the result of applying the filter over the concatenation of the input data. As a consequence, boundaries are irrelevant: filters have to handle input data split arbitrarily by the user.
14
15A "chain" is a function that combines the effect of two (or more) other functions, but whose interface is indistinguishable from the interface of one of its components. Thus, a chained filter can be used wherever an atomic filter can be used. However, its effect on data is the combined effect of its component filters. Note that, as a consequence, chains can be chained themselves to create arbitrarily complex operations that can be used just like atomic operations.
16
17Filters can be seen as internal nodes in a network through which data flows, potentially being transformed along its way. Chains connect these nodes together. To complete the picture, we need "sources" and "sinks" as initial and final nodes of the network, respectively. Less abstractly, a source is a function that produces new data every time it is called. On the other hand, sinks are functions that give a final destination to the data they receive. Naturally, sources and sinks can be chained with filters.
18
19Finally, filters, chains, sources, and sinks are all passive entities: they need to be repeatedly called in order for something to happen. "Pumps" provide the driving force that pushes data through the network, from a source to a sink.
20
21 Hopefully, these concepts will become clear with examples. In the following sections, we start with simplified interfaces, which we improve several times until we can find no obvious shortcomings. The evolution we present is not contrived: it follows the steps we followed ourselves as we consolidated our understanding of these concepts.
22
23### A concrete example
24
25Some data transformations are easier to implement as filters than others. Examples of operations that can be implemented as filters include the end-of-line normalization for text, the Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and many others. Let's use the end-of-line normalization as an example to define our initial filter interface. We later discuss why the implementation might not be trivial.
26
27Assume we are given text in an unknown end-of-line convention (including possibly mixed conventions) out of the commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) conventions. We would like to be able to write code like the following:
28```lua
29input = source.chain(source.file(io.stdin), normalize("\r\n"))
30output = sink.file(io.stdout)
31pump(input, output)
32```
33
34This program should read data from the standard input stream and normalize the end-of-line markers to the canonic CRLF marker defined by the MIME standard, finally sending the results to the standard output stream. For that, we use a "file source" to produce data from standard input, and chain it with a filter that normalizes the data. The pump then repeatedly gets data from the source, and moves it to the "file sink" that sends it to standard output.
35
36To make the discussion even more concrete, we start by discussing the implementation of the normalization filter. The `normalize` "factory" is a function that creates such a filter. Our initial filter interface is as follows: the filter receives a chunk of input data, and returns a chunk of processed data. When there is no more input data, the user notifies the filter by invoking it with a `nil` chunk. The filter then returns the final chunk of processed data.
37
38Although the interface is extremely simple, the implementation doesn't seem so obvious. Any filter respecting this interface needs to keep some kind of context between calls. This is because chunks can be broken between the CR and LF characters marking the end of a line. This need for context storage is what motivates the use of factories: each time the factory is called, it returns a filter with its own context so that we can have several independent filters being used at the same time. For the normalization filter, we know that the obvious solution (i.e. concatenating all the input into the context before producing any output) is not good enough, so we will have to find another way.
39
40We will break the implementation in two parts: a low-level filter, and a factory of high-level filters. The low-level filter will be implemented in C and will not carry any context between function calls. The high-level filter factory, implemented in Lua, will create and return a high-level filter that keeps whatever context the low-level filter needs, but isolates the user from its internal details. That way, we take advantage of C's efficiency to perform the dirty work, and take advantage of Lua's simplicity for the bookkeeping.
41
42### The Lua part of the implementation
43
44Below is the implementation of the factory of high-level end-of-line normalization filters:
45```lua
46function filter.cycle(low, ctx, extra)
47 return function(chunk)
48 local ret
49 ret, ctx = low(ctx, chunk, extra)
50 return ret
51 end
52end
53
54function normalize(marker)
55 return cycle(eol, 0, marker)
56end
57```
58
59The `normalize` factory simply calls a more generic factory, the `cycle` factory. This factory receives a low-level filter, an initial context and some extra value and returns the corresponding high-level filter. Each time the high level filer is called with a new chunk, it calls the low-level filter passing the previous context, the new chunk and the extra argument. The low-level filter produces the chunk of processed data and a new context. Finally, the high-level filter updates its internal context and returns the processed chunk of data to the user. It is the low-level filter that does all the work. Notice that this implementation takes advantage of the Lua 5.0 lexical scoping rules to store the context locally, between function calls.
60
61Moving to the low-level filter, we notice there is no perfect solution to the end-of-line marker normalization problem itself. The difficulty comes from an inherent ambiguity on the definition of empty lines within mixed input. However, the following solution works well for any consistent input, as well as for non-empty lines in mixed input. It also does a reasonable job with empty lines and serves as a good example of how to implement a low-level filter.
62
63Here is what we do: CR and LF are considered candidates for line break. We issue "one" end-of-line line marker if one of the candidates is seen alone, or followed by a "different" candidate. That is, CR&nbsp;CR and LF&nbsp;LF issue two end of line markers each, but CR&nbsp;LF and LF&nbsp;CR issue only one marker. This idea takes care of Mac OS, Mac OS X, VMS and Unix, DOS and MIME, as well as probably other more obscure conventions.
64
65### The C part of the implementation
66
67The low-level filter is divided into two simple functions. The inner function actually does the conversion. It takes each input character in turn, deciding what to output and how to modify the context. The context tells if the last character seen was a candidate and, if so, which candidate it was.
68```c
69#define candidate(c) (c == CR || c == LF)
70static int process(int c, int last, const char *marker, luaL_Buffer *buffer) {
71 if (candidate(c)) {
72 if (candidate(last)) {
73 if (c == last) luaL_addstring(buffer, marker);
74 return 0;
75 } else {
76 luaL_addstring(buffer, marker);
77 return c;
78 }
79 } else {
80 luaL_putchar(buffer, c);
81 return 0;
82 }
83}
84```
85
86The inner function makes use of Lua's auxiliary library's buffer interface for its efficiency and ease of use. The outer function simply interfaces with Lua. It receives the context and the input chunk (as well as an optional end-of-line marker), and returns the transformed output and the new context.
87```c
88static int eol(lua_State *L) {
89 int ctx = luaL_checkint(L, 1);
90 size_t isize = 0;
91 const char *input = luaL_optlstring(L, 2, NULL, &isize);
92 const char *last = input + isize;
93 const char *marker = luaL_optstring(L, 3, CRLF);
94 luaL_Buffer buffer;
95 luaL_buffinit(L, &amp;buffer);
96 if (!input) {
97 lua_pushnil(L);
98 lua_pushnumber(L, 0);
99 return 2;
100 }
101 while (input &lt; last)
102 ctx = process(*input++, ctx, marker, &amp;buffer);
103 luaL_pushresult(&amp;buffer);
104 lua_pushnumber(L, ctx);
105 return 2;
106}
107```
108
109Notice 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 indefinitely. It is a good idea to write filters like this, when possible.
110
111Besides the end-of-line normalization filter shown above, many other filters can be implemented with the same ideas. Examples include Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing etc. The challenging part is to decide what will be 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 the bytes that remain in the division of the input into 3-byte atoms.
112
113## Chaining
114
115Filters become more powerful when the concept of chaining is introduced. Suppose you have a filter for Quoted-Printable encoding and you want to encode some text. According to the standard, the text has to be normalized into its canonic form prior to encoding. A nice interface that simplifies this task is a factory that creates a composite filter that passes data through multiple filters, but that can be used wherever a primitive filter is used.
116```lua
117local function chain2(f1, f2)
118 return function(chunk)
119 local ret = f2(f1(chunk))
120 if chunk then return ret
121 else return ret .. f2() end
122 end
123end
124
125function filter.chain(...)
126 local arg = {...}
127 local f = arg[1]
128 for i = 2, #arg do
129 f = chain2(f, arg[i])
130 end
131 return f
132end
133
134local chain = filter.chain(normalize("\r\n"), encode("quoted-printable"))
135while 1 do
136 local chunk = io.read(2048)
137 io.write(chain(chunk))
138 if not chunk then break end
139end
140```
141
142The chaining factory is very simple. All it does is return a function that passes data through all filters and returns the result to the user. It uses the simpler auxiliary function that knows how to chain two filters together. In the auxiliary function, special care must be taken if the chunk is final. This is because the final chunk notification has to be pushed through both filters in turn. Thanks to the chain factory, it is easy to perform the Quoted-Printable conversion, as the above example shows.
143
144## Sources, sinks, and pumps
145
146As we noted in the introduction, the filters we introduced so far act as the internal nodes in a network of transformations. Information flows from node to node (or rather from one filter to the next) and is transformed on its way out. Chaining filters together is the way we found to connect nodes in the network. But what about the end nodes? In the beginning of the network, we need a node that provides the data, a source. In the end of the network, we need a node that takes in the data, a sink.
147
148### Sources
149
150We start with two simple sources. The first is the `empty` source: It simply returns no data, possibly returning an error message. The second is the `file` source, which produces the contents of a file in a chunk by chunk fashion, closing the file handle when done.
151```lua
152function source.empty(err)
153 return function()
154 return nil, err
155 end
156end
157
158function source.file(handle, io_err)
159 if handle then
160 return function()
161 local chunk = handle:read(2048)
162 if not chunk then handle:close() end
163 return chunk
164 end
165 else return source.empty(io_err or "unable to open file") end
166end
167```
168
169A source returns the next chunk of data each time it is called. When there is no more data, it just returns `nil`. If there is an error, the source can inform the caller by returning `nil` followed by an error message. Adrian Sietsma noticed that, although not on purpose, the interface for sources is compatible with the idea of iterators in Lua 5.0. That is, a data source can be nicely used in conjunction with `for` loops. Using our file source as an iterator, we can rewrite our first example:
170```lua
171local process = normalize("\r\n")
172for chunk in source.file(io.stdin) do
173 io.write(process(chunk))
174end
175io.write(process(nil))
176```
177
178Notice that the last call to the filter obtains the last chunk of processed data. The loop terminates when the source returns `nil` and therefore we need that final call outside of the loop.
179
180### Maintaining state between calls
181
182It is often the case that a source needs to change its behavior after some event. One simple example would be a file source that wants to make sure it returns `nil` regardless of how many times it is called after the end of file, avoiding attempts to read past the end of the file. Another example would be a source that returns the contents of several files, as if they were concatenated, moving from one file to the next until the end of the last file is reached.
183
184One way to implement this kind of source is to have the factory declare extra state variables that the source can use via lexical scoping. Our file source could set the file handle itself to `nil` when it detects the end-of-file. Then, every time the source is called, it could check if the handle is still valid and act accordingly:
185```lua
186function source.file(handle, io_err)
187 if handle then
188 return function()
189 if not handle then return nil end
190 local chunk = handle:read(2048)
191 if not chunk then
192 handle:close()
193 handle = nil
194 end
195 return chunk
196 end
197 else return source.empty(io_err or "unable to open file") end
198end
199```
200
201Another way to implement this behavior involves a change in the source interface to makes it more flexible. Let's allow a source to return a second value, besides the next chunk of data. If the returned chunk is `nil`, the extra return value tells us what happened. A second `nil` means that there is just no more data and the source is empty. Any other value is considered to be an error message. On the other hand, if the chunk was "not" `nil`, the second return value tells us whether the source wants to be replaced. If it is `nil`, we should proceed using the same source. Otherwise it has to be another source, which we have to use from then on, to get the remaining data.
202
203This extra freedom is good for someone writing a source function, but it is a pain for those that have to use it. Fortunately, given one of these "fancy" sources, we can transform it into a simple source that never needs to be replaced, using the following factory.
204```lua
205function source.simplify(src)
206 return function()
207 local chunk, err_or_new = src()
208 src = err_or_new or src
209 if not chunk then return nil, err_or_new
210 else return chunk end
211 end
212end
213```
214
215The simplification factory allows us to write fancy sources and use them as if they were simple. Therefore, our next functions will only produce simple sources, and functions that take sources will assume they are simple.
216
217Going back to our file source, the extended interface allows for a more elegant implementation. The new source just asks to be replaced by an empty source as soon as there is no more data. There is no repeated checking of the handle. To make things simpler to the user, the factory itself simplifies the the fancy file source before returning it to the user:
218```lua
219function source.file(handle, io_err)
220 if handle then
221 return source.simplify(function()
222 local chunk = handle:read(2048)
223 if not chunk then
224 handle:close()
225 return "", source.empty()
226 end
227 return chunk
228 end)
229 else return source.empty(io_err or "unable to open file") end
230end
231```
232
233We 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.
234```lua
235function source.cat(...)
236 local arg = {...}
237 local co = coroutine.create(function()
238 local i = 1
239 while i <= #arg do
240 local chunk, err = arg[i]()
241 if chunk then coroutine.yield(chunk)
242 elseif err then return nil, err
243 else i = i + 1 end
244 end
245 end)
246 return function()
247 return shift(coroutine.resume(co))
248 end
249end
250```
251
252The factory creates two functions. The first is an auxiliary that does all the work, in the form of a coroutine. It reads a chunk from one of the sources. If the chunk is `nil`, it moves to the next source, otherwise it just yields returning the chunk. When it is resumed, it continues from where it stopped and tries to read the next chunk. The second function is the source itself, and just resumes the execution of the auxiliary coroutine, returning to the user whatever chunks it returns (skipping the first result that tells us if the coroutine terminated). Imagine writing the same function without coroutines and you will notice the simplicity of this implementation. We will use coroutines again when we make the filter interface more powerful.
253
254### Chaining Sources
255
256What does it mean to chain a source with a filter? The most useful interpretation is that the combined source-filter is a new source that produces data and passes it through the filter before returning it. Here is a factory that does it:
257```lua
258function source.chain(src, f)
259 return source.simplify(function()
260 local chunk, err = src()
261 if not chunk then return f(nil), source.empty(err)
262 else return f(chunk) end
263 end)
264end
265```
266
267Our motivating example in the introduction chains a source with a filter. The idea of chaining a source with a filter is useful when one thinks about functions that might get their input data from a source. By chaining a simple source with one or more filters, the same function can be provided with filtered data even though it is unaware of the filtering that is happening behind its back.
268
269### Sinks
270
271Just as we defined an interface for an initial source of data, we can also define an interface for a final destination of data. We call any function respecting that interface a "sink". Below are two simple factories that return sinks. The table factory creates a sink that stores all obtained data into a table. The data can later be efficiently concatenated into a single string with the `table.concat` library function. As another example, we introduce the `null` sink: A sink that simply discards the data it receives.
272```lua
273function sink.table(t)
274 t = t or {}
275 local f = function(chunk, err)
276 if chunk then table.insert(t, chunk) end
277 return 1
278 end
279 return f, t
280end
281
282local function null()
283 return 1
284end
285
286function sink.null()
287 return null
288end
289```
290
291Sinks receive consecutive chunks of data, until the end of data is notified with a `nil` chunk. An error is notified by an extra argument giving an error message after the `nil` chunk. If a sink detects an error itself and wishes not to be called again, it should return `nil`, optionally followed by an error message. A return value that is not `nil` means the source will accept more data. Finally, just as sources can choose to be replaced, so can sinks, following the same interface. Once again, it is easy to implement a `sink.simplify` factory that transforms a fancy sink into a simple sink.
292
293As an example, let's create a source that reads from the standard input, then chain it with a filter that normalizes the end-of-line convention and let's use a sink to place all data into a table, printing the result in the end.
294```lua
295local load = source.chain(source.file(io.stdin), normalize("\r\n"))
296local store, t = sink.table()
297while 1 do
298 local chunk = load()
299 store(chunk)
300 if not chunk then break end
301end
302print(table.concat(t))
303```
304
305Again, just as we created a factory that produces a chained source-filter from a source and a filter, it is easy to create a factory that produces a new sink given a sink and a filter. The new sink passes all data it receives through the filter before handing it in to the original sink. Here is the implementation:
306```lua
307function sink.chain(f, snk)
308 return function(chunk, err)
309 local r, e = snk(f(chunk))
310 if not r then return nil, e end
311 if not chunk then return snk(nil, err) end
312 return 1
313 end
314end
315```
316
317### Pumps
318
319There is a while loop that has been around for too long in our examples. It's always there because everything that we designed so far is passive. Sources, sinks, filters: None of them will do anything on their own. The operation of pumping all data a source can provide into a sink is so common that we will provide a couple helper functions to do that for us.
320```lua
321function pump.step(src, snk)
322 local chunk, src_err = src()
323 local ret, snk_err = snk(chunk, src_err)
324 return chunk and ret and not src_err and not snk_err, src_err or snk_err
325end
326
327function pump.all(src, snk, step)
328 step = step or pump.step
329 while true do
330 local ret, err = step(src, snk)
331 if not ret then return not err, err end
332 end
333end
334```
335
336The `pump.step` function moves one chunk of data from the source to the sink. The `pump.all` function takes an optional `step` function and uses it to pump all the data from the source to the sink. We can now use everything we have to write a program that reads a binary file from disk and stores it in another file, after encoding it to the Base64 transfer content encoding:
337```lua
338local load = source.chain(
339 source.file(io.open("input.bin", "rb")),
340 encode("base64")
341)
342local store = sink.chain(
343 wrap(76),
344 sink.file(io.open("output.b64", "w")),
345)
346pump.all(load, store)
347```
348
349The way we split the filters here is not intuitive, on purpose. Alternatively, we could have chained the Base64 encode filter and the line-wrap filter together, and then chain the resulting filter with either the file source or the file sink. It doesn't really matter.
350
351## One last important change
352
353Turns out we still have a problem. When David Burgess was writing his gzip filter, he noticed that the decompression filter can explode a small input chunk into a huge amount of data. Although we wished we could ignore this problem, we soon agreed we couldn't. The only solution is to allow filters to return partial results, and that is what we chose to do. After invoking the filter to pass input data, the user now has to loop invoking the filter to find out if it has more output data to return. Note that these extra calls can't pass more data to the filter.
354
355More specifically, after passing a chunk of input data to a filter and collecting the first chunk of output data, the user invokes the filter repeatedly, passing the empty string, to get extra output chunks. When the filter itself returns an empty string, the user knows there is no more output data, and can proceed to pass the next input chunk. In the end, after the user passes a `nil` notifying the filter that there is no more input data, the filter might still have produced too much output data to return in a single chunk. The user has to loop again, this time passing `nil` each time, until the filter itself returns `nil` to notify the user it is finally done.
356
357Most filters won't need this extra freedom. Fortunately, the new filter interface is easy to implement. In fact, the end-of-line translation filter we created in the introduction already conforms to it. On the other hand, the chaining function becomes much more complicated. If it wasn't for coroutines, I wouldn't be happy to implement it. Let me know if you can find a simpler implementation that does not use coroutines!
358```lua
359local function chain2(f1, f2)
360 local co = coroutine.create(function(chunk)
361 while true do
362 local filtered1 = f1(chunk)
363 local filtered2 = f2(filtered1)
364 local done2 = filtered1 and ""
365 while true do
366 if filtered2 == "" or filtered2 == nil then break end
367 coroutine.yield(filtered2)
368 filtered2 = f2(done2)
369 end
370 if filtered1 == "" then chunk = coroutine.yield(filtered1)
371 elseif filtered1 == nil then return nil
372 else chunk = chunk and "" end
373 end
374 end)
375 return function(chunk)
376 local _, res = coroutine.resume(co, chunk)
377 return res
378 end
379end
380```
381
382Chaining sources also becomes more complicated, but a similar solution is possible with coroutines. Chaining sinks is just as simple as it has always been. Interestingly, these modifications do not have a measurable negative impact in the the performance of filters that didn't need the added flexibility. They do severely improve the efficiency of filters like the gzip filter, though, and that is why we are keeping them.
383
384## Final considerations
385
386These ideas were created during the development of [LuaSocket](https://github.com/lunarmodules/luasocket) 2.0, and are available as the LTN12 module. As a result, [LuaSocket](https://github.com/lunarmodules/luasocket) implementation was greatly simplified and became much more powerful. The MIME module is especially integrated to LTN12 and provides many other filters. We felt these concepts deserved to be made public even to those that don't care about [LuaSocket](https://github.com/lunarmodules/luasocket), hence the LTN.
387
388One extra application that deserves mentioning makes use of an identity filter. Suppose you want to provide some feedback to the user while a file is being downloaded into a sink. Chaining the sink with an identity filter (a filter that simply returns the received data unaltered), you can update a progress counter on the fly. The original sink doesn't have to be modified. Another interesting idea is that of a T sink: A sink that sends data to two other sinks. In summary, there appears to be enough room for many other interesting ideas.
389
390In this technical note we introduced filters, sources, sinks, and pumps. These are useful tools for data processing in general. Sources provide a simple abstraction for data acquisition. Sinks provide an abstraction for final data destinations. Filters define an interface for data transformations. The chaining of filters, sources and sinks provides an elegant way to create arbitrarily complex data transformation from simpler transformations. Pumps just put the machinery to work.
diff --git a/ltn012.wiki b/ltn012.wiki
deleted file mode 100644
index 96b13ae..0000000
--- a/ltn012.wiki
+++ /dev/null
@@ -1,393 +0,0 @@
1===Filters, sources and sinks: design, motivation and examples===
2==or Functional programming for the rest of us==
3by DiegoNehab
4
5{{{
6
7}}}
8
9===Abstract===
10Certain operations can be implemented in the form of filters. A filter is a function that processes data received in consecutive function calls, returning partial results chunk by chunk. Examples of operations that can be implemented as filters include the end-of-line normalization for text, Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and there are many others. Filters become even more powerful when we allow them to be chained together to create composite filters. Filters can be seen as middle nodes in a chain of data transformations. Sources an sinks are the corresponding end points of these chains. A source is a function that produces data, chunk by chunk, and a sink is a function that takes data, chunk by chunk. In this technical note, we define an elegant interface for filters, sources, sinks and chaining. We evolve our interface progressively, until we reach a high degree of generality. We discuss difficulties that arise during the implementation of this interface and we provide solutions and examples.
11
12===Introduction===
13
14Applications sometimes have too much information to process to fit in memory and are thus forced to process data in smaller parts. Even when there is enough memory, processing all the data atomically may take long enough to frustrate a user that wants to interact with the application. Furthermore, complex transformations can often be defined as series of simpler operations. Several different complex transformations might share the same simpler operations, so that an uniform interface to combine them is desirable. The following concepts constitute our solution to these problems.
15
16''Filters'' are functions that accept successive chunks of input, and produce successive chunks of output. Furthermore, the result of concatenating all the output data is the same as the result of applying the filter over the concatenation of the input data. As a consequence, boundaries are irrelevant: filters have to handle input data split arbitrarily by the user.
17
18A ''chain'' is a function that combines the effect of two (or more) other functions, but whose interface is indistinguishable from the interface of one of its components. Thus, a chained filter can be used wherever an atomic filter can be used. However, its effect on data is the combined effect of its component filters. Note that, as a consequence, chains can be chained themselves to create arbitrarily complex operations that can be used just like atomic operations.
19
20Filters can be seen as internal nodes in a network through which data flows, potentially being transformed along its way. Chains connect these nodes together. To complete the picture, we need ''sources'' and ''sinks'' as initial and final nodes of the network, respectively. Less abstractly, a source is a function that produces new data every time it is called. On the other hand, sinks are functions that give a final destination to the data they receive. Naturally, sources and sinks can be chained with filters.
21
22Finally, filters, chains, sources, and sinks are all passive entities: they need to be repeatedly called in order for something to happen. ''Pumps'' provide the driving force that pushes data through the network, from a source to a sink.
23
24 Hopefully, these concepts will become clear with examples. In the following sections, we start with simplified interfaces, which we improve several times until we can find no obvious shortcomings. The evolution we present is not contrived: it follows the steps we followed ourselves as we consolidated our understanding of these concepts.
25
26== A concrete example ==
27
28Some data transformations are easier to implement as filters than others. Examples of operations that can be implemented as filters include the end-of-line normalization for text, the Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and many others. Let's use the end-of-line normalization as an example to define our initial filter interface. We later discuss why the implementation might not be trivial.
29
30Assume we are given text in an unknown end-of-line convention (including possibly mixed conventions) out of the commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) conventions. We would like to be able to write code like the following:
31 {{{
32input = source.chain(source.file(io.stdin), normalize("\r\n"))
33output = sink.file(io.stdout)
34pump(input, output)
35}}}
36
37This program should read data from the standard input stream and normalize the end-of-line markers to the canonic CRLF marker defined by the MIME standard, finally sending the results to the standard output stream. For that, we use a ''file source'' to produce data from standard input, and chain it with a filter that normalizes the data. The pump then repeatedly gets data from the source, and moves it to the ''file sink'' that sends it to standard output.
38
39To make the discussion even more concrete, we start by discussing the implementation of the normalization filter. The {{normalize}} ''factory'' is a function that creates such a filter. Our initial filter interface is as follows: the filter receives a chunk of input data, and returns a chunk of processed data. When there is no more input data, the user notifies the filter by invoking it with a {{nil}} chunk. The filter then returns the final chunk of processed data.
40
41Although the interface is extremely simple, the implementation doesn't seem so obvious. Any filter respecting this interface needs to keep some kind of context between calls. This is because chunks can be broken between the CR and LF characters marking the end of a line. This need for context storage is what motivates the use of factories: each time the factory is called, it returns a filter with its own context so that we can have several independent filters being used at the same time. For the normalization filter, we know that the obvious solution (i.e. concatenating all the input into the context before producing any output) is not good enough, so we will have to find another way.
42
43We will break the implementation in two parts: a low-level filter, and a factory of high-level filters. The low-level filter will be implemented in C and will not carry any context between function calls. The high-level filter factory, implemented in Lua, will create and return a high-level filter that keeps whatever context the low-level filter needs, but isolates the user from its internal details. That way, we take advantage of C's efficiency to perform the dirty work, and take advantage of Lua's simplicity for the bookkeeping.
44
45==The Lua part of the implementation==
46
47Below is the implementation of the factory of high-level end-of-line normalization filters:
48 {{{
49function filter.cycle(low, ctx, extra)
50 return function(chunk)
51 local ret
52 ret, ctx = low(ctx, chunk, extra)
53 return ret
54 end
55end
56
57function normalize(marker)
58 return cycle(eol, 0, marker)
59end
60}}}
61
62The {{normalize}} factory simply calls a more generic factory, the {{cycle}} factory. This factory receives a low-level filter, an initial context and some extra value and returns the corresponding high-level filter. Each time the high level filer is called with a new chunk, it calls the low-level filter passing the previous context, the new chunk and the extra argument. The low-level filter produces the chunk of processed data and a new context. Finally, the high-level filter updates its internal context and returns the processed chunk of data to the user. It is the low-level filter that does all the work. Notice that this implementation takes advantage of the Lua 5.0 lexical scoping rules to store the context locally, between function calls.
63
64Moving to the low-level filter, we notice there is no perfect solution to the end-of-line marker normalization problem itself. The difficulty comes from an inherent ambiguity on the definition of empty lines within mixed input. However, the following solution works well for any consistent input, as well as for non-empty lines in mixed input. It also does a reasonable job with empty lines and serves as a good example of how to implement a low-level filter.
65
66Here is what we do: CR and LF are considered candidates for line break. We issue ''one'' end-of-line line marker if one of the candidates is seen alone, or followed by a ''different'' candidate. That is, CR&nbsp;CR and LF&nbsp;LF issue two end of line markers each, but CR&nbsp;LF and LF&nbsp;CR issue only one marker. This idea takes care of Mac OS, Mac OS X, VMS and Unix, DOS and MIME, as well as probably other more obscure conventions.
67
68==The C part of the implementation==
69
70The low-level filter is divided into two simple functions. The inner function actually does the conversion. It takes each input character in turn, deciding what to output and how to modify the context. The context tells if the last character seen was a candidate and, if so, which candidate it was.
71 {{{
72#define candidate(c) (c == CR || c == LF)
73static int process(int c, int last, const char *marker, luaL_Buffer *buffer) {
74 if (candidate(c)) {
75 if (candidate(last)) {
76 if (c == last) luaL_addstring(buffer, marker);
77 return 0;
78 } else {
79 luaL_addstring(buffer, marker);
80 return c;
81 }
82 } else {
83 luaL_putchar(buffer, c);
84 return 0;
85 }
86}
87}}}
88
89The inner function makes use of Lua's auxiliary library's buffer interface for its efficiency and ease of use. The outer function simply interfaces with Lua. It receives the context and the input chunk (as well as an optional end-of-line marker), and returns the transformed output and the new context.
90 {{{
91static int eol(lua_State *L) {
92 int ctx = luaL_checkint(L, 1);
93 size_t isize = 0;
94 const char *input = luaL_optlstring(L, 2, NULL, &isize);
95 const char *last = input + isize;
96 const char *marker = luaL_optstring(L, 3, CRLF);
97 luaL_Buffer buffer;
98 luaL_buffinit(L, &amp;buffer);
99 if (!input) {
100 lua_pushnil(L);
101 lua_pushnumber(L, 0);
102 return 2;
103 }
104 while (input &lt; last)
105 ctx = process(*input++, ctx, marker, &amp;buffer);
106 luaL_pushresult(&amp;buffer);
107 lua_pushnumber(L, ctx);
108 return 2;
109}
110}}}
111
112Notice 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 indefinitely. It is a good idea to write filters like this, when possible.
113
114Besides the end-of-line normalization filter shown above, many other filters can be implemented with the same ideas. Examples include Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing etc. The challenging part is to decide what will be 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 the bytes that remain in the division of the input into 3-byte atoms.
115
116===Chaining===
117
118Filters become more powerful when the concept of chaining is introduced. Suppose you have a filter for Quoted-Printable encoding and you want to encode some text. According to the standard, the text has to be normalized into its canonic form prior to encoding. A nice interface that simplifies this task is a factory that creates a composite filter that passes data through multiple filters, but that can be used wherever a primitive filter is used.
119 {{{
120local function chain2(f1, f2)
121 return function(chunk)
122 local ret = f2(f1(chunk))
123 if chunk then return ret
124 else return ret .. f2() end
125 end
126end
127
128function filter.chain(...)
129 local arg = {...}
130 local f = arg[1]
131 for i = 2, #arg do
132 f = chain2(f, arg[i])
133 end
134 return f
135end
136
137local chain = filter.chain(normalize("\r\n"), encode("quoted-printable"))
138while 1 do
139 local chunk = io.read(2048)
140 io.write(chain(chunk))
141 if not chunk then break end
142end
143}}}
144
145The chaining factory is very simple. All it does is return a function that passes data through all filters and returns the result to the user. It uses the simpler auxiliary function that knows how to chain two filters together. In the auxiliary function, special care must be taken if the chunk is final. This is because the final chunk notification has to be pushed through both filters in turn. Thanks to the chain factory, it is easy to perform the Quoted-Printable conversion, as the above example shows.
146
147===Sources, sinks, and pumps===
148
149As we noted in the introduction, the filters we introduced so far act as the internal nodes in a network of transformations. Information flows from node to node (or rather from one filter to the next) and is transformed on its way out. Chaining filters together is the way we found to connect nodes in the network. But what about the end nodes? In the beginning of the network, we need a node that provides the data, a source. In the end of the network, we need a node that takes in the data, a sink.
150
151==Sources==
152
153We start with two simple sources. The first is the {{empty}} source: It simply returns no data, possibly returning an error message. The second is the {{file}} source, which produces the contents of a file in a chunk by chunk fashion, closing the file handle when done.
154 {{{
155function source.empty(err)
156 return function()
157 return nil, err
158 end
159end
160
161function source.file(handle, io_err)
162 if handle then
163 return function()
164 local chunk = handle:read(2048)
165 if not chunk then handle:close() end
166 return chunk
167 end
168 else return source.empty(io_err or "unable to open file") end
169end
170}}}
171
172A source returns the next chunk of data each time it is called. When there is no more data, it just returns {{nil}}. If there is an error, the source can inform the caller by returning {{nil}} followed by an error message. Adrian Sietsma noticed that, although not on purpose, the interface for sources is compatible with the idea of iterators in Lua 5.0. That is, a data source can be nicely used in conjunction with {{for}} loops. Using our file source as an iterator, we can rewrite our first example:
173 {{{
174local process = normalize("\r\n")
175for chunk in source.file(io.stdin) do
176 io.write(process(chunk))
177end
178io.write(process(nil))
179}}}
180
181Notice that the last call to the filter obtains the last chunk of processed data. The loop terminates when the source returns {{nil}} and therefore we need that final call outside of the loop.
182
183==Maintaining state between calls==
184
185It is often the case that a source needs to change its behavior after some event. One simple example would be a file source that wants to make sure it returns {{nil}} regardless of how many times it is called after the end of file, avoiding attempts to read past the end of the file. Another example would be a source that returns the contents of several files, as if they were concatenated, moving from one file to the next until the end of the last file is reached.
186
187One way to implement this kind of source is to have the factory declare extra state variables that the source can use via lexical scoping. Our file source could set the file handle itself to {{nil}} when it detects the end-of-file. Then, every time the source is called, it could check if the handle is still valid and act accordingly:
188 {{{
189function source.file(handle, io_err)
190 if handle then
191 return function()
192 if not handle then return nil end
193 local chunk = handle:read(2048)
194 if not chunk then
195 handle:close()
196 handle = nil
197 end
198 return chunk
199 end
200 else return source.empty(io_err or "unable to open file") end
201end
202}}}
203
204Another way to implement this behavior involves a change in the source interface to makes it more flexible. Let's allow a source to return a second value, besides the next chunk of data. If the returned chunk is {{nil}}, the extra return value tells us what happened. A second {{nil}} means that there is just no more data and the source is empty. Any other value is considered to be an error message. On the other hand, if the chunk was ''not'' {{nil}}, the second return value tells us whether the source wants to be replaced. If it is {{nil}}, we should proceed using the same source. Otherwise it has to be another source, which we have to use from then on, to get the remaining data.
205
206This extra freedom is good for someone writing a source function, but it is a pain for those that have to use it. Fortunately, given one of these ''fancy'' sources, we can transform it into a simple source that never needs to be replaced, using the following factory.
207 {{{
208function source.simplify(src)
209 return function()
210 local chunk, err_or_new = src()
211 src = err_or_new or src
212 if not chunk then return nil, err_or_new
213 else return chunk end
214 end
215end
216}}}
217
218The simplification factory allows us to write fancy sources and use them as if they were simple. Therefore, our next functions will only produce simple sources, and functions that take sources will assume they are simple.
219
220Going back to our file source, the extended interface allows for a more elegant implementation. The new source just asks to be replaced by an empty source as soon as there is no more data. There is no repeated checking of the handle. To make things simpler to the user, the factory itself simplifies the the fancy file source before returning it to the user:
221 {{{
222function source.file(handle, io_err)
223 if handle then
224 return source.simplify(function()
225 local chunk = handle:read(2048)
226 if not chunk then
227 handle:close()
228 return "", source.empty()
229 end
230 return chunk
231 end)
232 else return source.empty(io_err or "unable to open file") end
233end
234}}}
235
236We 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.
237 {{{
238function source.cat(...)
239 local arg = {...}
240 local co = coroutine.create(function()
241 local i = 1
242 while i <= #arg do
243 local chunk, err = arg[i]()
244 if chunk then coroutine.yield(chunk)
245 elseif err then return nil, err
246 else i = i + 1 end
247 end
248 end)
249 return function()
250 return shift(coroutine.resume(co))
251 end
252end
253}}}
254
255The factory creates two functions. The first is an auxiliary that does all the work, in the form of a coroutine. It reads a chunk from one of the sources. If the chunk is {{nil}}, it moves to the next source, otherwise it just yields returning the chunk. When it is resumed, it continues from where it stopped and tries to read the next chunk. The second function is the source itself, and just resumes the execution of the auxiliary coroutine, returning to the user whatever chunks it returns (skipping the first result that tells us if the coroutine terminated). Imagine writing the same function without coroutines and you will notice the simplicity of this implementation. We will use coroutines again when we make the filter interface more powerful.
256
257==Chaining Sources==
258
259What does it mean to chain a source with a filter? The most useful interpretation is that the combined source-filter is a new source that produces data and passes it through the filter before returning it. Here is a factory that does it:
260 {{{
261function source.chain(src, f)
262 return source.simplify(function()
263 local chunk, err = src()
264 if not chunk then return f(nil), source.empty(err)
265 else return f(chunk) end
266 end)
267end
268}}}
269
270Our motivating example in the introduction chains a source with a filter. The idea of chaining a source with a filter is useful when one thinks about functions that might get their input data from a source. By chaining a simple source with one or more filters, the same function can be provided with filtered data even though it is unaware of the filtering that is happening behind its back.
271
272==Sinks==
273
274Just as we defined an interface for an initial source of data, we can also define an interface for a final destination of data. We call any function respecting that interface a ''sink''. Below are two simple factories that return sinks. The table factory creates a sink that stores all obtained data into a table. The data can later be efficiently concatenated into a single string with the {{table.concat}} library function. As another example, we introduce the {{null}} sink: A sink that simply discards the data it receives.
275 {{{
276function sink.table(t)
277 t = t or {}
278 local f = function(chunk, err)
279 if chunk then table.insert(t, chunk) end
280 return 1
281 end
282 return f, t
283end
284
285local function null()
286 return 1
287end
288
289function sink.null()
290 return null
291end
292}}}
293
294Sinks receive consecutive chunks of data, until the end of data is notified with a {{nil}} chunk. An error is notified by an extra argument giving an error message after the {{nil}} chunk. If a sink detects an error itself and wishes not to be called again, it should return {{nil}}, optionally followed by an error message. A return value that is not {{nil}} means the source will accept more data. Finally, just as sources can choose to be replaced, so can sinks, following the same interface. Once again, it is easy to implement a {{sink.simplify}} factory that transforms a fancy sink into a simple sink.
295
296As an example, let's create a source that reads from the standard input, then chain it with a filter that normalizes the end-of-line convention and let's use a sink to place all data into a table, printing the result in the end.
297 {{{
298local load = source.chain(source.file(io.stdin), normalize("\r\n"))
299local store, t = sink.table()
300while 1 do
301 local chunk = load()
302 store(chunk)
303 if not chunk then break end
304end
305print(table.concat(t))
306}}}
307
308Again, just as we created a factory that produces a chained source-filter from a source and a filter, it is easy to create a factory that produces a new sink given a sink and a filter. The new sink passes all data it receives through the filter before handing it in to the original sink. Here is the implementation:
309 {{{
310function sink.chain(f, snk)
311 return function(chunk, err)
312 local r, e = snk(f(chunk))
313 if not r then return nil, e end
314 if not chunk then return snk(nil, err) end
315 return 1
316 end
317end
318}}}
319
320==Pumps==
321
322There is a while loop that has been around for too long in our examples. It's always there because everything that we designed so far is passive. Sources, sinks, filters: None of them will do anything on their own. The operation of pumping all data a source can provide into a sink is so common that we will provide a couple helper functions to do that for us.
323 {{{
324function pump.step(src, snk)
325 local chunk, src_err = src()
326 local ret, snk_err = snk(chunk, src_err)
327 return chunk and ret and not src_err and not snk_err, src_err or snk_err
328end
329
330function pump.all(src, snk, step)
331 step = step or pump.step
332 while true do
333 local ret, err = step(src, snk)
334 if not ret then return not err, err end
335 end
336end
337}}}
338
339The {{pump.step}} function moves one chunk of data from the source to the sink. The {{pump.all}} function takes an optional {{step}} function and uses it to pump all the data from the source to the sink. We can now use everything we have to write a program that reads a binary file from disk and stores it in another file, after encoding it to the Base64 transfer content encoding:
340 {{{
341local load = source.chain(
342 source.file(io.open("input.bin", "rb")),
343 encode("base64")
344)
345local store = sink.chain(
346 wrap(76),
347 sink.file(io.open("output.b64", "w")),
348)
349pump.all(load, store)
350}}}
351
352The way we split the filters here is not intuitive, on purpose. Alternatively, we could have chained the Base64 encode filter and the line-wrap filter together, and then chain the resulting filter with either the file source or the file sink. It doesn't really matter.
353
354===One last important change===
355
356Turns out we still have a problem. When David Burgess was writing his gzip filter, he noticed that the decompression filter can explode a small input chunk into a huge amount of data. Although we wished we could ignore this problem, we soon agreed we couldn't. The only solution is to allow filters to return partial results, and that is what we chose to do. After invoking the filter to pass input data, the user now has to loop invoking the filter to find out if it has more output data to return. Note that these extra calls can't pass more data to the filter.
357
358More specifically, after passing a chunk of input data to a filter and collecting the first chunk of output data, the user invokes the filter repeatedly, passing the empty string, to get extra output chunks. When the filter itself returns an empty string, the user knows there is no more output data, and can proceed to pass the next input chunk. In the end, after the user passes a {{nil}} notifying the filter that there is no more input data, the filter might still have produced too much output data to return in a single chunk. The user has to loop again, this time passing {{nil}} each time, until the filter itself returns {{nil}} to notify the user it is finally done.
359
360Most filters won't need this extra freedom. Fortunately, the new filter interface is easy to implement. In fact, the end-of-line translation filter we created in the introduction already conforms to it. On the other hand, the chaining function becomes much more complicated. If it wasn't for coroutines, I wouldn't be happy to implement it. Let me know if you can find a simpler implementation that does not use coroutines!
361 {{{
362local function chain2(f1, f2)
363 local co = coroutine.create(function(chunk)
364 while true do
365 local filtered1 = f1(chunk)
366 local filtered2 = f2(filtered1)
367 local done2 = filtered1 and ""
368 while true do
369 if filtered2 == "" or filtered2 == nil then break end
370 coroutine.yield(filtered2)
371 filtered2 = f2(done2)
372 end
373 if filtered1 == "" then chunk = coroutine.yield(filtered1)
374 elseif filtered1 == nil then return nil
375 else chunk = chunk and "" end
376 end
377 end)
378 return function(chunk)
379 local _, res = coroutine.resume(co, chunk)
380 return res
381 end
382end
383}}}
384
385Chaining sources also becomes more complicated, but a similar solution is possible with coroutines. Chaining sinks is just as simple as it has always been. Interestingly, these modifications do not have a measurable negative impact in the the performance of filters that didn't need the added flexibility. They do severely improve the efficiency of filters like the gzip filter, though, and that is why we are keeping them.
386
387===Final considerations===
388
389These ideas were created during the development of {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket] 2.0, and are available as the LTN12 module. As a result, {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket] implementation was greatly simplified and became much more powerful. The MIME module is especially integrated to LTN12 and provides many other filters. We felt these concepts deserved to be made public even to those that don't care about {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket], hence the LTN.
390
391One extra application that deserves mentioning makes use of an identity filter. Suppose you want to provide some feedback to the user while a file is being downloaded into a sink. Chaining the sink with an identity filter (a filter that simply returns the received data unaltered), you can update a progress counter on the fly. The original sink doesn't have to be modified. Another interesting idea is that of a T sink: A sink that sends data to two other sinks. In summary, there appears to be enough room for many other interesting ideas.
392
393In this technical note we introduced filters, sources, sinks, and pumps. These are useful tools for data processing in general. Sources provide a simple abstraction for data acquisition. Sinks provide an abstraction for final data destinations. Filters define an interface for data transformations. The chaining of filters, sources and sinks provides an elegant way to create arbitrarily complex data transformation from simpler transformations. Pumps just put the machinery to work.
diff --git a/ltn013.md b/ltn013.md
new file mode 100644
index 0000000..9c56805
--- /dev/null
+++ b/ltn013.md
@@ -0,0 +1,191 @@
1# Using finalized exceptions
2### or How to get rid of all those if statements
3by DiegoNehab
4
5
6## Abstract
7This little LTN describes a simple exception scheme that greatly simplifies error checking in Lua programs. All the needed functionality ships standard with Lua, but is hidden between the `assert` and `pcall` functions. To make it more evident, we stick to a convenient standard (you probably already use anyways) for Lua function return values, and define two very simple helper functions (either in C or in Lua itself).
8
9## Introduction
10
11Most Lua functions return `nil` in case of error, followed by a message describing the error. If you don't use this convention, you probably have good reasons. Hopefully, after reading on, you will realize your reasons are not good enough.
12
13If you are like me, you hate error checking. Most nice little code snippets that look beautiful when you first write them lose some of their charm when you add all that error checking code. Yet, error checking is as important as the rest of the code. How sad.
14
15Even if you stick to a return convention, any complex task involving several function calls makes error checking both boring and error-prone (do you see the "error" below?)
16```lua
17function task(arg1, arg2, ...)
18 local ret1, err = task1(arg1)
19 if not ret1 then
20 cleanup1()
21 return nil, error
22 end
23 local ret2, err = task2(arg2)
24 if not ret then
25 cleanup2()
26 return nil, error
27 end
28 ...
29end
30```
31
32The standard `assert` function provides an interesting alternative. To use it, simply nest every function call to be error checked with a call to `assert`. The `assert` function checks the value of its first argument. If it is `nil`, `assert` throws the second argument as an error message. Otherwise, `assert` lets all arguments through as if had not been there. The idea greatly simplifies error checking:
33```lua
34function task(arg1, arg2, ...)
35 local ret1 = assert(task1(arg1))
36 local ret2 = assert(task2(arg2))
37 ...
38end
39```
40
41If any task fails, the execution is aborted by `assert` and the error message is displayed to the user as the cause of the problem. If no error happens, the task completes as before. There isn't a single `if` statement and this is great. However, there are some problems with the idea.
42
43First, the topmost `task` function doesn't respect the protocol followed by the lower-level tasks: It raises an error instead of returning `nil` followed by the error messages. Here is where the standard `pcall` comes in handy.
44```lua
45function xtask(arg1, arg2, ...)
46 local ret1 = assert(task1(arg1))
47 local ret2 = assert(task2(arg2))
48 ...
49end
50
51function task(arg1, arg2, ...)
52 local ok, ret_or_err = pcall(xtask, arg1, arg2, ...)
53 if ok then return ret_or_err
54 else return nil, ret_or_err end
55end
56```
57
58Our new `task` function is well behaved. `Pcall` catches any error raised by the calls to `assert` and returns it after the status code. That way, errors don't get propagated to the user of the high level `task` function.
59
60These are the main ideas for our exception scheme, but there are still a few glitches to fix:
61
62* Directly using `pcall` ruined the simplicity of the code;
63* What happened to the cleanup function calls? What if we have to, say, close a file?
64* `Assert` messes with the error message before raising the error (it adds line number information).
65
66Fortunately, all these problems are very easy to solve and that's what we do in the following sections.
67
68## Introducing the `protect` factory
69
70We 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:
71```lua
72local function pack(ok, ...)
73 return ok, {...}
74end
75
76function protect(f)
77 return function(...)
78 local ok, ret = pack(pcall(f, ...))
79 if ok then return unpack(ret)
80 else return nil, ret[1] end
81 end
82end
83```
84
85The `protect` factory receives a function that might raise exceptions and returns a function that respects our return value convention. Now we can rewrite the top-level `task` function in a much cleaner way:
86```lua
87task = protect(function(arg1, arg2, ...)
88 local ret1 = assert(task1(arg1))
89 local ret2 = assert(task2(arg2))
90 ...
91end)
92```
93
94The Lua implementation of the `protect` factory suffers with the creation of tables to hold multiple arguments and return values. It is possible (and easy) to implement the same function in C, without any table creation.
95```c
96static int safecall(lua_State *L) {
97 lua_pushvalue(L, lua_upvalueindex(1));
98 lua_insert(L, 1);
99 if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
100 lua_pushnil(L);
101 lua_insert(L, 1);
102 return 2;
103 } else return lua_gettop(L);
104}
105
106static int protect(lua_State *L) {
107 lua_pushcclosure(L, safecall, 1);
108 return 1;
109}
110```
111
112## The `newtry` factory
113
114Let's solve the two remaining issues with a single shot and use a concrete example to illustrate the proposed solution. Suppose you want to write a function to download an HTTP document. You have to connect, send the request and read the reply. Each of these tasks can fail, but if something goes wrong after you connected, you have to close the connection before returning the error message.
115```lua
116get = protect(function(host, path)
117 local c
118 -- create a try function with a finalizer to close the socket
119 local try = newtry(function()
120 if c then c:close() end
121 end)
122 -- connect and send request
123 c = try(connect(host, 80))
124 try(c:send("GET " .. path .. " HTTP/1.0\r\n\r\n"))
125 -- get headers
126 local h = {}
127 while 1 do
128 l = try(c:receive())
129 if l == "" then break end
130 table.insert(h, l)
131 end
132 -- get body
133 local b = try(c:receive("*a"))
134 c:close()
135 return b, h
136end)
137```
138
139The `newtry` factory returns a function that works just like `assert`. The differences are that the `try` function doesn't mess with the error message and it calls an optional "finalizer" before raising the error. In our example, the finalizer simply closes the socket.
140
141Even with a simple example like this, we see that the finalized exceptions simplified our life. Let's see what we gain in general, not just in this example:
142
143* We don't need to declare dummy variables to hold error messages in case any ever shows up;
144* We avoid using a variable to hold something that could either be a return value or an error message;
145* We didn't have to use several "if" statements to check for errors;
146* If an error happens, we know our finalizer is going to be invoked automatically;
147* Exceptions get propagated, so we don't repeat these "if" statements until the error reaches the user.
148
149Try writing the same function without the tricks we used above and you will see that the code gets ugly. Longer sequences of operations with error checking would get even uglier. So let's implement the `newtry` function in Lua:
150```lua
151function newtry(f)
152 return function(...)
153 if not arg[1] then
154 if f then f() end
155 error(arg[2], 0)
156 else
157 return ...
158 end
159 end
160end
161```
162
163Again, the implementation suffers from the creation of tables at each function call, so we prefer the C version:
164```lua
165static int finalize(lua_State *L) {
166 if (!lua_toboolean(L, 1)) {
167 lua_pushvalue(L, lua_upvalueindex(1));
168 lua_pcall(L, 0, 0, 0);
169 lua_settop(L, 2);
170 lua_error(L);
171 return 0;
172 } else return lua_gettop(L);
173}
174
175static int do_nothing(lua_State *L) {
176 (void) L;
177 return 0;
178}
179
180static int newtry(lua_State *L) {
181 lua_settop(L, 1);
182 if (lua_isnil(L, 1))
183 lua_pushcfunction(L, do_nothing);
184 lua_pushcclosure(L, finalize, 1);
185 return 1;
186}
187```
188
189## Final considerations
190
191The `protect` and `newtry` functions saved a "lot" of work in the implementation of [LuaSocket](https://github.com/lunarmodules/luasocket). The size of some modules was cut in half by the these ideas. It's true the scheme is not as generic as the exception mechanism of programming languages like C++ or Java, but the power/simplicity ratio is favorable and I hope it serves you as well as it served [LuaSocket](https://github.com/lunarmodules/luasocket).
diff --git a/ltn013.wiki b/ltn013.wiki
deleted file mode 100644
index a622424..0000000
--- a/ltn013.wiki
+++ /dev/null
@@ -1,194 +0,0 @@
1===Using finalized exceptions===
2==or How to get rid of all those if statements==
3by DiegoNehab
4
5{{{
6
7}}}
8
9===Abstract===
10This little LTN describes a simple exception scheme that greatly simplifies error checking in Lua programs. All the needed functionality ships standard with Lua, but is hidden between the {{assert}} and {{pcall}} functions. To make it more evident, we stick to a convenient standard (you probably already use anyways) for Lua function return values, and define two very simple helper functions (either in C or in Lua itself).
11
12===Introduction===
13
14Most Lua functions return {{nil}} in case of error, followed by a message describing the error. If you don't use this convention, you probably have good reasons. Hopefully, after reading on, you will realize your reasons are not good enough.
15
16If you are like me, you hate error checking. Most nice little code snippets that look beautiful when you first write them lose some of their charm when you add all that error checking code. Yet, error checking is as important as the rest of the code. How sad.
17
18Even if you stick to a return convention, any complex task involving several function calls makes error checking both boring and error-prone (do you see the ''error'' below?)
19 {{{
20function task(arg1, arg2, ...)
21 local ret1, err = task1(arg1)
22 if not ret1 then
23 cleanup1()
24 return nil, error
25 end
26 local ret2, err = task2(arg2)
27 if not ret then
28 cleanup2()
29 return nil, error
30 end
31 ...
32end
33}}}
34
35The standard {{assert}} function provides an interesting alternative. To use it, simply nest every function call to be error checked with a call to {{assert}}. The {{assert}} function checks the value of its first argument. If it is {{nil}}, {{assert}} throws the second argument as an error message. Otherwise, {{assert}} lets all arguments through as if had not been there. The idea greatly simplifies error checking:
36 {{{
37function task(arg1, arg2, ...)
38 local ret1 = assert(task1(arg1))
39 local ret2 = assert(task2(arg2))
40 ...
41end
42}}}
43
44If any task fails, the execution is aborted by {{assert}} and the error message is displayed to the user as the cause of the problem. If no error happens, the task completes as before. There isn't a single {{if}} statement and this is great. However, there are some problems with the idea.
45
46First, the topmost {{task}} function doesn't respect the protocol followed by the lower-level tasks: It raises an error instead of returning {{nil}} followed by the error messages. Here is where the standard {{pcall}} comes in handy.
47 {{{
48function xtask(arg1, arg2, ...)
49 local ret1 = assert(task1(arg1))
50 local ret2 = assert(task2(arg2))
51 ...
52end
53
54function task(arg1, arg2, ...)
55 local ok, ret_or_err = pcall(xtask, arg1, arg2, ...)
56 if ok then return ret_or_err
57 else return nil, ret_or_err end
58end
59}}}
60
61Our new {{task}} function is well behaved. {{Pcall}} catches any error raised by the calls to {{assert}} and returns it after the status code. That way, errors don't get propagated to the user of the high level {{task}} function.
62
63These are the main ideas for our exception scheme, but there are still a few glitches to fix:
64
65 * Directly using {{pcall}} ruined the simplicity of the code;
66 * What happened to the cleanup function calls? What if we have to, say, close a file?
67 * {{Assert}} messes with the error message before raising the error (it adds line number information).
68
69Fortunately, all these problems are very easy to solve and that's what we do in the following sections.
70
71== Introducing the {{protect}} factory ==
72
73We 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:
74 {{{
75local function pack(ok, ...)
76 return ok, {...}
77end
78
79function protect(f)
80 return function(...)
81 local ok, ret = pack(pcall(f, ...))
82 if ok then return unpack(ret)
83 else return nil, ret[1] end
84 end
85end
86}}}
87
88The {{protect}} factory receives a function that might raise exceptions and returns a function that respects our return value convention. Now we can rewrite the top-level {{task}} function in a much cleaner way:
89 {{{
90task = protect(function(arg1, arg2, ...)
91 local ret1 = assert(task1(arg1))
92 local ret2 = assert(task2(arg2))
93 ...
94end)
95}}}
96
97The Lua implementation of the {{protect}} factory suffers with the creation of tables to hold multiple arguments and return values. It is possible (and easy) to implement the same function in C, without any table creation.
98 {{{
99static int safecall(lua_State *L) {
100 lua_pushvalue(L, lua_upvalueindex(1));
101 lua_insert(L, 1);
102 if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
103 lua_pushnil(L);
104 lua_insert(L, 1);
105 return 2;
106 } else return lua_gettop(L);
107}
108
109static int protect(lua_State *L) {
110 lua_pushcclosure(L, safecall, 1);
111 return 1;
112}
113}}}
114
115===The {{newtry}} factory===
116
117Let's solve the two remaining issues with a single shot and use a concrete example to illustrate the proposed solution. Suppose you want to write a function to download an HTTP document. You have to connect, send the request and read the reply. Each of these tasks can fail, but if something goes wrong after you connected, you have to close the connection before returning the error message.
118 {{{
119get = protect(function(host, path)
120 local c
121 -- create a try function with a finalizer to close the socket
122 local try = newtry(function()
123 if c then c:close() end
124 end)
125 -- connect and send request
126 c = try(connect(host, 80))
127 try(c:send("GET " .. path .. " HTTP/1.0\r\n\r\n"))
128 -- get headers
129 local h = {}
130 while 1 do
131 l = try(c:receive())
132 if l == "" then break end
133 table.insert(h, l)
134 end
135 -- get body
136 local b = try(c:receive("*a"))
137 c:close()
138 return b, h
139end)
140}}}
141
142The {{newtry}} factory returns a function that works just like {{assert}}. The differences are that the {{try}} function doesn't mess with the error message and it calls an optional ''finalizer'' before raising the error. In our example, the finalizer simply closes the socket.
143
144Even with a simple example like this, we see that the finalized exceptions simplified our life. Let's see what we gain in general, not just in this example:
145
146 * We don't need to declare dummy variables to hold error messages in case any ever shows up;
147 * We avoid using a variable to hold something that could either be a return value or an error message;
148 * We didn't have to use several ''if'' statements to check for errors;
149 * If an error happens, we know our finalizer is going to be invoked automatically;
150 * Exceptions get propagated, so we don't repeat these ''if'' statements until the error reaches the user.
151
152Try writing the same function without the tricks we used above and you will see that the code gets ugly. Longer sequences of operations with error checking would get even uglier. So let's implement the {{newtry}} function in Lua:
153 {{{
154function newtry(f)
155 return function(...)
156 if not arg[1] then
157 if f then f() end
158 error(arg[2], 0)
159 else
160 return ...
161 end
162 end
163end
164}}}
165
166Again, the implementation suffers from the creation of tables at each function call, so we prefer the C version:
167 {{{
168static int finalize(lua_State *L) {
169 if (!lua_toboolean(L, 1)) {
170 lua_pushvalue(L, lua_upvalueindex(1));
171 lua_pcall(L, 0, 0, 0);
172 lua_settop(L, 2);
173 lua_error(L);
174 return 0;
175 } else return lua_gettop(L);
176}
177
178static int do_nothing(lua_State *L) {
179 (void) L;
180 return 0;
181}
182
183static int newtry(lua_State *L) {
184 lua_settop(L, 1);
185 if (lua_isnil(L, 1))
186 lua_pushcfunction(L, do_nothing);
187 lua_pushcclosure(L, finalize, 1);
188 return 1;
189}
190}}}
191
192===Final considerations===
193
194The {{protect}} and {{newtry}} functions saved a ''lot'' of work in the implementation of {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket]. The size of some modules was cut in half by the these ideas. It's true the scheme is not as generic as the exception mechanism of programming languages like C++ or Java, but the power/simplicity ratio is favorable and I hope it serves you as well as it served {{LuaSocket}}.
diff --git a/luasocket-scm-0.rockspec b/luasocket-scm-0.rockspec
deleted file mode 100644
index 352a497..0000000
--- a/luasocket-scm-0.rockspec
+++ /dev/null
@@ -1,101 +0,0 @@
1package = "LuaSocket"
2version = "scm-0"
3source = {
4 url = "https://github.com/diegonehab/luasocket/archive/master.zip",
5 dir = "luasocket-master",
6}
7description = {
8 summary = "Network support for the Lua language",
9 detailed = [[
10 LuaSocket is a Lua extension library that is composed by two parts: a C core
11 that provides support for the TCP and UDP transport layers, and a set of Lua
12 modules that add support for functionality commonly needed by applications
13 that deal with the Internet.
14 ]],
15 homepage = "http://luaforge.net/projects/luasocket/",
16 license = "MIT"
17}
18dependencies = {
19 "lua >= 5.1"
20}
21
22local function make_plat(plat)
23 local defines = {
24 unix = {
25 "LUASOCKET_DEBUG",
26 "LUASOCKET_API=__attribute__((visibility(\"default\")))",
27 "UNIX_API=__attribute__((visibility(\"default\")))",
28 "MIME_API=__attribute__((visibility(\"default\")))"
29 },
30 macosx = {
31 "LUASOCKET_DEBUG",
32 "UNIX_HAS_SUN_LEN",
33 "LUASOCKET_API=__attribute__((visibility(\"default\")))",
34 "UNIX_API=__attribute__((visibility(\"default\")))",
35 "MIME_API=__attribute__((visibility(\"default\")))"
36 },
37 win32 = {
38 "LUASOCKET_DEBUG",
39 "NDEBUG",
40 "LUASOCKET_API=__declspec(dllexport)",
41 "MIME_API=__declspec(dllexport)"
42 },
43 mingw32 = {
44 "LUASOCKET_DEBUG",
45 "LUASOCKET_INET_PTON",
46 "WINVER=0x0501",
47 "LUASOCKET_API=__declspec(dllexport)",
48 "MIME_API=__declspec(dllexport)"
49 }
50 }
51 local modules = {
52 ["socket.core"] = {
53 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" },
54 defines = defines[plat],
55 incdir = "/src"
56 },
57 ["mime.core"] = {
58 sources = { "src/mime.c", "src/compat.c" },
59 defines = defines[plat],
60 incdir = "/src"
61 },
62 ["socket.http"] = "src/http.lua",
63 ["socket.url"] = "src/url.lua",
64 ["socket.tp"] = "src/tp.lua",
65 ["socket.ftp"] = "src/ftp.lua",
66 ["socket.headers"] = "src/headers.lua",
67 ["socket.smtp"] = "src/smtp.lua",
68 ltn12 = "src/ltn12.lua",
69 socket = "src/socket.lua",
70 mime = "src/mime.lua"
71 }
72 if plat == "unix" or plat == "macosx" then
73 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
74 modules["socket.unix"] = {
75 sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/unix.c" },
76 defines = defines[plat],
77 incdir = "/src"
78 }
79 modules["socket.serial"] = {
80 sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/serial.c" },
81 defines = defines[plat],
82 incdir = "/src"
83 }
84 end
85 if plat == "win32" or plat == "mingw32" then
86 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
87 modules["socket.core"].libraries = { "ws2_32" }
88 end
89 return { modules = modules }
90end
91
92build = {
93 type = "builtin",
94 platforms = {
95 unix = make_plat("unix"),
96 macosx = make_plat("macosx"),
97 win32 = make_plat("win32"),
98 mingw32 = make_plat("mingw32")
99 },
100 copy_directories = { "doc", "samples", "etc", "test" }
101}
diff --git a/luasocket-scm-3.rockspec b/luasocket-scm-3.rockspec
new file mode 100644
index 0000000..5a5f7b5
--- /dev/null
+++ b/luasocket-scm-3.rockspec
@@ -0,0 +1,134 @@
1package = "LuaSocket"
2version = "scm-3"
3source = {
4 url = "git+https://github.com/lunarmodules/luasocket.git",
5 branch = "master"
6}
7description = {
8 summary = "Network support for the Lua language",
9 detailed = [[
10 LuaSocket is a Lua extension library composed of two parts: a set of C
11 modules that provide support for the TCP and UDP transport layers, and a
12 set of Lua modules that provide functions commonly needed by applications
13 that deal with the Internet.
14 ]],
15 homepage = "https://github.com/lunarmodules/luasocket",
16 license = "MIT"
17}
18dependencies = {
19 "lua >= 5.1"
20}
21
22local function make_plat(plat)
23 local defines = {
24 unix = {
25 "LUASOCKET_DEBUG"
26 },
27 macosx = {
28 "LUASOCKET_DEBUG",
29 "UNIX_HAS_SUN_LEN"
30 },
31 win32 = {
32 "LUASOCKET_DEBUG",
33 "NDEBUG"
34 },
35 mingw32 = {
36 "LUASOCKET_DEBUG",
37 -- "LUASOCKET_INET_PTON",
38 "WINVER=0x0501"
39 }
40 }
41 local modules = {
42 ["socket.core"] = {
43 sources = {
44 "src/luasocket.c"
45 , "src/timeout.c"
46 , "src/buffer.c"
47 , "src/io.c"
48 , "src/auxiliar.c"
49 , "src/options.c"
50 , "src/inet.c"
51 , "src/except.c"
52 , "src/select.c"
53 , "src/tcp.c"
54 , "src/udp.c"
55 , "src/compat.c" },
56 defines = defines[plat],
57 incdir = "/src"
58 },
59 ["mime.core"] = {
60 sources = { "src/mime.c", "src/compat.c" },
61 defines = defines[plat],
62 incdir = "/src"
63 },
64 ["socket.http"] = "src/http.lua",
65 ["socket.url"] = "src/url.lua",
66 ["socket.tp"] = "src/tp.lua",
67 ["socket.ftp"] = "src/ftp.lua",
68 ["socket.headers"] = "src/headers.lua",
69 ["socket.smtp"] = "src/smtp.lua",
70 ltn12 = "src/ltn12.lua",
71 socket = "src/socket.lua",
72 mime = "src/mime.lua"
73 }
74 if plat == "unix"
75 or plat == "macosx"
76 or plat == "haiku"
77 then
78 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
79 if plat == "haiku" then
80 modules["socket.core"].libraries = {"network"}
81 end
82 modules["socket.unix"] = {
83 sources = {
84 "src/buffer.c"
85 , "src/compat.c"
86 , "src/auxiliar.c"
87 , "src/options.c"
88 , "src/timeout.c"
89 , "src/io.c"
90 , "src/usocket.c"
91 , "src/unix.c"
92 , "src/unixdgram.c"
93 , "src/unixstream.c" },
94 defines = defines[plat],
95 incdir = "/src"
96 }
97 modules["socket.serial"] = {
98 sources = {
99 "src/buffer.c"
100 , "src/compat.c"
101 , "src/auxiliar.c"
102 , "src/options.c"
103 , "src/timeout.c"
104 , "src/io.c"
105 , "src/usocket.c"
106 , "src/serial.c" },
107 defines = defines[plat],
108 incdir = "/src"
109 }
110 end
111 if plat == "win32"
112 or plat == "mingw32"
113 then
114 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
115 modules["socket.core"].libraries = { "ws2_32" }
116 modules["socket.core"].libdirs = {}
117 end
118 return { modules = modules }
119end
120
121build = {
122 type = "builtin",
123 platforms = {
124 unix = make_plat("unix"),
125 macosx = make_plat("macosx"),
126 haiku = make_plat("haiku"),
127 win32 = make_plat("win32"),
128 mingw32 = make_plat("mingw32")
129 },
130 copy_directories = {
131 "docs"
132 , "samples"
133 , "test" }
134}
diff --git a/macosx.cmd b/macosx.cmd
index 46a0709..dd5d8cf 100644
--- a/macosx.cmd
+++ b/macosx.cmd
@@ -1 +1 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/diego/build/macosx/include LUAPREFIX_macosx=/Users/diego/build/macosx install-both make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/$USER/build/macosx/include LUAPREFIX_macosx=/Users/$USER/build/macosx install-both
diff --git a/makefile b/makefile
index e34f5a9..63d9985 100644..100755
--- a/makefile
+++ b/makefile
@@ -10,7 +10,7 @@
10# print print the build settings 10# print print the build settings
11 11
12PLAT?= linux 12PLAT?= linux
13PLATS= macosx linux win32 mingw freebsd 13PLATS= macosx linux win32 win64 mingw freebsd solaris
14 14
15all: $(PLAT) 15all: $(PLAT)
16 16
@@ -33,6 +33,9 @@ install-both:
33 $(MAKE) clean 33 $(MAKE) clean
34 @cd src; $(MAKE) $(PLAT) LUAV=5.3 34 @cd src; $(MAKE) $(PLAT) LUAV=5.3
35 @cd src; $(MAKE) install LUAV=5.3 35 @cd src; $(MAKE) install LUAV=5.3
36 $(MAKE) clean
37 @cd src; $(MAKE) $(PLAT) LUAV=5.4
38 @cd src; $(MAKE) install LUAV=5.4
36 39
37install-both-unix: 40install-both-unix:
38 $(MAKE) clean 41 $(MAKE) clean
@@ -44,6 +47,9 @@ install-both-unix:
44 $(MAKE) clean 47 $(MAKE) clean
45 @cd src; $(MAKE) $(PLAT) LUAV=5.3 48 @cd src; $(MAKE) $(PLAT) LUAV=5.3
46 @cd src; $(MAKE) install-unix LUAV=5.3 49 @cd src; $(MAKE) install-unix LUAV=5.3
50 $(MAKE) clean
51 @cd src; $(MAKE) $(PLAT) LUAV=5.4
52 @cd src; $(MAKE) install-unix LUAV=5.4
47 53
48.PHONY: test 54.PHONY: test
49 55
diff --git a/makefile.dist b/makefile.dist
index 45a8866..5ef44d3 100644
--- a/makefile.dist
+++ b/makefile.dist
@@ -1,7 +1,7 @@
1#-------------------------------------------------------------------------- 1#--------------------------------------------------------------------------
2# Distribution makefile 2# Distribution makefile
3#-------------------------------------------------------------------------- 3#--------------------------------------------------------------------------
4DIST = luasocket-3.0-rc1 4DIST = luasocket-3.0.0
5 5
6TEST = \ 6TEST = \
7 test/README \ 7 test/README \
@@ -22,20 +22,17 @@ SAMPLES = \
22 samples/lpr.lua \ 22 samples/lpr.lua \
23 samples/talker.lua \ 23 samples/talker.lua \
24 samples/tinyirc.lua 24 samples/tinyirc.lua
25 25 samples/b64.lua \
26ETC = \ 26 samples/check-links.lua \
27 etc/README \ 27 samples/check-memory.lua \
28 etc/b64.lua \ 28 samples/dict.lua \
29 etc/check-links.lua \ 29 samples/dispatch.lua \
30 etc/check-memory.lua \ 30 samples/eol.lua \
31 etc/dict.lua \ 31 samples/forward.lua \
32 etc/dispatch.lua \ 32 samples/get.lua \
33 etc/eol.lua \ 33 samples/lp.lua \
34 etc/forward.lua \ 34 samples/qp.lua \
35 etc/get.lua \ 35 samples/tftp.lua
36 etc/lp.lua \
37 etc/qp.lua \
38 etc/tftp.lua
39 36
40SRC = \ 37SRC = \
41 src/makefile \ 38 src/makefile \
@@ -92,39 +89,36 @@ MAKE = \
92 socket.vcxproj \ 89 socket.vcxproj \
93 mime.vcxproj 90 mime.vcxproj
94 91
95DOC = \ 92DOCS = \
96 doc/dns.html \ 93 docs/dns.html \
97 doc/ftp.html \ 94 docs/ftp.html \
98 doc/index.html \ 95 docs/index.html \
99 doc/http.html \ 96 docs/http.html \
100 doc/installation.html \ 97 docs/installation.html \
101 doc/introduction.html \ 98 docs/introduction.html \
102 doc/ltn12.html \ 99 docs/ltn12.html \
103 doc/luasocket.png \ 100 docs/luasocket.png \
104 doc/mime.html \ 101 docs/mime.html \
105 doc/reference.css \ 102 docs/reference.css \
106 doc/reference.html \ 103 docs/reference.html \
107 doc/smtp.html \ 104 docs/smtp.html \
108 doc/socket.html \ 105 docs/socket.html \
109 doc/tcp.html \ 106 docs/tcp.html \
110 doc/udp.html \ 107 docs/udp.html \
111 doc/url.html 108 docs/url.html
112 109
113dist: 110dist:
114 mkdir -p $(DIST) 111 mkdir -p $(DIST)
115 cp -vf NEW $(DIST) 112 cp -vf CHANGELOG.md $(DIST)
116 cp -vf LICENSE $(DIST) 113 cp -vf LICENSE $(DIST)
117 cp -vf README $(DIST) 114 cp -vf README.md $(DIST)
118 cp -vf $(MAKE) $(DIST) 115 cp -vf $(MAKE) $(DIST)
119 116
120 mkdir -p $(DIST)/etc
121 cp -vf $(ETC) $(DIST)/etc
122
123 mkdir -p $(DIST)/src 117 mkdir -p $(DIST)/src
124 cp -vf $(SRC) $(DIST)/src 118 cp -vf $(SRC) $(DIST)/src
125 119
126 mkdir -p $(DIST)/doc 120 mkdir -p $(DIST)/docs
127 cp -vf $(DOC) $(DIST)/doc 121 cp -vf $(DOCS) $(DIST)/docs
128 122
129 mkdir -p $(DIST)/samples 123 mkdir -p $(DIST)/samples
130 cp -vf $(SAMPLES) $(DIST)/samples 124 cp -vf $(SAMPLES) $(DIST)/samples
diff --git a/mime.vcxproj b/mime.vcxproj
index c77d611..575f985 100755
--- a/mime.vcxproj
+++ b/mime.vcxproj
@@ -1,5 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup Label="ProjectConfigurations"> 3 <ItemGroup Label="ProjectConfigurations">
4 <ProjectConfiguration Include="Debug|Win32"> 4 <ProjectConfiguration Include="Debug|Win32">
5 <Configuration>Debug</Configuration> 5 <Configuration>Debug</Configuration>
@@ -20,19 +20,7 @@
20 </ItemGroup> 20 </ItemGroup>
21 <ItemGroup> 21 <ItemGroup>
22 <ClCompile Include="src\mime.c" /> 22 <ClCompile Include="src\mime.c" />
23 </ItemGroup> 23 <ClCompile Include="src\compat.c" />
24 <ItemGroup>
25 <CustomBuild Include="src\mime.lua">
26 <FileType>Document</FileType>
27 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
28 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
29 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
30 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
31 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
32 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
33 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
34 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
35 </CustomBuild>
36 </ItemGroup> 24 </ItemGroup>
37 <PropertyGroup Label="Globals"> 25 <PropertyGroup Label="Globals">
38 <ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid> 26 <ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>
@@ -41,22 +29,22 @@
41 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 29 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
42 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> 30 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
43 <ConfigurationType>DynamicLibrary</ConfigurationType> 31 <ConfigurationType>DynamicLibrary</ConfigurationType>
44 <PlatformToolset>v110</PlatformToolset> 32 <PlatformToolset>v141</PlatformToolset>
45 <CharacterSet>MultiByte</CharacterSet> 33 <CharacterSet>MultiByte</CharacterSet>
46 </PropertyGroup> 34 </PropertyGroup>
47 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> 35 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
48 <ConfigurationType>DynamicLibrary</ConfigurationType> 36 <ConfigurationType>DynamicLibrary</ConfigurationType>
49 <PlatformToolset>v110</PlatformToolset> 37 <PlatformToolset>v141</PlatformToolset>
50 <CharacterSet>MultiByte</CharacterSet> 38 <CharacterSet>MultiByte</CharacterSet>
51 </PropertyGroup> 39 </PropertyGroup>
52 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> 40 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
53 <ConfigurationType>DynamicLibrary</ConfigurationType> 41 <ConfigurationType>DynamicLibrary</ConfigurationType>
54 <PlatformToolset>v110</PlatformToolset> 42 <PlatformToolset>v141</PlatformToolset>
55 <CharacterSet>MultiByte</CharacterSet> 43 <CharacterSet>MultiByte</CharacterSet>
56 </PropertyGroup> 44 </PropertyGroup>
57 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> 45 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
58 <ConfigurationType>DynamicLibrary</ConfigurationType> 46 <ConfigurationType>DynamicLibrary</ConfigurationType>
59 <PlatformToolset>v110</PlatformToolset> 47 <PlatformToolset>v141</PlatformToolset>
60 <CharacterSet>MultiByte</CharacterSet> 48 <CharacterSet>MultiByte</CharacterSet>
61 </PropertyGroup> 49 </PropertyGroup>
62 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 50 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -87,7 +75,7 @@
87 <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> 75 <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
88 </PropertyGroup> 76 </PropertyGroup>
89 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 77 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
90 <OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir> 78 <OutDir>$(Configuration)\mime\</OutDir>
91 <IntDir>$(Configuration)\</IntDir> 79 <IntDir>$(Configuration)\</IntDir>
92 <LinkIncremental>true</LinkIncremental> 80 <LinkIncremental>true</LinkIncremental>
93 <TargetName>core</TargetName> 81 <TargetName>core</TargetName>
@@ -95,23 +83,23 @@
95 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> 83 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
96 <LinkIncremental>true</LinkIncremental> 84 <LinkIncremental>true</LinkIncremental>
97 <TargetName>core</TargetName> 85 <TargetName>core</TargetName>
98 <OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir> 86 <OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
99 </PropertyGroup> 87 </PropertyGroup>
100 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 88 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
101 <OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir> 89 <OutDir>$(Configuration)\mime\</OutDir>
102 <IntDir>$(Configuration)\</IntDir> 90 <IntDir>$(Configuration)\</IntDir>
103 <LinkIncremental>false</LinkIncremental> 91 <LinkIncremental>false</LinkIncremental>
104 <TargetName>core</TargetName> 92 <TargetName>core</TargetName>
105 </PropertyGroup> 93 </PropertyGroup>
106 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> 94 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
107 <LinkIncremental>false</LinkIncremental> 95 <LinkIncremental>false</LinkIncremental>
108 <OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir> 96 <OutDir>$(Platform)\$(Configuration)\mime\</OutDir>
109 <TargetName>core</TargetName> 97 <TargetName>core</TargetName>
110 </PropertyGroup> 98 </PropertyGroup>
111 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 99 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
112 <ClCompile> 100 <ClCompile>
113 <Optimization>Disabled</Optimization> 101 <Optimization>Disabled</Optimization>
114 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 102 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
115 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 103 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
116 <MinimalRebuild>true</MinimalRebuild> 104 <MinimalRebuild>true</MinimalRebuild>
117 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 105 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@@ -122,9 +110,9 @@
122 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 110 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
123 </ClCompile> 111 </ClCompile>
124 <Link> 112 <Link>
125 <AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies> 113 <AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
126 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 114 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
127 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 115 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
128 <GenerateDebugInformation>true</GenerateDebugInformation> 116 <GenerateDebugInformation>true</GenerateDebugInformation>
129 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile> 117 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
130 <SubSystem>Windows</SubSystem> 118 <SubSystem>Windows</SubSystem>
@@ -138,7 +126,7 @@
138 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> 126 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
139 <ClCompile> 127 <ClCompile>
140 <Optimization>Disabled</Optimization> 128 <Optimization>Disabled</Optimization>
141 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 129 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
142 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 130 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
143 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 131 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
144 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 132 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -149,9 +137,9 @@
149 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 137 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
150 </ClCompile> 138 </ClCompile>
151 <Link> 139 <Link>
152 <AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies> 140 <AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
153 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 141 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
154 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 142 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
155 <GenerateDebugInformation>true</GenerateDebugInformation> 143 <GenerateDebugInformation>true</GenerateDebugInformation>
156 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile> 144 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
157 <SubSystem>Windows</SubSystem> 145 <SubSystem>Windows</SubSystem>
@@ -163,7 +151,7 @@
163 </ItemDefinitionGroup> 151 </ItemDefinitionGroup>
164 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 152 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
165 <ClCompile> 153 <ClCompile>
166 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 154 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
167 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 155 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
168 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 156 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
169 <PrecompiledHeader /> 157 <PrecompiledHeader />
@@ -172,9 +160,9 @@
172 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 160 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
173 </ClCompile> 161 </ClCompile>
174 <Link> 162 <Link>
175 <AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies> 163 <AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
176 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 164 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
177 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 165 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
178 <GenerateDebugInformation>true</GenerateDebugInformation> 166 <GenerateDebugInformation>true</GenerateDebugInformation>
179 <SubSystem>Windows</SubSystem> 167 <SubSystem>Windows</SubSystem>
180 <OptimizeReferences>true</OptimizeReferences> 168 <OptimizeReferences>true</OptimizeReferences>
@@ -187,7 +175,7 @@
187 </ItemDefinitionGroup> 175 </ItemDefinitionGroup>
188 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> 176 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
189 <ClCompile> 177 <ClCompile>
190 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 178 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
191 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 179 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
192 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 180 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
193 <PrecompiledHeader> 181 <PrecompiledHeader>
@@ -198,9 +186,9 @@
198 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 186 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
199 </ClCompile> 187 </ClCompile>
200 <Link> 188 <Link>
201 <AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies> 189 <AdditionalDependencies>$(LUALIBNAME);%(AdditionalDependencies)</AdditionalDependencies>
202 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 190 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
203 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 191 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
204 <GenerateDebugInformation>true</GenerateDebugInformation> 192 <GenerateDebugInformation>true</GenerateDebugInformation>
205 <SubSystem>Windows</SubSystem> 193 <SubSystem>Windows</SubSystem>
206 <OptimizeReferences>true</OptimizeReferences> 194 <OptimizeReferences>true</OptimizeReferences>
diff --git a/mime.vcxproj.filters b/mime.vcxproj.filters
deleted file mode 100644
index 621215b..0000000
--- a/mime.vcxproj.filters
+++ /dev/null
@@ -1,16 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup>
4 <ClCompile Include="src\mime.c" />
5 </ItemGroup>
6 <ItemGroup>
7 <Filter Include="cdir">
8 <UniqueIdentifier>{fad87a86-297c-4881-a114-73b967bb3c92}</UniqueIdentifier>
9 </Filter>
10 </ItemGroup>
11 <ItemGroup>
12 <CustomBuild Include="src\mime.lua">
13 <Filter>cdir</Filter>
14 </CustomBuild>
15 </ItemGroup>
16</Project> \ No newline at end of file
diff --git a/rockspecs/luasocket-3.0.0-1.rockspec b/rockspecs/luasocket-3.0.0-1.rockspec
new file mode 100644
index 0000000..4cf4acf
--- /dev/null
+++ b/rockspecs/luasocket-3.0.0-1.rockspec
@@ -0,0 +1,134 @@
1package = "LuaSocket"
2version = "3.0.0-1"
3source = {
4 url = "git+https://github.com/lunarmodules/luasocket.git",
5 tag = "v3.0.0"
6}
7description = {
8 summary = "Network support for the Lua language",
9 detailed = [[
10 LuaSocket is a Lua extension library composed of two parts: a set of C
11 modules that provide support for the TCP and UDP transport layers, and a
12 set of Lua modules that provide functions commonly needed by applications
13 that deal with the Internet.
14 ]],
15 homepage = "https://github.com/lunarmodules/luasocket",
16 license = "MIT"
17}
18dependencies = {
19 "lua >= 5.1"
20}
21
22local function make_plat(plat)
23 local defines = {
24 unix = {
25 "LUASOCKET_DEBUG"
26 },
27 macosx = {
28 "LUASOCKET_DEBUG",
29 "UNIX_HAS_SUN_LEN"
30 },
31 win32 = {
32 "LUASOCKET_DEBUG",
33 "NDEBUG"
34 },
35 mingw32 = {
36 "LUASOCKET_DEBUG",
37 "LUASOCKET_INET_PTON",
38 "WINVER=0x0501"
39 }
40 }
41 local modules = {
42 ["socket.core"] = {
43 sources = {
44 "src/luasocket.c"
45 , "src/timeout.c"
46 , "src/buffer.c"
47 , "src/io.c"
48 , "src/auxiliar.c"
49 , "src/options.c"
50 , "src/inet.c"
51 , "src/except.c"
52 , "src/select.c"
53 , "src/tcp.c"
54 , "src/udp.c"
55 , "src/compat.c" },
56 defines = defines[plat],
57 incdir = "/src"
58 },
59 ["mime.core"] = {
60 sources = { "src/mime.c", "src/compat.c" },
61 defines = defines[plat],
62 incdir = "/src"
63 },
64 ["socket.http"] = "src/http.lua",
65 ["socket.url"] = "src/url.lua",
66 ["socket.tp"] = "src/tp.lua",
67 ["socket.ftp"] = "src/ftp.lua",
68 ["socket.headers"] = "src/headers.lua",
69 ["socket.smtp"] = "src/smtp.lua",
70 ltn12 = "src/ltn12.lua",
71 socket = "src/socket.lua",
72 mime = "src/mime.lua"
73 }
74 if plat == "unix"
75 or plat == "macosx"
76 or plat == "haiku"
77 then
78 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
79 if plat == "haiku" then
80 modules["socket.core"].libraries = {"network"}
81 end
82 modules["socket.unix"] = {
83 sources = {
84 "src/buffer.c"
85 , "src/compat.c"
86 , "src/auxiliar.c"
87 , "src/options.c"
88 , "src/timeout.c"
89 , "src/io.c"
90 , "src/usocket.c"
91 , "src/unix.c"
92 , "src/unixdgram.c"
93 , "src/unixstream.c" },
94 defines = defines[plat],
95 incdir = "/src"
96 }
97 modules["socket.serial"] = {
98 sources = {
99 "src/buffer.c"
100 , "src/compat.c"
101 , "src/auxiliar.c"
102 , "src/options.c"
103 , "src/timeout.c"
104 , "src/io.c"
105 , "src/usocket.c"
106 , "src/serial.c" },
107 defines = defines[plat],
108 incdir = "/src"
109 }
110 end
111 if plat == "win32"
112 or plat == "mingw32"
113 then
114 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
115 modules["socket.core"].libraries = { "ws2_32" }
116 end
117 return { modules = modules }
118end
119
120build = {
121 type = "builtin",
122 platforms = {
123 unix = make_plat("unix"),
124 macosx = make_plat("macosx"),
125 haiku = make_plat("haiku"),
126 win32 = make_plat("win32"),
127 mingw32 = make_plat("mingw32")
128 },
129 copy_directories = {
130 "docs"
131 , "samples"
132 , "etc"
133 , "test" }
134}
diff --git a/rockspecs/luasocket-3.0rc1-2.rockspec b/rockspecs/luasocket-3.0rc1-2.rockspec
new file mode 100644
index 0000000..3cb6524
--- /dev/null
+++ b/rockspecs/luasocket-3.0rc1-2.rockspec
@@ -0,0 +1,108 @@
1package = "LuaSocket"
2version = "3.0rc1-2"
3source = {
4 url = "https://github.com/diegonehab/luasocket/archive/v3.0-rc1.zip",
5 dir = "luasocket-3.0-rc1",
6}
7description = {
8 summary = "Network support for the Lua language",
9 detailed = [[
10 LuaSocket is a Lua extension library that is composed by two parts: a C core
11 that provides support for the TCP and UDP transport layers, and a set of Lua
12 modules that add support for functionality commonly needed by applications
13 that deal with the Internet.
14 ]],
15 homepage = "http://luaforge.net/projects/luasocket/",
16 license = "MIT"
17}
18dependencies = {
19 "lua >= 5.1"
20}
21
22local function make_plat(plat)
23 local defines = {
24 unix = {
25 "LUA_COMPAT_APIINTCASTS",
26 "LUASOCKET_DEBUG",
27 "LUASOCKET_API=__attribute__((visibility(\"default\")))",
28 "UNIX_API=__attribute__((visibility(\"default\")))",
29 "MIME_API=__attribute__((visibility(\"default\")))"
30 },
31 macosx = {
32 "LUA_COMPAT_APIINTCASTS",
33 "LUASOCKET_DEBUG",
34 "UNIX_HAS_SUN_LEN",
35 "LUASOCKET_API=__attribute__((visibility(\"default\")))",
36 "UNIX_API=__attribute__((visibility(\"default\")))",
37 "MIME_API=__attribute__((visibility(\"default\")))"
38 },
39 win32 = {
40 "LUA_COMPAT_APIINTCASTS",
41 "LUASOCKET_DEBUG",
42 "NDEBUG",
43 "LUASOCKET_API=__declspec(dllexport)",
44 "MIME_API=__declspec(dllexport)"
45 },
46 mingw32 = {
47 "LUA_COMPAT_APIINTCASTS",
48 "LUASOCKET_DEBUG",
49 "LUASOCKET_INET_PTON",
50 "WINVER=0x0501",
51 "LUASOCKET_API=__declspec(dllexport)",
52 "MIME_API=__declspec(dllexport)"
53 }
54 }
55 local modules = {
56 ["socket.core"] = {
57 sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c",
58 "src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c" },
59 defines = defines[plat],
60 incdir = "src"
61 },
62 ["mime.core"] = {
63 sources = { "src/mime.c" },
64 defines = defines[plat],
65 incdir = "src"
66 },
67 ["socket.http"] = "src/http.lua",
68 ["socket.url"] = "src/url.lua",
69 ["socket.tp"] = "src/tp.lua",
70 ["socket.ftp"] = "src/ftp.lua",
71 ["socket.headers"] = "src/headers.lua",
72 ["socket.smtp"] = "src/smtp.lua",
73 ltn12 = "src/ltn12.lua",
74 socket = "src/socket.lua",
75 mime = "src/mime.lua"
76 }
77 if plat == "unix" or plat == "macosx" then
78 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
79 modules["socket.unix"] = {
80 sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c",
81 "src/usocket.c", "src/unix.c" },
82 defines = defines[plat],
83 incdir = "/src"
84 }
85 modules["socket.serial"] = {
86 sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c",
87 "src/io.c", "src/usocket.c", "src/serial.c" },
88 defines = defines[plat],
89 incdir = "/src"
90 }
91 end
92 if plat == "win32" or plat == "mingw32" then
93 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
94 modules["socket.core"].libraries = { "ws2_32" }
95 end
96 return { modules = modules }
97end
98
99build = {
100 type = "builtin",
101 platforms = {
102 unix = make_plat("unix"),
103 macosx = make_plat("macosx"),
104 win32 = make_plat("win32"),
105 mingw32 = make_plat("mingw32")
106 },
107 copy_directories = { "doc", "samples", "etc", "test" }
108}
diff --git a/rockspecs/luasocket-3.1.0-1.rockspec b/rockspecs/luasocket-3.1.0-1.rockspec
new file mode 100644
index 0000000..2d724ac
--- /dev/null
+++ b/rockspecs/luasocket-3.1.0-1.rockspec
@@ -0,0 +1,135 @@
1package = "LuaSocket"
2version = "3.1.0-1"
3source = {
4 url = "git+https://github.com/lunarmodules/luasocket.git",
5 tag = "v3.1.0"
6}
7description = {
8 summary = "Network support for the Lua language",
9 detailed = [[
10 LuaSocket is a Lua extension library composed of two parts: a set of C
11 modules that provide support for the TCP and UDP transport layers, and a
12 set of Lua modules that provide functions commonly needed by applications
13 that deal with the Internet.
14 ]],
15 homepage = "https://github.com/lunarmodules/luasocket",
16 license = "MIT"
17}
18dependencies = {
19 "lua >= 5.1"
20}
21
22local function make_plat(plat)
23 local defines = {
24 unix = {
25 "LUASOCKET_DEBUG"
26 },
27 macosx = {
28 "LUASOCKET_DEBUG",
29 "UNIX_HAS_SUN_LEN"
30 },
31 win32 = {
32 "LUASOCKET_DEBUG",
33 "NDEBUG"
34 },
35 mingw32 = {
36 "LUASOCKET_DEBUG",
37 -- "LUASOCKET_INET_PTON",
38 "WINVER=0x0501"
39 }
40 }
41 local modules = {
42 ["socket.core"] = {
43 sources = {
44 "src/luasocket.c"
45 , "src/timeout.c"
46 , "src/buffer.c"
47 , "src/io.c"
48 , "src/auxiliar.c"
49 , "src/options.c"
50 , "src/inet.c"
51 , "src/except.c"
52 , "src/select.c"
53 , "src/tcp.c"
54 , "src/udp.c"
55 , "src/compat.c" },
56 defines = defines[plat],
57 incdir = "/src"
58 },
59 ["mime.core"] = {
60 sources = { "src/mime.c", "src/compat.c" },
61 defines = defines[plat],
62 incdir = "/src"
63 },
64 ["socket.http"] = "src/http.lua",
65 ["socket.url"] = "src/url.lua",
66 ["socket.tp"] = "src/tp.lua",
67 ["socket.ftp"] = "src/ftp.lua",
68 ["socket.headers"] = "src/headers.lua",
69 ["socket.smtp"] = "src/smtp.lua",
70 ltn12 = "src/ltn12.lua",
71 socket = "src/socket.lua",
72 mime = "src/mime.lua"
73 }
74 if plat == "unix"
75 or plat == "macosx"
76 or plat == "haiku"
77 then
78 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
79 if plat == "haiku" then
80 modules["socket.core"].libraries = {"network"}
81 end
82 modules["socket.unix"] = {
83 sources = {
84 "src/buffer.c"
85 , "src/compat.c"
86 , "src/auxiliar.c"
87 , "src/options.c"
88 , "src/timeout.c"
89 , "src/io.c"
90 , "src/usocket.c"
91 , "src/unix.c"
92 , "src/unixdgram.c"
93 , "src/unixstream.c" },
94 defines = defines[plat],
95 incdir = "/src"
96 }
97 modules["socket.serial"] = {
98 sources = {
99 "src/buffer.c"
100 , "src/compat.c"
101 , "src/auxiliar.c"
102 , "src/options.c"
103 , "src/timeout.c"
104 , "src/io.c"
105 , "src/usocket.c"
106 , "src/serial.c" },
107 defines = defines[plat],
108 incdir = "/src"
109 }
110 end
111 if plat == "win32"
112 or plat == "mingw32"
113 then
114 modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
115 modules["socket.core"].libraries = { "ws2_32" }
116 modules["socket.core"].libdirs = {}
117 end
118 return { modules = modules }
119end
120
121build = {
122 type = "builtin",
123 platforms = {
124 unix = make_plat("unix"),
125 macosx = make_plat("macosx"),
126 haiku = make_plat("haiku"),
127 win32 = make_plat("win32"),
128 mingw32 = make_plat("mingw32")
129 },
130 copy_directories = {
131 "docs"
132 , "samples"
133 , "etc"
134 , "test" }
135}
diff --git a/samples/README b/samples/README
index e63a6f5..4ee06b6 100644
--- a/samples/README
+++ b/samples/README
@@ -1,11 +1,95 @@
1This directory contains some sample programs using 1This directory contains some sample programs using
2LuaSocket. This code is not supported. 2LuaSocket. This code is not supported.
3 3
4 tftp.lua -- Trivial FTP client
5
6This module implements file retrieval by the TFTP protocol.
7Its main use was to test the UDP code, but since someone
8found it usefull, I turned it into a module that is almost
9official (no uploads, yet).
10
11 dict.lua -- Dict client
12
13The dict.lua module started with a cool simple client
14for the DICT protocol, written by Luiz Henrique Figueiredo.
15This new version has been converted into a library, similar
16to the HTTP and FTP libraries, that can be used from within
17any luasocket application. Take a look on the source code
18and you will be able to figure out how to use it.
19
20 lp.lua -- LPD client library
21
22The lp.lua module implements the client part of the Line
23Printer Daemon protocol, used to print files on Unix
24machines. It is courtesy of David Burgess! See the source
25code and the lpr.lua in the examples directory.
26
27 b64.lua
28 qp.lua
29 eol.lua
30
31These are tiny programs that perform Base64,
32Quoted-Printable and end-of-line marker conversions.
33
34 get.lua -- file retriever
35
36This little program is a client that uses the FTP and
37HTTP code to implement a command line file graber. Just
38run
39
40 lua get.lua <remote-file> [<local-file>]
41
42to download a remote file (either ftp:// or http://) to
43the specified local file. The program also prints the
44download throughput, elapsed time, bytes already downloaded
45etc during download.
46
47 check-memory.lua -- checks memory consumption
48
49This is just to see how much memory each module uses.
50
51 dispatch.lua -- coroutine based dispatcher
52
53This is a first try at a coroutine based non-blocking
54dispatcher for LuaSocket. Take a look at 'check-links.lua'
55and at 'forward.lua' to see how to use it.
56
57 check-links.lua -- HTML link checker program
58
59This little program scans a HTML file and checks for broken
60links. It is similar to check-links.pl by Jamie Zawinski,
61but uses all facilities of the LuaSocket library and the Lua
62language. It has not been thoroughly tested, but it should
63work. Just run
64
65 lua check-links.lua [-n] {<url>} > output
66
67and open the result to see a list of broken links. Make sure
68you check the '-n' switch. It runs in non-blocking mode,
69using coroutines, and is MUCH faster!
70
71 forward.lua -- coroutine based forward server
72
73This is a forward server that can accept several connections
74and transfers simultaneously using non-blocking I/O and the
75coroutine-based dispatcher. You can run, for example
76
77 lua forward.lua 8080:proxy.com:3128
78
79to redirect all local conections to port 8080 to the host
80'proxy.com' at port 3128.
81
82 unix.c and unix.h
83
84This is an implementation of Unix local domain sockets and
85demonstrates how to extend LuaSocket with a new type of
86transport. It has been tested on Linux and on Mac OS X.
87
4 listener.lua -- socket to stdout 88 listener.lua -- socket to stdout
5 talker.lua -- stdin to socket 89 talker.lua -- stdin to socket
6 90
7listener.lua and talker.lua are about the simplest 91listener.lua and talker.lua are about the simplest
8applications you can write using LuaSocket. Run 92applications you can write using LuaSocket. Run
9 93
10 'lua listener.lua' and 'lua talker.lua' 94 'lua listener.lua' and 'lua talker.lua'
11 95
@@ -17,13 +101,13 @@ be printed by listen.lua.
17This is a cool program written by David Burgess to print 101This is a cool program written by David Burgess to print
18files using the Line Printer Daemon protocol, widely used in 102files using the Line Printer Daemon protocol, widely used in
19Unix machines. It uses the lp.lua implementation, in the 103Unix machines. It uses the lp.lua implementation, in the
20etc directory. Just run 'lua lpr.lua <filename> 104samples directory. Just run 'lua lpr.lua <filename>
21queue=<printername>' and the file will print! 105queue=<printername>' and the file will print!
22 106
23 cddb.lua -- CDDB client 107 cddb.lua -- CDDB client
24 108
25This is the first try on a simple CDDB client. Not really 109This is the first try on a simple CDDB client. Not really
26useful, but one day it might become a module. 110useful, but one day it might become a module.
27 111
28 daytimeclnt.lua -- day time client 112 daytimeclnt.lua -- day time client
29 113
diff --git a/etc/b64.lua b/samples/b64.lua
index 11eeb2d..11eeb2d 100644
--- a/etc/b64.lua
+++ b/samples/b64.lua
diff --git a/samples/cddb.lua b/samples/cddb.lua
index 49a1871..59d5a44 100644
--- a/samples/cddb.lua
+++ b/samples/cddb.lua
@@ -26,7 +26,7 @@ function parse(body)
26 data[key] = value 26 data[key] = value
27 end 27 end
28 end 28 end
29 return data, code, message 29 return data, code, message
30end 30end
31 31
32local host = socket.dns.gethostname() 32local host = socket.dns.gethostname()
diff --git a/etc/check-links.lua b/samples/check-links.lua
index 283f3ac..283f3ac 100644
--- a/etc/check-links.lua
+++ b/samples/check-links.lua
diff --git a/etc/check-memory.lua b/samples/check-memory.lua
index 7bd984d..7bd984d 100644
--- a/etc/check-memory.lua
+++ b/samples/check-memory.lua
diff --git a/etc/cookie.lua b/samples/cookie.lua
index 4adb403..fec10a1 100644
--- a/etc/cookie.lua
+++ b/samples/cookie.lua
@@ -5,7 +5,7 @@ local ltn12 = require"ltn12"
5 5
6local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]' 6local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
7 7
8local function unquote(t, quoted) 8local function unquote(t, quoted)
9 local n = string.match(t, "%$(%d+)$") 9 local n = string.match(t, "%$(%d+)$")
10 if n then n = tonumber(n) end 10 if n then n = tonumber(n) end
11 if quoted[n] then return quoted[n] 11 if quoted[n] then return quoted[n]
@@ -14,19 +14,19 @@ end
14 14
15local function parse_set_cookie(c, quoted, cookie_table) 15local function parse_set_cookie(c, quoted, cookie_table)
16 c = c .. ";$last=last;" 16 c = c .. ";$last=last;"
17 local _, __, n, v, i = string.find(c, "(" .. token_class .. 17 local _, _, n, v, i = string.find(c, "(" .. token_class ..
18 "+)%s*=%s*(.-)%s*;%s*()") 18 "+)%s*=%s*(.-)%s*;%s*()")
19 local cookie = { 19 local cookie = {
20 name = n, 20 name = n,
21 value = unquote(v, quoted), 21 value = unquote(v, quoted),
22 attributes = {} 22 attributes = {}
23 } 23 }
24 while 1 do 24 while 1 do
25 _, __, n, v, i = string.find(c, "(" .. token_class .. 25 _, _, n, v, i = string.find(c, "(" .. token_class ..
26 "+)%s*=?%s*(.-)%s*;%s*()", i) 26 "+)%s*=?%s*(.-)%s*;%s*()", i)
27 if not n or n == "$last" then break end 27 if not n or n == "$last" then break end
28 cookie.attributes[#cookie.attributes+1] = { 28 cookie.attributes[#cookie.attributes+1] = {
29 name = n, 29 name = n,
30 value = unquote(v, quoted) 30 value = unquote(v, quoted)
31 } 31 }
32 end 32 end
@@ -46,8 +46,8 @@ local function split_set_cookie(s, cookie_table)
46 -- split into individual cookies 46 -- split into individual cookies
47 i = 1 47 i = 1
48 while 1 do 48 while 1 do
49 local _, __, cookie, next_token 49 local _, _, cookie, next_token
50 _, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" .. 50 _, _, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
51 token_class .. "+)%s*=", i) 51 token_class .. "+)%s*=", i)
52 if not next_token then break end 52 if not next_token then break end
53 parse_set_cookie(cookie, quoted, cookie_table) 53 parse_set_cookie(cookie, quoted, cookie_table)
@@ -62,12 +62,12 @@ local function quote(s)
62end 62end
63 63
64local _empty = {} 64local _empty = {}
65local function build_cookies(cookies) 65local function build_cookies(cookies)
66 s = "" 66 s = ""
67 for i,v in ipairs(cookies or _empty) do 67 for i,v in ipairs(cookies or _empty) do
68 if v.name then 68 if v.name then
69 s = s .. v.name 69 s = s .. v.name
70 if v.value and v.value ~= "" then 70 if v.value and v.value ~= "" then
71 s = s .. '=' .. quote(v.value) 71 s = s .. '=' .. quote(v.value)
72 end 72 end
73 end 73 end
@@ -83,6 +83,6 @@ local function build_cookies(cookies)
83 end 83 end
84 if i < #cookies then s = s .. ", " end 84 if i < #cookies then s = s .. ", " end
85 end 85 end
86 return s 86 return s
87end 87end
88 88
diff --git a/etc/dict.lua b/samples/dict.lua
index 8c5b711..8c5b711 100644
--- a/etc/dict.lua
+++ b/samples/dict.lua
diff --git a/etc/dispatch.lua b/samples/dispatch.lua
index 2485415..2485415 100644
--- a/etc/dispatch.lua
+++ b/samples/dispatch.lua
diff --git a/etc/eol.lua b/samples/eol.lua
index eeaf0ce..eeaf0ce 100644
--- a/etc/eol.lua
+++ b/samples/eol.lua
diff --git a/etc/forward.lua b/samples/forward.lua
index 05ced1a..05ced1a 100644
--- a/etc/forward.lua
+++ b/samples/forward.lua
diff --git a/etc/get.lua b/samples/get.lua
index 9edc235..d53c465 100644
--- a/etc/get.lua
+++ b/samples/get.lua
@@ -71,7 +71,7 @@ function stats(size)
71 local current = socket.gettime() 71 local current = socket.gettime()
72 if chunk then 72 if chunk then
73 -- total bytes received 73 -- total bytes received
74 got = got + string.len(chunk) 74 got = got + string.len(chunk)
75 -- not enough time for estimate 75 -- not enough time for estimate
76 if current - last > 1 then 76 if current - last > 1 then
77 io.stderr:write("\r", gauge(got, current - start, size)) 77 io.stderr:write("\r", gauge(got, current - start, size))
diff --git a/etc/links b/samples/links
index 087f1c0..087f1c0 100644
--- a/etc/links
+++ b/samples/links
diff --git a/etc/lp.lua b/samples/lp.lua
index 25f0b95..25f0b95 100644
--- a/etc/lp.lua
+++ b/samples/lp.lua
diff --git a/etc/qp.lua b/samples/qp.lua
index 523238b..523238b 100644
--- a/etc/qp.lua
+++ b/samples/qp.lua
diff --git a/etc/tftp.lua b/samples/tftp.lua
index ed99cd1..ed99cd1 100644
--- a/etc/tftp.lua
+++ b/samples/tftp.lua
diff --git a/socket.vcxproj b/socket.vcxproj
index 16daeef..51ebc68 100755
--- a/socket.vcxproj
+++ b/socket.vcxproj
@@ -1,5 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup Label="ProjectConfigurations"> 3 <ItemGroup Label="ProjectConfigurations">
4 <ProjectConfiguration Include="Debug|Win32"> 4 <ProjectConfiguration Include="Debug|Win32">
5 <Configuration>Debug</Configuration> 5 <Configuration>Debug</Configuration>
@@ -21,6 +21,7 @@
21 <ItemGroup> 21 <ItemGroup>
22 <ClCompile Include="src\auxiliar.c" /> 22 <ClCompile Include="src\auxiliar.c" />
23 <ClCompile Include="src\buffer.c" /> 23 <ClCompile Include="src\buffer.c" />
24 <ClCompile Include="src\compat.c" />
24 <ClCompile Include="src\except.c" /> 25 <ClCompile Include="src\except.c" />
25 <ClCompile Include="src\inet.c" /> 26 <ClCompile Include="src\inet.c" />
26 <ClCompile Include="src\io.c" /> 27 <ClCompile Include="src\io.c" />
@@ -32,98 +33,6 @@
32 <ClCompile Include="src\udp.c" /> 33 <ClCompile Include="src\udp.c" />
33 <ClCompile Include="src\wsocket.c" /> 34 <ClCompile Include="src\wsocket.c" />
34 </ItemGroup> 35 </ItemGroup>
35 <ItemGroup>
36 <CustomBuild Include="src\ltn12.lua">
37 <FileType>Document</FileType>
38 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
39 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
40 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
41 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
42 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
43 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
44 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
45 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
46 </CustomBuild>
47 <CustomBuild Include="src\socket.lua">
48 <FileType>Document</FileType>
49 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
50 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
51 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
52 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
53 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
54 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
55 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
56 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
57 </CustomBuild>
58 </ItemGroup>
59 <ItemGroup>
60 <CustomBuild Include="src\ftp.lua">
61 <FileType>Document</FileType>
62 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
63 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
64 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
65 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
66 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
67 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
68 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
69 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
70 </CustomBuild>
71 <CustomBuild Include="src\headers.lua">
72 <FileType>Document</FileType>
73 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
74 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
75 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
76 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
77 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
78 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
79 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
80 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
81 </CustomBuild>
82 <CustomBuild Include="src\http.lua">
83 <FileType>Document</FileType>
84 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
85 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
86 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
87 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
88 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
89 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
90 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
91 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
92 </CustomBuild>
93 <CustomBuild Include="src\smtp.lua">
94 <FileType>Document</FileType>
95 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
96 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
97 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
98 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
99 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
100 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
101 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
102 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
103 </CustomBuild>
104 <CustomBuild Include="src\tp.lua">
105 <FileType>Document</FileType>
106 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
107 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
108 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
109 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
110 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
111 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
112 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
113 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
114 </CustomBuild>
115 <CustomBuild Include="src\url.lua">
116 <FileType>Document</FileType>
117 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
118 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
119 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
120 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
121 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
122 <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
123 <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
124 <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
125 </CustomBuild>
126 </ItemGroup>
127 <PropertyGroup Label="Globals"> 36 <PropertyGroup Label="Globals">
128 <ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid> 37 <ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid>
129 <Keyword>Win32Proj</Keyword> 38 <Keyword>Win32Proj</Keyword>
@@ -131,22 +40,22 @@
131 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 40 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
132 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> 41 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
133 <ConfigurationType>DynamicLibrary</ConfigurationType> 42 <ConfigurationType>DynamicLibrary</ConfigurationType>
134 <PlatformToolset>v110</PlatformToolset> 43 <PlatformToolset>v141</PlatformToolset>
135 <CharacterSet>MultiByte</CharacterSet> 44 <CharacterSet>MultiByte</CharacterSet>
136 </PropertyGroup> 45 </PropertyGroup>
137 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> 46 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
138 <ConfigurationType>DynamicLibrary</ConfigurationType> 47 <ConfigurationType>DynamicLibrary</ConfigurationType>
139 <PlatformToolset>v110</PlatformToolset> 48 <PlatformToolset>v141</PlatformToolset>
140 <CharacterSet>MultiByte</CharacterSet> 49 <CharacterSet>MultiByte</CharacterSet>
141 </PropertyGroup> 50 </PropertyGroup>
142 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> 51 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
143 <ConfigurationType>DynamicLibrary</ConfigurationType> 52 <ConfigurationType>DynamicLibrary</ConfigurationType>
144 <PlatformToolset>v110</PlatformToolset> 53 <PlatformToolset>v141</PlatformToolset>
145 <CharacterSet>MultiByte</CharacterSet> 54 <CharacterSet>MultiByte</CharacterSet>
146 </PropertyGroup> 55 </PropertyGroup>
147 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> 56 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
148 <ConfigurationType>DynamicLibrary</ConfigurationType> 57 <ConfigurationType>DynamicLibrary</ConfigurationType>
149 <PlatformToolset>v110</PlatformToolset> 58 <PlatformToolset>v141</PlatformToolset>
150 <CharacterSet>MultiByte</CharacterSet> 59 <CharacterSet>MultiByte</CharacterSet>
151 </PropertyGroup> 60 </PropertyGroup>
152 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 61 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -177,7 +86,7 @@
177 <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion> 86 <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
178 </PropertyGroup> 87 </PropertyGroup>
179 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 88 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
180 <OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir> 89 <OutDir>$(Configuration)\socket\</OutDir>
181 <IntDir>$(Configuration)\</IntDir> 90 <IntDir>$(Configuration)\</IntDir>
182 <LinkIncremental>true</LinkIncremental> 91 <LinkIncremental>true</LinkIncremental>
183 <TargetName>core</TargetName> 92 <TargetName>core</TargetName>
@@ -185,23 +94,23 @@
185 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> 94 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
186 <LinkIncremental>true</LinkIncremental> 95 <LinkIncremental>true</LinkIncremental>
187 <TargetName>core</TargetName> 96 <TargetName>core</TargetName>
188 <OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir> 97 <OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
189 </PropertyGroup> 98 </PropertyGroup>
190 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 99 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
191 <OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir> 100 <OutDir>$(Configuration)\socket\</OutDir>
192 <IntDir>$(Configuration)\</IntDir> 101 <IntDir>$(Configuration)\</IntDir>
193 <LinkIncremental>false</LinkIncremental> 102 <LinkIncremental>false</LinkIncremental>
194 <TargetName>core</TargetName> 103 <TargetName>core</TargetName>
195 </PropertyGroup> 104 </PropertyGroup>
196 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> 105 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
197 <LinkIncremental>false</LinkIncremental> 106 <LinkIncremental>false</LinkIncremental>
198 <OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir> 107 <OutDir>$(Platform)\$(Configuration)\socket\</OutDir>
199 <TargetName>core</TargetName> 108 <TargetName>core</TargetName>
200 </PropertyGroup> 109 </PropertyGroup>
201 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 110 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
202 <ClCompile> 111 <ClCompile>
203 <Optimization>Disabled</Optimization> 112 <Optimization>Disabled</Optimization>
204 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 113 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
205 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> 114 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
206 <MinimalRebuild>true</MinimalRebuild> 115 <MinimalRebuild>true</MinimalRebuild>
207 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 116 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@@ -212,9 +121,9 @@
212 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 121 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
213 </ClCompile> 122 </ClCompile>
214 <Link> 123 <Link>
215 <AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> 124 <AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
216 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 125 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
217 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 126 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
218 <GenerateDebugInformation>true</GenerateDebugInformation> 127 <GenerateDebugInformation>true</GenerateDebugInformation>
219 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile> 128 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
220 <SubSystem>Windows</SubSystem> 129 <SubSystem>Windows</SubSystem>
@@ -228,7 +137,7 @@
228 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> 137 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
229 <ClCompile> 138 <ClCompile>
230 <Optimization>Disabled</Optimization> 139 <Optimization>Disabled</Optimization>
231 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 140 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
232 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> 141 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
233 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 142 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
234 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 143 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -239,9 +148,9 @@
239 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 148 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
240 </ClCompile> 149 </ClCompile>
241 <Link> 150 <Link>
242 <AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> 151 <AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
243 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 152 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
244 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 153 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
245 <GenerateDebugInformation>true</GenerateDebugInformation> 154 <GenerateDebugInformation>true</GenerateDebugInformation>
246 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile> 155 <ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
247 <SubSystem>Windows</SubSystem> 156 <SubSystem>Windows</SubSystem>
@@ -253,7 +162,7 @@
253 </ItemDefinitionGroup> 162 </ItemDefinitionGroup>
254 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 163 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
255 <ClCompile> 164 <ClCompile>
256 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 165 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
257 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 166 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
258 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 167 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
259 <PrecompiledHeader /> 168 <PrecompiledHeader />
@@ -262,9 +171,9 @@
262 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 171 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
263 </ClCompile> 172 </ClCompile>
264 <Link> 173 <Link>
265 <AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> 174 <AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
266 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 175 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
267 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 176 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
268 <GenerateDebugInformation>true</GenerateDebugInformation> 177 <GenerateDebugInformation>true</GenerateDebugInformation>
269 <SubSystem>Windows</SubSystem> 178 <SubSystem>Windows</SubSystem>
270 <OptimizeReferences>true</OptimizeReferences> 179 <OptimizeReferences>true</OptimizeReferences>
@@ -277,7 +186,7 @@
277 </ItemDefinitionGroup> 186 </ItemDefinitionGroup>
278 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> 187 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
279 <ClCompile> 188 <ClCompile>
280 <AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 189 <AdditionalIncludeDirectories>$(LUAINC);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
281 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 190 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
282 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 191 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
283 <PrecompiledHeader> 192 <PrecompiledHeader>
@@ -288,9 +197,9 @@
288 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName> 197 <ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
289 </ClCompile> 198 </ClCompile>
290 <Link> 199 <Link>
291 <AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> 200 <AdditionalDependencies>$(LUALIBNAME);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
292 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile> 201 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
293 <AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 202 <AdditionalLibraryDirectories>$(LUALIB);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
294 <GenerateDebugInformation>true</GenerateDebugInformation> 203 <GenerateDebugInformation>true</GenerateDebugInformation>
295 <SubSystem>Windows</SubSystem> 204 <SubSystem>Windows</SubSystem>
296 <OptimizeReferences>true</OptimizeReferences> 205 <OptimizeReferences>true</OptimizeReferences>
diff --git a/socket.vcxproj.filters b/socket.vcxproj.filters
deleted file mode 100644
index 38f2f07..0000000
--- a/socket.vcxproj.filters
+++ /dev/null
@@ -1,51 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup>
4 <ClCompile Include="src\auxiliar.c" />
5 <ClCompile Include="src\buffer.c" />
6 <ClCompile Include="src\except.c" />
7 <ClCompile Include="src\inet.c" />
8 <ClCompile Include="src\io.c" />
9 <ClCompile Include="src\luasocket.c" />
10 <ClCompile Include="src\options.c" />
11 <ClCompile Include="src\select.c" />
12 <ClCompile Include="src\tcp.c" />
13 <ClCompile Include="src\timeout.c" />
14 <ClCompile Include="src\udp.c" />
15 <ClCompile Include="src\wsocket.c" />
16 </ItemGroup>
17 <ItemGroup>
18 <CustomBuild Include="src\ltn12.lua">
19 <Filter>cdir</Filter>
20 </CustomBuild>
21 <CustomBuild Include="src\socket.lua">
22 <Filter>cdir</Filter>
23 </CustomBuild>
24 <CustomBuild Include="src\ftp.lua">
25 <Filter>ldir</Filter>
26 </CustomBuild>
27 <CustomBuild Include="src\headers.lua">
28 <Filter>ldir</Filter>
29 </CustomBuild>
30 <CustomBuild Include="src\http.lua">
31 <Filter>ldir</Filter>
32 </CustomBuild>
33 <CustomBuild Include="src\smtp.lua">
34 <Filter>ldir</Filter>
35 </CustomBuild>
36 <CustomBuild Include="src\tp.lua">
37 <Filter>ldir</Filter>
38 </CustomBuild>
39 <CustomBuild Include="src\url.lua">
40 <Filter>ldir</Filter>
41 </CustomBuild>
42 </ItemGroup>
43 <ItemGroup>
44 <Filter Include="cdir">
45 <UniqueIdentifier>{b053460d-5439-4e3a-a2eb-c31a95b5691f}</UniqueIdentifier>
46 </Filter>
47 <Filter Include="ldir">
48 <UniqueIdentifier>{b301b82c-37cb-4e05-9333-194e92ed7a62}</UniqueIdentifier>
49 </Filter>
50 </ItemGroup>
51</Project> \ No newline at end of file
diff --git a/src/auxiliar.c b/src/auxiliar.c
index 18fa8e4..93a66a0 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -2,14 +2,11 @@
2* Auxiliar routines for class hierarchy manipulation 2* Auxiliar routines for class hierarchy manipulation
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
6#include "auxiliar.h"
5#include <string.h> 7#include <string.h>
6#include <stdio.h> 8#include <stdio.h>
7 9
8#include "auxiliar.h"
9
10/*=========================================================================*\
11* Exported functions
12\*=========================================================================*/
13/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------*\
14* Initializes the module 11* Initializes the module
15\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
@@ -143,7 +140,7 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
143* otherwise 140* otherwise
144\*-------------------------------------------------------------------------*/ 141\*-------------------------------------------------------------------------*/
145void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { 142void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
146 return luaL_checkudata(L, objidx, classname); 143 return luaL_testudata(L, objidx, classname);
147} 144}
148 145
149/*-------------------------------------------------------------------------*\ 146/*-------------------------------------------------------------------------*\
@@ -155,4 +152,3 @@ int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
155 luaL_typename(L, narg)); 152 luaL_typename(L, narg));
156 return luaL_argerror(L, narg, msg); 153 return luaL_argerror(L, narg, msg);
157} 154}
158
diff --git a/src/auxiliar.h b/src/auxiliar.h
index 65511d4..e8c3ead 100644
--- a/src/auxiliar.h
+++ b/src/auxiliar.h
@@ -29,20 +29,26 @@
29* reverse mapping are done using lauxlib. 29* reverse mapping are done using lauxlib.
30\*=========================================================================*/ 30\*=========================================================================*/
31 31
32#include "lua.h" 32#include "luasocket.h"
33#include "lauxlib.h" 33
34#include "compat.h" 34#ifndef _WIN32
35#pragma GCC visibility push(hidden)
36#endif
35 37
36int auxiliar_open(lua_State *L); 38int auxiliar_open(lua_State *L);
37void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); 39void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
40int auxiliar_tostring(lua_State *L);
38void auxiliar_add2group(lua_State *L, const char *classname, const char *group); 41void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
39void auxiliar_setclass(lua_State *L, const char *classname, int objidx); 42int auxiliar_checkboolean(lua_State *L, int objidx);
40void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); 43void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
41void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); 44void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
42void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); 45void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
43void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); 46void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
44int auxiliar_checkboolean(lua_State *L, int objidx); 47void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
45int auxiliar_tostring(lua_State *L);
46int auxiliar_typeerror(lua_State *L, int narg, const char *tname); 48int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
47 49
50#ifndef _WIN32
51#pragma GCC visibility pop
52#endif
53
48#endif /* AUXILIAR_H */ 54#endif /* AUXILIAR_H */
diff --git a/src/buffer.c b/src/buffer.c
index fff1634..7148be3 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2,10 +2,7 @@
2* Input/Output interface for Lua programs 2* Input/Output interface for Lua programs
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "lua.h" 5#include "luasocket.h"
6#include "lauxlib.h"
7#include "compat.h"
8
9#include "buffer.h" 6#include "buffer.h"
10 7
11/*=========================================================================*\ 8/*=========================================================================*\
@@ -106,11 +103,14 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
106* object:receive() interface 103* object:receive() interface
107\*-------------------------------------------------------------------------*/ 104\*-------------------------------------------------------------------------*/
108int buffer_meth_receive(lua_State *L, p_buffer buf) { 105int buffer_meth_receive(lua_State *L, p_buffer buf) {
109 int err = IO_DONE, top = lua_gettop(L); 106 int err = IO_DONE, top;
110 luaL_Buffer b; 107 luaL_Buffer b;
111 size_t size; 108 size_t size;
112 const char *part = luaL_optlstring(L, 3, "", &size); 109 const char *part = luaL_optlstring(L, 3, "", &size);
113 timeout_markstart(buf->tm); 110 timeout_markstart(buf->tm);
111 /* make sure we don't confuse buffer stuff with arguments */
112 lua_settop(L, 3);
113 top = lua_gettop(L);
114 /* initialize buffer with optional extra prefix 114 /* initialize buffer with optional extra prefix
115 * (useful for concatenating previous partial results) */ 115 * (useful for concatenating previous partial results) */
116 luaL_buffinit(L, &b); 116 luaL_buffinit(L, &b);
diff --git a/src/buffer.h b/src/buffer.h
index 1281bb3..a0901fc 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -15,8 +15,7 @@
15* The module is built on top of the I/O abstraction defined in io.h and the 15* The module is built on top of the I/O abstraction defined in io.h and the
16* timeout management is done with the timeout.h interface. 16* timeout management is done with the timeout.h interface.
17\*=========================================================================*/ 17\*=========================================================================*/
18#include "lua.h" 18#include "luasocket.h"
19
20#include "io.h" 19#include "io.h"
21#include "timeout.h" 20#include "timeout.h"
22 21
@@ -34,12 +33,20 @@ typedef struct t_buffer_ {
34} t_buffer; 33} t_buffer;
35typedef t_buffer *p_buffer; 34typedef t_buffer *p_buffer;
36 35
36#ifndef _WIN32
37#pragma GCC visibility push(hidden)
38#endif
39
37int buffer_open(lua_State *L); 40int buffer_open(lua_State *L);
38void buffer_init(p_buffer buf, p_io io, p_timeout tm); 41void buffer_init(p_buffer buf, p_io io, p_timeout tm);
39int buffer_meth_send(lua_State *L, p_buffer buf);
40int buffer_meth_receive(lua_State *L, p_buffer buf);
41int buffer_meth_getstats(lua_State *L, p_buffer buf); 42int buffer_meth_getstats(lua_State *L, p_buffer buf);
42int buffer_meth_setstats(lua_State *L, p_buffer buf); 43int buffer_meth_setstats(lua_State *L, p_buffer buf);
44int buffer_meth_send(lua_State *L, p_buffer buf);
45int buffer_meth_receive(lua_State *L, p_buffer buf);
43int buffer_isempty(p_buffer buf); 46int buffer_isempty(p_buffer buf);
44 47
48#ifndef _WIN32
49#pragma GCC visibility pop
50#endif
51
45#endif /* BUF_H */ 52#endif /* BUF_H */
diff --git a/src/compat.c b/src/compat.c
index c2d99cb..34ffdaf 100644
--- a/src/compat.c
+++ b/src/compat.c
@@ -1,10 +1,12 @@
1#include "luasocket.h"
1#include "compat.h" 2#include "compat.h"
2 3
3#if LUA_VERSION_NUM==501 4#if LUA_VERSION_NUM==501
5
4/* 6/*
5** Adapted from Lua 5.2 7** Adapted from Lua 5.2
6*/ 8*/
7void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { 9void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
8 luaL_checkstack(L, nup+1, "too many upvalues"); 10 luaL_checkstack(L, nup+1, "too many upvalues");
9 for (; l->name != NULL; l++) { /* fill the table with given functions */ 11 for (; l->name != NULL; l++) { /* fill the table with given functions */
10 int i; 12 int i;
@@ -16,4 +18,22 @@ void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
16 } 18 }
17 lua_pop(L, nup); /* remove upvalues */ 19 lua_pop(L, nup); /* remove upvalues */
18} 20}
21
22/*
23** Duplicated from Lua 5.2
24*/
25void *luasocket_testudata (lua_State *L, int ud, const char *tname) {
26 void *p = lua_touserdata(L, ud);
27 if (p != NULL) { /* value is a userdata? */
28 if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
29 luaL_getmetatable(L, tname); /* get correct metatable */
30 if (!lua_rawequal(L, -1, -2)) /* not the same? */
31 p = NULL; /* value is a userdata with wrong metatable */
32 lua_pop(L, 2); /* remove both metatables */
33 return p;
34 }
35 }
36 return NULL; /* value is not a userdata with a metatable */
37}
38
19#endif 39#endif
diff --git a/src/compat.h b/src/compat.h
index 7bf8010..fa2d7d7 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -1,11 +1,22 @@
1#ifndef COMPAT_H 1#ifndef COMPAT_H
2#define COMPAT_H 2#define COMPAT_H
3 3
4#include "lua.h"
5#include "lauxlib.h"
6
7#if LUA_VERSION_NUM==501 4#if LUA_VERSION_NUM==501
8void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); 5
6#ifndef _WIN32
7#pragma GCC visibility push(hidden)
8#endif
9
10void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
11void *luasocket_testudata ( lua_State *L, int arg, const char *tname);
12
13#ifndef _WIN32
14#pragma GCC visibility pop
15#endif
16
17#define luaL_setfuncs luasocket_setfuncs
18#define luaL_testudata luasocket_testudata
19
9#endif 20#endif
10 21
11#endif 22#endif
diff --git a/src/except.c b/src/except.c
index 261ac98..9c3317f 100644
--- a/src/except.c
+++ b/src/except.c
@@ -2,17 +2,13 @@
2* Simple exception support 2* Simple exception support
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <stdio.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "except.h" 6#include "except.h"
7#include <stdio.h>
12 8
13#if LUA_VERSION_NUM < 502 9#if LUA_VERSION_NUM < 502
14#define lua_pcallk(L, na, nr, err, ctx, cont) \ 10#define lua_pcallk(L, na, nr, err, ctx, cont) \
15 ((void)ctx,(void)cont,lua_pcall(L, na, nr, err)) 11 (((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
16#endif 12#endif
17 13
18#if LUA_VERSION_NUM < 503 14#if LUA_VERSION_NUM < 503
@@ -39,18 +35,17 @@ static luaL_Reg func[] = {
39* Try factory 35* Try factory
40\*-------------------------------------------------------------------------*/ 36\*-------------------------------------------------------------------------*/
41static void wrap(lua_State *L) { 37static void wrap(lua_State *L) {
42 lua_newtable(L); 38 lua_createtable(L, 1, 0);
43 lua_pushnumber(L, 1); 39 lua_pushvalue(L, -2);
44 lua_pushvalue(L, -3); 40 lua_rawseti(L, -2, 1);
45 lua_settable(L, -3); 41 lua_pushvalue(L, lua_upvalueindex(1));
46 lua_insert(L, -2); 42 lua_setmetatable(L, -2);
47 lua_pop(L, 1);
48} 43}
49 44
50static int finalize(lua_State *L) { 45static int finalize(lua_State *L) {
51 if (!lua_toboolean(L, 1)) { 46 if (!lua_toboolean(L, 1)) {
52 lua_pushvalue(L, lua_upvalueindex(1)); 47 lua_pushvalue(L, lua_upvalueindex(2));
53 lua_pcall(L, 0, 0, 0); 48 lua_call(L, 0, 0);
54 lua_settop(L, 2); 49 lua_settop(L, 2);
55 wrap(L); 50 wrap(L);
56 lua_error(L); 51 lua_error(L);
@@ -58,15 +53,17 @@ static int finalize(lua_State *L) {
58 } else return lua_gettop(L); 53 } else return lua_gettop(L);
59} 54}
60 55
61static int do_nothing(lua_State *L) { 56static int do_nothing(lua_State *L) {
62 (void) L; 57 (void) L;
63 return 0; 58 return 0;
64} 59}
65 60
66static int global_newtry(lua_State *L) { 61static int global_newtry(lua_State *L) {
67 lua_settop(L, 1); 62 lua_settop(L, 1);
68 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); 63 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
69 lua_pushcclosure(L, finalize, 1); 64 lua_pushvalue(L, lua_upvalueindex(1));
65 lua_insert(L, -2);
66 lua_pushcclosure(L, finalize, 2);
70 return 1; 67 return 1;
71} 68}
72 69
@@ -74,13 +71,16 @@ static int global_newtry(lua_State *L) {
74* Protect factory 71* Protect factory
75\*-------------------------------------------------------------------------*/ 72\*-------------------------------------------------------------------------*/
76static int unwrap(lua_State *L) { 73static int unwrap(lua_State *L) {
77 if (lua_istable(L, -1)) { 74 if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
78 lua_pushnumber(L, 1); 75 int r = lua_rawequal(L, -1, lua_upvalueindex(1));
79 lua_gettable(L, -2); 76 lua_pop(L, 1);
80 lua_pushnil(L); 77 if (r) {
81 lua_insert(L, -2); 78 lua_pushnil(L);
82 return 1; 79 lua_rawgeti(L, -2, 1);
83 } else return 0; 80 return 1;
81 }
82 }
83 return 0;
84} 84}
85 85
86static int protected_finish(lua_State *L, int status, lua_KContext ctx) { 86static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
@@ -103,14 +103,17 @@ static int protected_cont(lua_State *L) {
103 103
104static int protected_(lua_State *L) { 104static int protected_(lua_State *L) {
105 int status; 105 int status;
106 lua_pushvalue(L, lua_upvalueindex(1)); 106 lua_pushvalue(L, lua_upvalueindex(2));
107 lua_insert(L, 1); 107 lua_insert(L, 1);
108 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); 108 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
109 return protected_finish(L, status, 0); 109 return protected_finish(L, status, 0);
110} 110}
111 111
112static int global_protect(lua_State *L) { 112static int global_protect(lua_State *L) {
113 lua_pushcclosure(L, protected_, 1); 113 lua_settop(L, 1);
114 lua_pushvalue(L, lua_upvalueindex(1));
115 lua_insert(L, 1);
116 lua_pushcclosure(L, protected_, 2);
114 return 1; 117 return 1;
115} 118}
116 119
@@ -118,6 +121,9 @@ static int global_protect(lua_State *L) {
118* Init module 121* Init module
119\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
120int except_open(lua_State *L) { 123int except_open(lua_State *L) {
121 luaL_setfuncs(L, func, 0); 124 lua_newtable(L); /* metatable for wrapped exceptions */
125 lua_pushboolean(L, 0);
126 lua_setfield(L, -2, "__metatable");
127 luaL_setfuncs(L, func, 1);
122 return 0; 128 return 0;
123} 129}
diff --git a/src/except.h b/src/except.h
index 1e7a245..71c31fd 100644
--- a/src/except.h
+++ b/src/except.h
@@ -9,25 +9,38 @@
9* error checking was taking a substantial amount of the coding. These 9* error checking was taking a substantial amount of the coding. These
10* function greatly simplify the task of checking errors. 10* function greatly simplify the task of checking errors.
11* 11*
12* The main idea is that functions should return nil as its first return 12* The main idea is that functions should return nil as their first return
13* value when it finds an error, and return an error message (or value) 13* values when they find an error, and return an error message (or value)
14* following nil. In case of success, as long as the first value is not nil, 14* following nil. In case of success, as long as the first value is not nil,
15* the other values don't matter. 15* the other values don't matter.
16* 16*
17* The idea is to nest function calls with the "try" function. This function 17* The idea is to nest function calls with the "try" function. This function
18* checks the first value, and calls "error" on the second if the first is 18* checks the first value, and, if it's falsy, wraps the second value in a
19* nil. Otherwise, it returns all values it received. 19* table with metatable and calls "error" on it. Otherwise, it returns all
20* values it received. Basically, it works like the Lua "assert" function,
21* but it creates errors targeted specifically at "protect".
20* 22*
21* The protect function returns a new function that behaves exactly like the 23* The "newtry" function is a factory for "try" functions that call a
22* function it receives, but the new function doesn't throw exceptions: it 24* finalizer in protected mode before calling "error".
23* returns nil followed by the error message instead.
24* 25*
25* With these two function, it's easy to write functions that throw 26* The "protect" function returns a new function that behaves exactly like
26* exceptions on error, but that don't interrupt the user script. 27* the function it receives, but the new function catches exceptions thrown
28* by "try" functions and returns nil followed by the error message instead.
29*
30* With these three functions, it's easy to write functions that throw
31* exceptions on error, but that don't interrupt the user script.
27\*=========================================================================*/ 32\*=========================================================================*/
28 33
29#include "lua.h" 34#include "luasocket.h"
35
36#ifndef _WIN32
37#pragma GCC visibility push(hidden)
38#endif
30 39
31int except_open(lua_State *L); 40int except_open(lua_State *L);
32 41
42#ifndef _WIN32
43#pragma GCC visibility pop
44#endif
45
33#endif 46#endif
diff --git a/src/ftp.lua b/src/ftp.lua
index 917cd89..0ebc508 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -23,7 +23,7 @@ local _M = socket.ftp
23-- timeout in seconds before the program gives up on a connection 23-- timeout in seconds before the program gives up on a connection
24_M.TIMEOUT = 60 24_M.TIMEOUT = 60
25-- default port for ftp service 25-- default port for ftp service
26_M.PORT = 21 26local PORT = 21
27-- this is the default anonymous password. used when no password is 27-- this is the default anonymous password. used when no password is
28-- provided in url. should be changed to your e-mail. 28-- provided in url. should be changed to your e-mail.
29_M.USER = "ftp" 29_M.USER = "ftp"
@@ -35,7 +35,7 @@ _M.PASSWORD = "anonymous@anonymous.org"
35local metat = { __index = {} } 35local metat = { __index = {} }
36 36
37function _M.open(server, port, create) 37function _M.open(server, port, create)
38 local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create)) 38 local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
39 local f = base.setmetatable({ tp = tp }, metat) 39 local f = base.setmetatable({ tp = tp }, metat)
40 -- make sure everything gets closed in an exception 40 -- make sure everything gets closed in an exception
41 f.try = socket.newtry(function() f:close() end) 41 f.try = socket.newtry(function() f:close() end)
@@ -51,12 +51,12 @@ end
51function metat.__index:pasvconnect() 51function metat.__index:pasvconnect()
52 self.data = self.try(socket.tcp()) 52 self.data = self.try(socket.tcp())
53 self.try(self.data:settimeout(_M.TIMEOUT)) 53 self.try(self.data:settimeout(_M.TIMEOUT))
54 self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) 54 self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
55end 55end
56 56
57function metat.__index:login(user, password) 57function metat.__index:login(user, password)
58 self.try(self.tp:command("user", user or _M.USER)) 58 self.try(self.tp:command("user", user or _M.USER))
59 local code, reply = self.try(self.tp:check{"2..", 331}) 59 local code, _ = self.try(self.tp:check{"2..", 331})
60 if code == 331 then 60 if code == 331 then
61 self.try(self.tp:command("pass", password or _M.PASSWORD)) 61 self.try(self.tp:command("pass", password or _M.PASSWORD))
62 self.try(self.tp:check("2..")) 62 self.try(self.tp:check("2.."))
@@ -66,37 +66,70 @@ end
66 66
67function metat.__index:pasv() 67function metat.__index:pasv()
68 self.try(self.tp:command("pasv")) 68 self.try(self.tp:command("pasv"))
69 local code, reply = self.try(self.tp:check("2..")) 69 local _, reply = self.try(self.tp:check("2.."))
70 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" 70 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
71 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) 71 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
72 self.try(a and b and c and d and p1 and p2, reply) 72 self.try(a and b and c and d and p1 and p2, reply)
73 self.pasvt = { 73 self.pasvt = {
74 ip = string.format("%d.%d.%d.%d", a, b, c, d), 74 address = string.format("%d.%d.%d.%d", a, b, c, d),
75 port = p1*256 + p2 75 port = p1*256 + p2
76 } 76 }
77 if self.server then 77 if self.server then
78 self.server:close() 78 self.server:close()
79 self.server = nil 79 self.server = nil
80 end 80 end
81 return self.pasvt.ip, self.pasvt.port 81 return self.pasvt.address, self.pasvt.port
82end 82end
83 83
84function metat.__index:port(ip, port) 84function metat.__index:epsv()
85 self.try(self.tp:command("epsv"))
86 local _, reply = self.try(self.tp:check("229"))
87 local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
88 local _, _, _, port = string.match(reply, pattern)
89 self.try(port, "invalid epsv response")
90 self.pasvt = {
91 address = self.tp:getpeername(),
92 port = port
93 }
94 if self.server then
95 self.server:close()
96 self.server = nil
97 end
98 return self.pasvt.address, self.pasvt.port
99end
100
101
102function metat.__index:port(address, port)
85 self.pasvt = nil 103 self.pasvt = nil
86 if not ip then 104 if not address then
87 ip, port = self.try(self.tp:getcontrol():getsockname()) 105 address = self.try(self.tp:getsockname())
88 self.server = self.try(socket.bind(ip, 0)) 106 self.server = self.try(socket.bind(address, 0))
89 ip, port = self.try(self.server:getsockname()) 107 address, port = self.try(self.server:getsockname())
90 self.try(self.server:settimeout(_M.TIMEOUT)) 108 self.try(self.server:settimeout(_M.TIMEOUT))
91 end 109 end
92 local pl = math.mod(port, 256) 110 local pl = math.mod(port, 256)
93 local ph = (port - pl)/256 111 local ph = (port - pl)/256
94 local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") 112 local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",")
95 self.try(self.tp:command("port", arg)) 113 self.try(self.tp:command("port", arg))
96 self.try(self.tp:check("2..")) 114 self.try(self.tp:check("2.."))
97 return 1 115 return 1
98end 116end
99 117
118function metat.__index:eprt(family, address, port)
119 self.pasvt = nil
120 if not address then
121 address = self.try(self.tp:getsockname())
122 self.server = self.try(socket.bind(address, 0))
123 address, port = self.try(self.server:getsockname())
124 self.try(self.server:settimeout(_M.TIMEOUT))
125 end
126 local arg = string.format("|%s|%s|%d|", family, address, port)
127 self.try(self.tp:command("eprt", arg))
128 self.try(self.tp:check("2.."))
129 return 1
130end
131
132
100function metat.__index:send(sendt) 133function metat.__index:send(sendt)
101 self.try(self.pasvt or self.server, "need port or pasv first") 134 self.try(self.pasvt or self.server, "need port or pasv first")
102 -- if there is a pasvt table, we already sent a PASV command 135 -- if there is a pasvt table, we already sent a PASV command
@@ -109,13 +142,13 @@ function metat.__index:send(sendt)
109 local command = sendt.command or "stor" 142 local command = sendt.command or "stor"
110 -- send the transfer command and check the reply 143 -- send the transfer command and check the reply
111 self.try(self.tp:command(command, argument)) 144 self.try(self.tp:command(command, argument))
112 local code, reply = self.try(self.tp:check{"2..", "1.."}) 145 local code, _ = self.try(self.tp:check{"2..", "1.."})
113 -- if there is not a a pasvt table, then there is a server 146 -- if there is not a pasvt table, then there is a server
114 -- and we already sent a PORT command 147 -- and we already sent a PORT command
115 if not self.pasvt then self:portconnect() end 148 if not self.pasvt then self:portconnect() end
116 -- get the sink, source and step for the transfer 149 -- get the sink, source and step for the transfer
117 local step = sendt.step or ltn12.pump.step 150 local step = sendt.step or ltn12.pump.step
118 local readt = {self.tp.c} 151 local readt = { self.tp }
119 local checkstep = function(src, snk) 152 local checkstep = function(src, snk)
120 -- check status in control connection while downloading 153 -- check status in control connection while downloading
121 local readyt = socket.select(readt, nil, 0) 154 local readyt = socket.select(readt, nil, 0)
@@ -207,7 +240,7 @@ local function tput(putt)
207 f:greet() 240 f:greet()
208 f:login(putt.user, putt.password) 241 f:login(putt.user, putt.password)
209 if putt.type then f:type(putt.type) end 242 if putt.type then f:type(putt.type) end
210 f:pasv() 243 f:epsv()
211 local sent = f:send(putt) 244 local sent = f:send(putt)
212 f:quit() 245 f:quit()
213 f:close() 246 f:close()
@@ -219,7 +252,7 @@ local default = {
219 scheme = "ftp" 252 scheme = "ftp"
220} 253}
221 254
222local function parse(u) 255local function genericform(u)
223 local t = socket.try(url.parse(u, default)) 256 local t = socket.try(url.parse(u, default))
224 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") 257 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
225 socket.try(t.host, "missing hostname") 258 socket.try(t.host, "missing hostname")
@@ -232,8 +265,10 @@ local function parse(u)
232 return t 265 return t
233end 266end
234 267
268_M.genericform = genericform
269
235local function sput(u, body) 270local function sput(u, body)
236 local putt = parse(u) 271 local putt = genericform(u)
237 putt.source = ltn12.source.string(body) 272 putt.source = ltn12.source.string(body)
238 return tput(putt) 273 return tput(putt)
239end 274end
@@ -250,14 +285,14 @@ local function tget(gett)
250 f:greet() 285 f:greet()
251 f:login(gett.user, gett.password) 286 f:login(gett.user, gett.password)
252 if gett.type then f:type(gett.type) end 287 if gett.type then f:type(gett.type) end
253 f:pasv() 288 f:epsv()
254 f:receive(gett) 289 f:receive(gett)
255 f:quit() 290 f:quit()
256 return f:close() 291 return f:close()
257end 292end
258 293
259local function sget(u) 294local function sget(u)
260 local gett = parse(u) 295 local gett = genericform(u)
261 local t = {} 296 local t = {}
262 gett.sink = ltn12.sink.table(t) 297 gett.sink = ltn12.sink.table(t)
263 tget(gett) 298 tget(gett)
@@ -271,8 +306,17 @@ _M.command = socket.protect(function(cmdt)
271 local f = _M.open(cmdt.host, cmdt.port, cmdt.create) 306 local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
272 f:greet() 307 f:greet()
273 f:login(cmdt.user, cmdt.password) 308 f:login(cmdt.user, cmdt.password)
274 f.try(f.tp:command(cmdt.command, cmdt.argument)) 309 if type(cmdt.command) == "table" then
275 if cmdt.check then f.try(f.tp:check(cmdt.check)) end 310 local argument = cmdt.argument or {}
311 local check = cmdt.check or {}
312 for i,cmd in ipairs(cmdt.command) do
313 f.try(f.tp:command(cmd, argument[i]))
314 if check[i] then f.try(f.tp:check(check[i])) end
315 end
316 else
317 f.try(f.tp:command(cmdt.command, cmdt.argument))
318 if cmdt.check then f.try(f.tp:check(cmdt.check)) end
319 end
276 f:quit() 320 f:quit()
277 return f:close() 321 return f:close()
278end) 322end)
@@ -282,4 +326,4 @@ _M.get = socket.protect(function(gett)
282 else return tget(gett) end 326 else return tget(gett) end
283end) 327end)
284 328
285return _M \ No newline at end of file 329return _M
diff --git a/src/http.lua b/src/http.lua
index 45ffa15..fbd5ff6 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -23,11 +23,24 @@ local _M = socket.http
23----------------------------------------------------------------------------- 23-----------------------------------------------------------------------------
24-- connection timeout in seconds 24-- connection timeout in seconds
25_M.TIMEOUT = 60 25_M.TIMEOUT = 60
26-- default port for document retrieval
27_M.PORT = 80
28-- user agent field sent in request 26-- user agent field sent in request
29_M.USERAGENT = socket._VERSION 27_M.USERAGENT = socket._VERSION
30 28
29-- supported schemes and their particulars
30local SCHEMES = {
31 http = {
32 port = 80
33 , create = function(t)
34 return socket.tcp end }
35 , https = {
36 port = 443
37 , create = function(t)
38 local https = assert(
39 require("ssl.https"), 'LuaSocket: LuaSec not found')
40 local tcp = assert(
41 https.tcp, 'LuaSocket: Function tcp() not available from LuaSec')
42 return tcp(t) end }}
43
31----------------------------------------------------------------------------- 44-----------------------------------------------------------------------------
32-- Reads MIME headers from a connection, unfolding where needed 45-- Reads MIME headers from a connection, unfolding where needed
33----------------------------------------------------------------------------- 46-----------------------------------------------------------------------------
@@ -76,7 +89,7 @@ socket.sourcet["http-chunked"] = function(sock, headers)
76 -- was it the last chunk? 89 -- was it the last chunk?
77 if size > 0 then 90 if size > 0 then
78 -- if not, get chunk and skip terminating CRLF 91 -- if not, get chunk and skip terminating CRLF
79 local chunk, err, part = sock:receive(size) 92 local chunk, err, _ = sock:receive(size)
80 if chunk then sock:receive() end 93 if chunk then sock:receive() end
81 return chunk, err 94 return chunk, err
82 else 95 else
@@ -108,13 +121,13 @@ local metat = { __index = {} }
108 121
109function _M.open(host, port, create) 122function _M.open(host, port, create)
110 -- create socket with user connect function, or with default 123 -- create socket with user connect function, or with default
111 local c = socket.try((create or socket.tcp)()) 124 local c = socket.try(create())
112 local h = base.setmetatable({ c = c }, metat) 125 local h = base.setmetatable({ c = c }, metat)
113 -- create finalized try 126 -- create finalized try
114 h.try = socket.newtry(function() h:close() end) 127 h.try = socket.newtry(function() h:close() end)
115 -- set timeout before connecting 128 -- set timeout before connecting
116 h.try(c:settimeout(_M.TIMEOUT)) 129 h.try(c:settimeout(_M.TIMEOUT))
117 h.try(c:connect(host, port or _M.PORT)) 130 h.try(c:connect(host, port))
118 -- here everything worked 131 -- here everything worked
119 return h 132 return h
120end 133end
@@ -144,10 +157,15 @@ function metat.__index:sendbody(headers, source, step)
144end 157end
145 158
146function metat.__index:receivestatusline() 159function metat.__index:receivestatusline()
147 local status = self.try(self.c:receive(5)) 160 local status,ec = self.try(self.c:receive(5))
148 -- identify HTTP/0.9 responses, which do not contain a status line 161 -- identify HTTP/0.9 responses, which do not contain a status line
149 -- this is just a heuristic, but is what the RFC recommends 162 -- this is just a heuristic, but is what the RFC recommends
150 if status ~= "HTTP/" then return nil, status end 163 if status ~= "HTTP/" then
164 if ec == "timeout" then
165 return 408
166 end
167 return nil, status
168 end
151 -- otherwise proceed reading a status line 169 -- otherwise proceed reading a status line
152 status = self.try(self.c:receive("*l", status)) 170 status = self.try(self.c:receive("*l", status))
153 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) 171 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
@@ -209,7 +227,10 @@ end
209 227
210local function adjustheaders(reqt) 228local function adjustheaders(reqt)
211 -- default headers 229 -- default headers
212 local host = string.gsub(reqt.authority, "^.-@", "") 230 local host = reqt.host
231 local port = tostring(reqt.port)
232 if port ~= tostring(SCHEMES[reqt.scheme].port) then
233 host = host .. ':' .. port end
213 local lower = { 234 local lower = {
214 ["user-agent"] = _M.USERAGENT, 235 ["user-agent"] = _M.USERAGENT,
215 ["host"] = host, 236 ["host"] = host,
@@ -218,15 +239,16 @@ local function adjustheaders(reqt)
218 } 239 }
219 -- if we have authentication information, pass it along 240 -- if we have authentication information, pass it along
220 if reqt.user and reqt.password then 241 if reqt.user and reqt.password then
221 lower["authorization"] = 242 lower["authorization"] =
222 "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) 243 "Basic " .. (mime.b64(reqt.user .. ":" ..
244 url.unescape(reqt.password)))
223 end 245 end
224 -- if we have proxy authentication information, pass it along 246 -- if we have proxy authentication information, pass it along
225 local proxy = reqt.proxy or _M.PROXY 247 local proxy = reqt.proxy or _M.PROXY
226 if proxy then 248 if proxy then
227 proxy = url.parse(proxy) 249 proxy = url.parse(proxy)
228 if proxy.user and proxy.password then 250 if proxy.user and proxy.password then
229 lower["proxy-authorization"] = 251 lower["proxy-authorization"] =
230 "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password)) 252 "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password))
231 end 253 end
232 end 254 end
@@ -239,10 +261,8 @@ end
239 261
240-- default url parts 262-- default url parts
241local default = { 263local default = {
242 host = "", 264 path ="/"
243 port = _M.PORT, 265 , scheme = "http"
244 path ="/",
245 scheme = "http"
246} 266}
247 267
248local function adjustrequest(reqt) 268local function adjustrequest(reqt)
@@ -250,25 +270,48 @@ local function adjustrequest(reqt)
250 local nreqt = reqt.url and url.parse(reqt.url, default) or {} 270 local nreqt = reqt.url and url.parse(reqt.url, default) or {}
251 -- explicit components override url 271 -- explicit components override url
252 for i,v in base.pairs(reqt) do nreqt[i] = v end 272 for i,v in base.pairs(reqt) do nreqt[i] = v end
253 if nreqt.port == "" then nreqt.port = 80 end 273 -- default to scheme particulars
254 socket.try(nreqt.host and nreqt.host ~= "", 274 local schemedefs, host, port, method
255 "invalid host '" .. base.tostring(nreqt.host) .. "'") 275 = SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method
276 if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end
277 if not (port and port ~= '') then nreqt.port = schemedefs.port end
278 if not (method and method ~= '') then nreqt.method = 'GET' end
279 if not (host and host ~= "") then
280 socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
281 end
256 -- compute uri if user hasn't overriden 282 -- compute uri if user hasn't overriden
257 nreqt.uri = reqt.uri or adjusturi(nreqt) 283 nreqt.uri = reqt.uri or adjusturi(nreqt)
258 -- adjust headers in request 284 -- adjust headers in request
259 nreqt.headers = adjustheaders(nreqt) 285 nreqt.headers = adjustheaders(nreqt)
286 if nreqt.source
287 and not nreqt.headers["content-length"]
288 and not nreqt.headers["transfer-encoding"]
289 then
290 nreqt.headers["transfer-encoding"] = "chunked"
291 end
292
260 -- ajust host and port if there is a proxy 293 -- ajust host and port if there is a proxy
261 nreqt.host, nreqt.port = adjustproxy(nreqt) 294 nreqt.host, nreqt.port = adjustproxy(nreqt)
262 return nreqt 295 return nreqt
263end 296end
264 297
265local function shouldredirect(reqt, code, headers) 298local function shouldredirect(reqt, code, headers)
266 return headers.location and 299 local location = headers.location
267 string.gsub(headers.location, "%s", "") ~= "" and 300 if not location then return false end
268 (reqt.redirect ~= false) and 301 location = string.gsub(location, "%s", "")
302 if location == "" then return false end
303 -- the RFC says the redirect URL may be relative
304 location = url.absolute(reqt.url, location)
305 local scheme = url.parse(location).scheme
306 if scheme and (not SCHEMES[scheme]) then return false end
307 -- avoid https downgrades
308 if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end
309 return (reqt.redirect ~= false) and
269 (code == 301 or code == 302 or code == 303 or code == 307) and 310 (code == 301 or code == 302 or code == 303 or code == 307) and
270 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") 311 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
271 and (not reqt.nredirects or reqt.nredirects < 5) 312 and ((false == reqt.maxredirects)
313 or ((reqt.nredirects or 0)
314 < (reqt.maxredirects or 5)))
272end 315end
273 316
274local function shouldreceivebody(reqt, code) 317local function shouldreceivebody(reqt, code)
@@ -282,17 +325,23 @@ end
282local trequest, tredirect 325local trequest, tredirect
283 326
284--[[local]] function tredirect(reqt, location) 327--[[local]] function tredirect(reqt, location)
328 -- the RFC says the redirect URL may be relative
329 local newurl = url.absolute(reqt.url, location)
330 -- if switching schemes, reset port and create function
331 if url.parse(newurl).scheme ~= reqt.scheme then
332 reqt.port = nil
333 reqt.create = nil end
334 -- make new request
285 local result, code, headers, status = trequest { 335 local result, code, headers, status = trequest {
286 -- the RFC says the redirect URL has to be absolute, but some 336 url = newurl,
287 -- servers do not respect that
288 url = url.absolute(reqt.url, location),
289 source = reqt.source, 337 source = reqt.source,
290 sink = reqt.sink, 338 sink = reqt.sink,
291 headers = reqt.headers, 339 headers = reqt.headers,
292 proxy = reqt.proxy, 340 proxy = reqt.proxy,
341 maxredirects = reqt.maxredirects,
293 nredirects = (reqt.nredirects or 0) + 1, 342 nredirects = (reqt.nredirects or 0) + 1,
294 create = reqt.create 343 create = reqt.create
295 } 344 }
296 -- pass location header back as a hint we redirected 345 -- pass location header back as a hint we redirected
297 headers = headers or {} 346 headers = headers or {}
298 headers.location = headers.location or location 347 headers.location = headers.location or location
@@ -309,23 +358,25 @@ end
309 h:sendheaders(nreqt.headers) 358 h:sendheaders(nreqt.headers)
310 -- if there is a body, send it 359 -- if there is a body, send it
311 if nreqt.source then 360 if nreqt.source then
312 h:sendbody(nreqt.headers, nreqt.source, nreqt.step) 361 h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
313 end 362 end
314 local code, status = h:receivestatusline() 363 local code, status = h:receivestatusline()
315 -- if it is an HTTP/0.9 server, simply get the body and we are done 364 -- if it is an HTTP/0.9 server, simply get the body and we are done
316 if not code then 365 if not code then
317 h:receive09body(status, nreqt.sink, nreqt.step) 366 h:receive09body(status, nreqt.sink, nreqt.step)
318 return 1, 200 367 return 1, 200
368 elseif code == 408 then
369 return 1, code
319 end 370 end
320 local headers 371 local headers
321 -- ignore any 100-continue messages 372 -- ignore any 100-continue messages
322 while code == 100 do 373 while code == 100 do
323 headers = h:receiveheaders() 374 h:receiveheaders()
324 code, status = h:receivestatusline() 375 code, status = h:receivestatusline()
325 end 376 end
326 headers = h:receiveheaders() 377 headers = h:receiveheaders()
327 -- at this point we should have a honest reply from the server 378 -- at this point we should have a honest reply from the server
328 -- we can't redirect if we already used the source, so we report the error 379 -- we can't redirect if we already used the source, so we report the error
329 if shouldredirect(nreqt, code, headers) and not nreqt.source then 380 if shouldredirect(nreqt, code, headers) and not nreqt.source then
330 h:close() 381 h:close()
331 return tredirect(reqt, headers.location) 382 return tredirect(reqt, headers.location)
@@ -338,11 +389,13 @@ end
338 return 1, code, headers, status 389 return 1, code, headers, status
339end 390end
340 391
341local function srequest(u, b) 392-- turns an url and a body into a generic request
393local function genericform(u, b)
342 local t = {} 394 local t = {}
343 local reqt = { 395 local reqt = {
344 url = u, 396 url = u,
345 sink = ltn12.sink.table(t) 397 sink = ltn12.sink.table(t),
398 target = t
346 } 399 }
347 if b then 400 if b then
348 reqt.source = ltn12.source.string(b) 401 reqt.source = ltn12.source.string(b)
@@ -352,8 +405,15 @@ local function srequest(u, b)
352 } 405 }
353 reqt.method = "POST" 406 reqt.method = "POST"
354 end 407 end
355 local code, headers, status = socket.skip(1, trequest(reqt)) 408 return reqt
356 return table.concat(t), code, headers, status 409end
410
411_M.genericform = genericform
412
413local function srequest(u, b)
414 local reqt = genericform(u, b)
415 local _, code, headers, status = trequest(reqt)
416 return table.concat(reqt.target), code, headers, status
357end 417end
358 418
359_M.request = socket.protect(function(reqt, body) 419_M.request = socket.protect(function(reqt, body)
@@ -361,4 +421,5 @@ _M.request = socket.protect(function(reqt, body)
361 else return trequest(reqt) end 421 else return trequest(reqt) end
362end) 422end)
363 423
424_M.schemes = SCHEMES
364return _M 425return _M
diff --git a/src/inet.c b/src/inet.c
index 331b800..138c9ab 100644..100755
--- a/src/inet.c
+++ b/src/inet.c
@@ -2,16 +2,13 @@
2* Internet domain functions 2* Internet domain functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
6#include "inet.h"
7
5#include <stdio.h> 8#include <stdio.h>
6#include <stdlib.h> 9#include <stdlib.h>
7#include <string.h> 10#include <string.h>
8 11
9#include "lua.h"
10#include "lauxlib.h"
11#include "compat.h"
12
13#include "inet.h"
14
15/*=========================================================================*\ 12/*=========================================================================*\
16* Internal function prototypes. 13* Internal function prototypes.
17\*=========================================================================*/ 14\*=========================================================================*/
@@ -32,9 +29,6 @@ static luaL_Reg func[] = {
32 { NULL, NULL} 29 { NULL, NULL}
33}; 30};
34 31
35/*=========================================================================*\
36* Exported functions
37\*=========================================================================*/
38/*-------------------------------------------------------------------------*\ 32/*-------------------------------------------------------------------------*\
39* Initializes module 33* Initializes module
40\*-------------------------------------------------------------------------*/ 34\*-------------------------------------------------------------------------*/
@@ -259,7 +253,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
259 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); 253 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
260 if (err) { 254 if (err) {
261 lua_pushnil(L); 255 lua_pushnil(L);
262 lua_pushstring(L, gai_strerror(err)); 256 lua_pushstring(L, LUA_GAI_STRERROR(err));
263 return 2; 257 return 2;
264 } 258 }
265 lua_pushstring(L, name); 259 lua_pushstring(L, name);
@@ -292,7 +286,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
292 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); 286 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
293 if (err) { 287 if (err) {
294 lua_pushnil(L); 288 lua_pushnil(L);
295 lua_pushstring(L, gai_strerror(err)); 289 lua_pushstring(L, LUA_GAI_STRERROR(err));
296 return 2; 290 return 2;
297 } 291 }
298 lua_pushstring(L, name); 292 lua_pushstring(L, name);
@@ -423,8 +417,8 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
423 /* try connecting to remote address */ 417 /* try connecting to remote address */
424 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, 418 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
425 (socklen_t) iterator->ai_addrlen, tm)); 419 (socklen_t) iterator->ai_addrlen, tm));
426 /* if success, break out of loop */ 420 /* if success or timeout is zero, break out of loop */
427 if (err == NULL) { 421 if (err == NULL || timeout_iszero(tm)) {
428 *family = current_family; 422 *family = current_family;
429 break; 423 break;
430 } 424 }
diff --git a/src/inet.h b/src/inet.h
index feb3541..5618b61 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -14,7 +14,7 @@
14* 14*
15* The Lua functions toip and tohostname are also implemented here. 15* The Lua functions toip and tohostname are also implemented here.
16\*=========================================================================*/ 16\*=========================================================================*/
17#include "lua.h" 17#include "luasocket.h"
18#include "socket.h" 18#include "socket.h"
19#include "timeout.h" 19#include "timeout.h"
20 20
@@ -22,21 +22,23 @@
22#define LUASOCKET_INET_ATON 22#define LUASOCKET_INET_ATON
23#endif 23#endif
24 24
25#ifndef _WIN32
26#pragma GCC visibility push(hidden)
27#endif
28
25int inet_open(lua_State *L); 29int inet_open(lua_State *L);
26 30
27const char *inet_trycreate(p_socket ps, int family, int type, int protocol); 31int inet_optfamily(lua_State* L, int narg, const char* def);
28const char *inet_tryconnect(p_socket ps, int *family, const char *address, 32int inet_optsocktype(lua_State* L, int narg, const char* def);
29 const char *serv, p_timeout tm, struct addrinfo *connecthints);
30const char *inet_trybind(p_socket ps, int *family, const char *address,
31 const char *serv, struct addrinfo *bindhints);
32const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
33const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
34 33
35int inet_meth_getpeername(lua_State *L, p_socket ps, int family); 34int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
36int inet_meth_getsockname(lua_State *L, p_socket ps, int family); 35int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
37 36
38int inet_optfamily(lua_State* L, int narg, const char* def); 37const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
39int inet_optsocktype(lua_State* L, int narg, const char* def); 38const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
39const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints);
40const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
41const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints);
40 42
41#ifdef LUASOCKET_INET_ATON 43#ifdef LUASOCKET_INET_ATON
42int inet_aton(const char *cp, struct in_addr *inp); 44int inet_aton(const char *cp, struct in_addr *inp);
@@ -47,4 +49,8 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
47int inet_pton(int af, const char *src, void *dst); 49int inet_pton(int af, const char *src, void *dst);
48#endif 50#endif
49 51
52#ifndef _WIN32
53#pragma GCC visibility pop
54#endif
55
50#endif /* INET_H */ 56#endif /* INET_H */
diff --git a/src/io.c b/src/io.c
index a4230ce..5ad4b3a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -2,11 +2,9 @@
2* Input/Output abstraction 2* Input/Output abstraction
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
5#include "io.h" 6#include "io.h"
6 7
7/*=========================================================================*\
8* Exported functions
9\*=========================================================================*/
10/*-------------------------------------------------------------------------*\ 8/*-------------------------------------------------------------------------*\
11* Initializes C structure 9* Initializes C structure
12\*-------------------------------------------------------------------------*/ 10\*-------------------------------------------------------------------------*/
diff --git a/src/io.h b/src/io.h
index 8cca08a..b8a54df 100644
--- a/src/io.h
+++ b/src/io.h
@@ -12,9 +12,7 @@
12* The module socket.h implements this interface, and thus the module tcp.h 12* The module socket.h implements this interface, and thus the module tcp.h
13* is very simple. 13* is very simple.
14\*=========================================================================*/ 14\*=========================================================================*/
15#include <stdio.h> 15#include "luasocket.h"
16#include "lua.h"
17
18#include "timeout.h" 16#include "timeout.h"
19 17
20/* IO error codes */ 18/* IO error codes */
@@ -58,8 +56,15 @@ typedef struct t_io_ {
58} t_io; 56} t_io;
59typedef t_io *p_io; 57typedef t_io *p_io;
60 58
59#ifndef _WIN32
60#pragma GCC visibility push(hidden)
61#endif
62
61void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); 63void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
62const char *io_strerror(int err); 64const char *io_strerror(int err);
63 65
64#endif /* IO_H */ 66#ifndef _WIN32
67#pragma GCC visibility pop
68#endif
65 69
70#endif /* IO_H */
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 1014de2..4cb17f5 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -9,10 +9,13 @@
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10local string = require("string") 10local string = require("string")
11local table = require("table") 11local table = require("table")
12local unpack = unpack or table.unpack
12local base = _G 13local base = _G
14local select = select
15
13local _M = {} 16local _M = {}
14if module then -- heuristic for exporting a global package table 17if module then -- heuristic for exporting a global package table
15 ltn12 = _M 18 ltn12 = _M -- luacheck: ignore
16end 19end
17local filter,source,sink,pump = {},{},{},{} 20local filter,source,sink,pump = {},{},{},{}
18 21
@@ -124,6 +127,16 @@ function source.string(s)
124 else return source.empty() end 127 else return source.empty() end
125end 128end
126 129
130-- creates table source
131function source.table(t)
132 base.assert('table' == type(t))
133 local i = 0
134 return function()
135 i = i + 1
136 return t[i]
137 end
138end
139
127-- creates rewindable source 140-- creates rewindable source
128function source.rewind(src) 141function source.rewind(src)
129 base.assert(src) 142 base.assert(src)
diff --git a/src/luasocket.c b/src/luasocket.c
index 7d9c802..0fd99f7 100644..100755
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -12,16 +12,6 @@
12* standard Lua read and write functions. 12* standard Lua read and write functions.
13\*=========================================================================*/ 13\*=========================================================================*/
14 14
15/*=========================================================================*\
16* Standard include files
17\*=========================================================================*/
18#include "lua.h"
19#include "lauxlib.h"
20#include "compat.h"
21
22/*=========================================================================*\
23* LuaSocket includes
24\*=========================================================================*/
25#include "luasocket.h" 15#include "luasocket.h"
26#include "auxiliar.h" 16#include "auxiliar.h"
27#include "except.h" 17#include "except.h"
@@ -64,7 +54,7 @@ static luaL_Reg func[] = {
64* Skip a few arguments 54* Skip a few arguments
65\*-------------------------------------------------------------------------*/ 55\*-------------------------------------------------------------------------*/
66static int global_skip(lua_State *L) { 56static int global_skip(lua_State *L) {
67 int amount = luaL_checkinteger(L, 1); 57 int amount = (int) luaL_checkinteger(L, 1);
68 int ret = lua_gettop(L) - amount - 1; 58 int ret = lua_gettop(L) - amount - 1;
69 return ret >= 0 ? ret : 0; 59 return ret >= 0 ? ret : 0;
70} 60}
diff --git a/src/luasocket.h b/src/luasocket.h
index f75d21f..1017fba 100644
--- a/src/luasocket.h
+++ b/src/luasocket.h
@@ -6,21 +6,28 @@
6* Diego Nehab 6* Diego Nehab
7* 9/11/1999 7* 9/11/1999
8\*=========================================================================*/ 8\*=========================================================================*/
9#include "lua.h"
10 9
11/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------* \
12* Current socket library version 11* Current socket library version
13\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
14#define LUASOCKET_VERSION "LuaSocket 3.0-rc1" 13#define LUASOCKET_VERSION "LuaSocket 3.0.0"
15#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" 14#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
16 15
17/*-------------------------------------------------------------------------*\ 16/*-------------------------------------------------------------------------*\
18* This macro prefixes all exported API functions 17* This macro prefixes all exported API functions
19\*-------------------------------------------------------------------------*/ 18\*-------------------------------------------------------------------------*/
20#ifndef LUASOCKET_API 19#ifndef LUASOCKET_API
21#define LUASOCKET_API extern 20#ifdef _WIN32
21#define LUASOCKET_API __declspec(dllexport)
22#else
23#define LUASOCKET_API __attribute__ ((visibility ("default")))
24#endif
22#endif 25#endif
23 26
27#include "lua.h"
28#include "lauxlib.h"
29#include "compat.h"
30
24/*-------------------------------------------------------------------------*\ 31/*-------------------------------------------------------------------------*\
25* Initializes the library. 32* Initializes the library.
26\*-------------------------------------------------------------------------*/ 33\*-------------------------------------------------------------------------*/
diff --git a/src/makefile b/src/makefile
index 2704a92..06f4d19 100644..100755
--- a/src/makefile
+++ b/src/makefile
@@ -12,34 +12,31 @@
12# 12#
13# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw 13# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
14 14
15# PLAT: linux macosx win32 mingw 15# PLAT: linux macosx win32 win64 mingw
16# platform to build for 16# platform to build for
17PLAT?=linux 17PLAT?=linux
18 18
19# LUAV: 5.1 5.2 19# LUAV: 5.1 5.2 5.3 5.4
20# lua version to build against 20# lua version to build against
21LUAV?=5.1 21LUAV?=5.1
22 22
23# MYCFLAGS: to be set by user if needed 23# MYCFLAGS: to be set by user if needed
24MYCFLAGS= 24MYCFLAGS?=
25 25
26# MYLDFLAGS: to be set by user if needed 26# MYLDFLAGS: to be set by user if needed
27MYLDFLAGS= 27MYLDFLAGS?=
28 28
29# DEBUG: NODEBUG DEBUG 29# DEBUG: NODEBUG DEBUG
30# debug mode causes luasocket to collect and returns timing information useful 30# debug mode causes luasocket to collect and returns timing information useful
31# for testing and debugging luasocket itself 31# for testing and debugging luasocket itself
32DEBUG?=NODEBUG 32DEBUG?=NODEBUG
33 33
34# COMPAT: COMPAT NOCOMPAT
35# when compiling for 5.2, use LUA_COMPAT_MODULE
36COMPAT?=NOCOMPAT
37
38# where lua headers are found for macosx builds 34# where lua headers are found for macosx builds
39# LUAINC_macosx: 35# LUAINC_macosx:
40# /opt/local/include 36# /opt/local/include
41LUAINC_macosx_base?=/opt/local/include 37LUAINC_macosx_base?=/opt/local/include
42LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) 38LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) $(LUAINC_macosx_base)/lua$(LUAV) $(LUAINC_macosx_base)/lua-$(LUAV)
39
43# FIXME default should this default to fink or to macports? 40# FIXME default should this default to fink or to macports?
44# What happens when more than one Lua version is installed? 41# What happens when more than one Lua version is installed?
45LUAPREFIX_macosx?=/opt/local 42LUAPREFIX_macosx?=/opt/local
@@ -52,16 +49,16 @@ LDIR_macosx?=share/lua/$(LUAV)
52# /usr/local/include/lua$(LUAV) 49# /usr/local/include/lua$(LUAV)
53# where lua headers are found for linux builds 50# where lua headers are found for linux builds
54LUAINC_linux_base?=/usr/include 51LUAINC_linux_base?=/usr/include
55LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) 52LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) $(LUAINC_linux_base)/lua$(LUAV)
56LUAPREFIX_linux?=/usr/local 53LUAPREFIX_linux?=/usr/local
57CDIR_linux?=lib/lua/$(LUAV) 54CDIR_linux?=lib/lua/$(LUAV)
58LDIR_linux?=share/lua/$(LUAV) 55LDIR_linux?=share/lua/$(LUAV)
59 56
60# LUAINC_freebsd: 57# LUAINC_freebsd:
61# /usr/local/include/lua$(LUAV) 58# /usr/local/include/lua$(LUAV)
62# where lua headers are found for linux builds 59# where lua headers are found for freebsd builds
63LUAINC_freebsd_base?=/usr/local/include/ 60LUAINC_freebsd_base?=/usr/local/include/
64LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua$(LUAV) 61LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua/$(LUAV) $(LUAINC_freebsd_base)/lua$(LUAV)
65LUAPREFIX_freebsd?=/usr/local/ 62LUAPREFIX_freebsd?=/usr/local/
66CDIR_freebsd?=lib/lua/$(LUAV) 63CDIR_freebsd?=lib/lua/$(LUAV)
67LDIR_freebsd?=share/lua/$(LUAV) 64LDIR_freebsd?=share/lua/$(LUAV)
@@ -70,7 +67,7 @@ LDIR_freebsd?=share/lua/$(LUAV)
70# LUAINC_mingw: 67# LUAINC_mingw:
71# /opt/local/include 68# /opt/local/include
72LUAINC_mingw_base?=/usr/include 69LUAINC_mingw_base?=/usr/include
73LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) 70LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) $(LUAINC_mingw_base)/lua$(LUAV)
74LUALIB_mingw_base?=/usr/bin 71LUALIB_mingw_base?=/usr/bin
75LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll 72LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll
76LUAPREFIX_mingw?=/usr 73LUAPREFIX_mingw?=/usr
@@ -81,13 +78,32 @@ LDIR_mingw?=lua/$(LUAV)/lua
81# LUAINC_win32: 78# LUAINC_win32:
82# LUALIB_win32: 79# LUALIB_win32:
83# where lua headers and libraries are found for win32 builds 80# where lua headers and libraries are found for win32 builds
84LUAINC_win32_base?=
85LUAINC_win32?=$(LUAINC_win32_base)/lua/$(LUAV)
86PLATFORM_win32?=Release
87LUAPREFIX_win32?= 81LUAPREFIX_win32?=
88CDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32) 82LUAINC_win32?=$(LUAPREFIX_win32)/include/lua/$(LUAV) $(LUAPREFIX_win32)/include/lua$(LUAV)
89LDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)/lua 83PLATFORM_win32?=Release
90LUALIB_win32?=$(LUAPREFIX_win32)/lua/$(LUAV)/$(PLATFORM_win32) 84CDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)
85LDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)/lua
86LUALIB_win32?=$(LUAPREFIX_win32)/lib/lua/$(LUAV)/$(PLATFORM_win32)
87LUALIBNAME_win32?=lua$(subst .,,$(LUAV)).lib
88
89# LUAINC_win64:
90# LUALIB_win64:
91# where lua headers and libraries are found for win64 builds
92LUAPREFIX_win64?=
93LUAINC_win64?=$(LUAPREFIX_win64)/include/lua/$(LUAV) $(LUAPREFIX_win64)/include/lua$(LUAV)
94PLATFORM_win64?=x64/Release
95CDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)
96LDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)/lua
97LUALIB_win64?=$(LUAPREFIX_win64)/lib/lua/$(LUAV)/$(PLATFORM_win64)
98LUALIBNAME_win64?=lua$(subst .,,$(LUAV)).lib
99
100
101# LUAINC_solaris:
102LUAINC_solaris_base?=/usr/include
103LUAINC_solaris?=$(LUAINC_solaris_base)/lua/$(LUAV) $(LUAINC_solaris_base)/lua$(LUAV)
104LUAPREFIX_solaris?=/usr/local
105CDIR_solaris?=lib/lua/$(LUAV)
106LDIR_solaris?=share/lua/$(LUAV)
91 107
92# prefix: /usr/local /usr /opt/local /sw 108# prefix: /usr/local /usr /opt/local /sw
93# the top of the default install tree 109# the top of the default install tree
@@ -98,7 +114,7 @@ LDIR?=$(LDIR_$(PLAT))
98 114
99# DESTDIR: (no default) 115# DESTDIR: (no default)
100# used by package managers to install into a temporary destination 116# used by package managers to install into a temporary destination
101DESTDIR= 117DESTDIR?=
102 118
103#------ 119#------
104# Definitions below can be overridden on the make command line, but 120# Definitions below can be overridden on the make command line, but
@@ -131,11 +147,13 @@ print:
131 @echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT)) 147 @echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT))
132 @echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR) 148 @echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR)
133 @echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR) 149 @echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR)
150 @echo CFLAGS=$(CFLAGS)
151 @echo LDFLAGS=$(LDFLAGS)
134 152
135#------ 153#------
136# Supported platforms 154# Supported platforms
137# 155#
138PLATS= macosx linux win32 mingw 156PLATS= macosx linux win32 win64 mingw solaris
139 157
140#------ 158#------
141# Compiler and linker settings 159# Compiler and linker settings
@@ -143,14 +161,10 @@ PLATS= macosx linux win32 mingw
143SO_macosx=so 161SO_macosx=so
144O_macosx=o 162O_macosx=o
145CC_macosx=gcc 163CC_macosx=gcc
146DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN -DLUA_$(COMPAT)_MODULE \ 164DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
147 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 165CFLAGS_macosx=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
148 -DUNIX_API='__attribute__((visibility("default")))' \ 166LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
149 -DMIME_API='__attribute__((visibility("default")))' 167LD_macosx=gcc
150CFLAGS_macosx= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \
151 -fvisibility=hidden
152LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
153LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
154SOCKET_macosx=usocket.o 168SOCKET_macosx=usocket.o
155 169
156#------ 170#------
@@ -159,13 +173,10 @@ SOCKET_macosx=usocket.o
159SO_linux=so 173SO_linux=so
160O_linux=o 174O_linux=o
161CC_linux=gcc 175CC_linux=gcc
162DEF_linux=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 176DEF_linux=-DLUASOCKET_$(DEBUG)
163 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 177CFLAGS_linux=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
164 -DUNIX_API='__attribute__((visibility("default")))' \ 178 -Wimplicit -O2 -ggdb3 -fpic
165 -DMIME_API='__attribute__((visibility("default")))' 179LDFLAGS_linux=-O -shared -fpic -o
166CFLAGS_linux= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
167 -Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
168LDFLAGS_linux=-O -shared -fpic -o
169LD_linux=gcc 180LD_linux=gcc
170SOCKET_linux=usocket.o 181SOCKET_linux=usocket.o
171 182
@@ -175,28 +186,36 @@ SOCKET_linux=usocket.o
175SO_freebsd=so 186SO_freebsd=so
176O_freebsd=o 187O_freebsd=o
177CC_freebsd=gcc 188CC_freebsd=gcc
178DEF_freebsd=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 189DEF_freebsd=-DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
179 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 190CFLAGS_freebsd=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
180 -DUNIX_API='__attribute__((visibility("default")))' \ 191 -Wimplicit -O2 -ggdb3 -fpic
181 -DMIME_API='__attribute__((visibility("default")))' 192LDFLAGS_freebsd=-O -shared -fpic -o
182CFLAGS_freebsd= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
183 -Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
184LDFLAGS_freebsd=-O -shared -fpic -o
185LD_freebsd=gcc 193LD_freebsd=gcc
186SOCKET_freebsd=usocket.o 194SOCKET_freebsd=usocket.o
187 195
188#------ 196#------
189# Compiler and linker settings 197# Compiler and linker settings
198# for Solaris
199SO_solaris=so
200O_solaris=o
201CC_solaris=gcc
202DEF_solaris=-DLUASOCKET_$(DEBUG)
203CFLAGS_solaris=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
204 -Wimplicit -O2 -ggdb3 -fpic
205LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o
206LD_solaris=gcc
207SOCKET_solaris=usocket.o
208
209#------
210# Compiler and linker settings
190# for MingW 211# for MingW
191SO_mingw=dll 212SO_mingw=dll
192O_mingw=o 213O_mingw=o
193CC_mingw=gcc 214CC_mingw=gcc
194DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 215DEF_mingw= -DLUASOCKET_$(DEBUG) \
195 -DWINVER=0x0501 -DLUASOCKET_API='__declspec(dllexport)' \ 216 -DWINVER=0x0501
196 -DMIME_API='__declspec(dllexport)' 217CFLAGS_mingw=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
197CFLAGS_mingw= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \ 218LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
198 -fvisibility=hidden
199LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
200LD_mingw=gcc 219LD_mingw=gcc
201SOCKET_mingw=wsocket.o 220SOCKET_mingw=wsocket.o
202 221
@@ -208,34 +227,55 @@ SO_win32=dll
208O_win32=obj 227O_win32=obj
209CC_win32=cl 228CC_win32=cl
210DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \ 229DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
211 //D "LUASOCKET_API=__declspec(dllexport)" //D "_CRT_SECURE_NO_WARNINGS" \ 230 //D "_CRT_SECURE_NO_WARNINGS" \
212 //D "_WINDLL" //D "LUA_$(COMPAT)_MODULE" \ 231 //D "_WINDLL" \
213 //D "MIME_API=__declspec(dllexport)" \ 232 //D "LUASOCKET_$(DEBUG)"
214 //D "LUASOCKET_$(DEBUG)" 233CFLAGS_win32=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
215CFLAGS_win32=//I "$(LUAINC)" $(DEF) //O2 //Ot //MD //W3 //nologo
216LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \ 234LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
217 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \ 235 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \
218 //MANIFESTUAC:"level='asInvoker' uiAccess='false'" \ 236 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
219 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \ 237 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
220 //MACHINE:X86 /LIBPATH:"$(shell cmd //c echo $(LUALIB))" \ 238 //MACHINE:X86 /LIBPATH:"$(LUALIB)" \
221 lua$(subst .,,$(LUAV)).lib ws2_32.lib //OUT: 239 $(LUALIBNAME_win32) ws2_32.lib //OUT:
240
222LD_win32=cl 241LD_win32=cl
223SOCKET_win32=wsocket.obj 242SOCKET_win32=wsocket.obj
224 243
244#------
245# Compiler and linker settings
246# for Win64
247SO_win64=dll
248O_win64=obj
249CC_win64=cl
250DEF_win64= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
251 //D "_CRT_SECURE_NO_WARNINGS" \
252 //D "_WINDLL" \
253 //D "LUASOCKET_$(DEBUG)"
254CFLAGS_win64=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
255LDFLAGS_win64= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
256 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \
257 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
258 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
259 /LIBPATH:"$(LUALIB)" \
260 $(LUALIBNAME_win64) ws2_32.lib //OUT:
261
262LD_win64=cl
263SOCKET_win64=wsocket.obj
264
225.SUFFIXES: .obj 265.SUFFIXES: .obj
226 266
227.c.obj: 267.c.obj:
228 $(CC) $(LUASOCKET_CFLAGS) //Fo"$@" //c $< 268 $(CC) $(CFLAGS) //Fo"$@" //c $<
229 269
230#------ 270#------
231# Output file names 271# Output file names
232# 272#
233SO=$(SO_$(PLAT)) 273SO=$(SO_$(PLAT))
234O=$(O_$(PLAT)) 274O=$(O_$(PLAT))
235SOCKET_V=3.0-rc1 275SOCKET_V=3.0.0
236MIME_V=1.0.3 276MIME_V=1.0.3
237SOCKET_SO=socket.$(SO).$(SOCKET_V) 277SOCKET_SO=socket-$(SOCKET_V).$(SO)
238MIME_SO=mime.$(SO).$(MIME_V) 278MIME_SO=mime-$(MIME_V).$(SO)
239UNIX_SO=unix.$(SO) 279UNIX_SO=unix.$(SO)
240SERIAL_SO=serial.$(SO) 280SERIAL_SO=serial.$(SO)
241SOCKET=$(SOCKET_$(PLAT)) 281SOCKET=$(SOCKET_$(PLAT))
@@ -286,6 +326,9 @@ UNIX_OBJS=\
286 timeout.$(O) \ 326 timeout.$(O) \
287 io.$(O) \ 327 io.$(O) \
288 usocket.$(O) \ 328 usocket.$(O) \
329 unixstream.$(O) \
330 unixdgram.$(O) \
331 compat.$(O) \
289 unix.$(O) 332 unix.$(O)
290 333
291#------ 334#------
@@ -293,6 +336,7 @@ UNIX_OBJS=\
293# 336#
294SERIAL_OBJS=\ 337SERIAL_OBJS=\
295 buffer.$(O) \ 338 buffer.$(O) \
339 compat.$(O) \
296 auxiliar.$(O) \ 340 auxiliar.$(O) \
297 options.$(O) \ 341 options.$(O) \
298 timeout.$(O) \ 342 timeout.$(O) \
@@ -331,12 +375,18 @@ macosx:
331win32: 375win32:
332 $(MAKE) all PLAT=win32 376 $(MAKE) all PLAT=win32
333 377
378win64:
379 $(MAKE) all PLAT=win64
380
334linux: 381linux:
335 $(MAKE) all-unix PLAT=linux 382 $(MAKE) all-unix PLAT=linux
336 383
337mingw: 384mingw:
338 $(MAKE) all PLAT=mingw 385 $(MAKE) all PLAT=mingw
339 386
387solaris:
388 $(MAKE) all-unix PLAT=solaris
389
340none: 390none:
341 @echo "Please run" 391 @echo "Please run"
342 @echo " make PLATFORM" 392 @echo " make PLATFORM"
@@ -359,7 +409,7 @@ $(UNIX_SO): $(UNIX_OBJS)
359$(SERIAL_SO): $(SERIAL_OBJS) 409$(SERIAL_SO): $(SERIAL_OBJS)
360 $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@ 410 $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
361 411
362install: 412install:
363 $(INSTALL_DIR) $(INSTALL_TOP_LDIR) 413 $(INSTALL_DIR) $(INSTALL_TOP_LDIR)
364 $(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR) 414 $(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
365 $(INSTALL_DIR) $(INSTALL_SOCKET_LDIR) 415 $(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
diff --git a/src/mbox.lua b/src/mbox.lua
index 7724ae2..12823b0 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -1,8 +1,8 @@
1local _M = {} 1local _M = {}
2 2
3if module then 3if module then
4 mbox = _M 4 mbox = _M -- luacheck: ignore
5end 5end
6 6
7function _M.split_message(message_s) 7function _M.split_message(message_s)
8 local message = {} 8 local message = {}
@@ -29,7 +29,7 @@ end
29function _M.parse_header(header_s) 29function _M.parse_header(header_s)
30 header_s = string.gsub(header_s, "\n[ ]+", " ") 30 header_s = string.gsub(header_s, "\n[ ]+", " ")
31 header_s = string.gsub(header_s, "\n+", "") 31 header_s = string.gsub(header_s, "\n+", "")
32 local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") 32 local _, _, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
33 return name, value 33 return name, value
34end 34end
35 35
@@ -49,9 +49,9 @@ function _M.parse_headers(headers_s)
49end 49end
50 50
51function _M.parse_from(from) 51function _M.parse_from(from)
52 local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") 52 local _, _, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
53 if not address then 53 if not address then
54 _, __, address = string.find(from, "%s*(.+)%s*") 54 _, _, address = string.find(from, "%s*(.+)%s*")
55 end 55 end
56 name = name or "" 56 name = name or ""
57 address = address or "" 57 address = address or ""
@@ -61,9 +61,10 @@ function _M.parse_from(from)
61end 61end
62 62
63function _M.split_mbox(mbox_s) 63function _M.split_mbox(mbox_s)
64 mbox = {} 64 local mbox = {}
65 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" 65 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
66 local nj, i, j = 1, 1, 1 66 local nj, i
67 local j = 1
67 while 1 do 68 while 1 do
68 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) 69 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
69 if not i then break end 70 if not i then break end
diff --git a/src/mime.c b/src/mime.c
index ed44104..05602f5 100644..100755
--- a/src/mime.c
+++ b/src/mime.c
@@ -2,13 +2,10 @@
2* MIME support functions 2* MIME support functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "mime.h" 6#include "mime.h"
7#include <string.h>
8#include <ctype.h>
12 9
13/*=========================================================================*\ 10/*=========================================================================*\
14* Don't want to trust escape character constants 11* Don't want to trust escape character constants
@@ -30,12 +27,12 @@ static int mime_global_eol(lua_State *L);
30static int mime_global_dot(lua_State *L); 27static int mime_global_dot(lua_State *L);
31 28
32static size_t dot(int c, size_t state, luaL_Buffer *buffer); 29static size_t dot(int c, size_t state, luaL_Buffer *buffer);
33static void b64setup(UC *base); 30/*static void b64setup(UC *base);*/
34static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 31static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
35static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); 32static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
36static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 33static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
37 34
38static void qpsetup(UC *class, UC *unbase); 35/*static void qpsetup(UC *class, UC *unbase);*/
39static void qpquote(UC c, luaL_Buffer *buffer); 36static void qpquote(UC c, luaL_Buffer *buffer);
40static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 37static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
41static size_t qpencode(UC c, UC *input, size_t size, 38static size_t qpencode(UC c, UC *input, size_t size,
@@ -58,17 +55,111 @@ static luaL_Reg func[] = {
58/*-------------------------------------------------------------------------*\ 55/*-------------------------------------------------------------------------*\
59* Quoted-printable globals 56* Quoted-printable globals
60\*-------------------------------------------------------------------------*/ 57\*-------------------------------------------------------------------------*/
61static UC qpclass[256];
62static UC qpbase[] = "0123456789ABCDEF";
63static UC qpunbase[256];
64enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; 58enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
65 59
60static const UC qpclass[] = {
61 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
62 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
63 QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
64 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
65 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
66 QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
67 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
68 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
69 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
70 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
71 QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
72 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
73 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
74 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
75 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
76 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
77 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
78 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
79 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
80 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
81 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
82 QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
83 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
84 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
85 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
86 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
87 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
88 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
89 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
90 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
91 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
92 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
93 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
94 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
95 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
96 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
97 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
98 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
99 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
100 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
101 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
102 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
103 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
104};
105
106static const UC qpbase[] = "0123456789ABCDEF";
107
108static const UC qpunbase[] = {
109 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
110 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
111 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
112 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
113 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
114 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
115 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
116 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
117 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
118 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
119 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
120 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
121 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
122 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
123 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
124 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
125 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
126 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
128 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
129 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
130 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
131 255, 255, 255, 255, 255, 255, 255, 255
132};
133
66/*-------------------------------------------------------------------------*\ 134/*-------------------------------------------------------------------------*\
67* Base64 globals 135* Base64 globals
68\*-------------------------------------------------------------------------*/ 136\*-------------------------------------------------------------------------*/
69static const UC b64base[] = 137static const UC b64base[] =
70 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 138 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
71static UC b64unbase[256]; 139
140static const UC b64unbase[] = {
141 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
142 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
143 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
144 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
145 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
146 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
147 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
148 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
149 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
150 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
151 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
152 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
153 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
154 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
155 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
156 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
157 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
158 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
159 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
160 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
161 255, 255
162};
72 163
73/*=========================================================================*\ 164/*=========================================================================*\
74* Exported functions 165* Exported functions
@@ -76,7 +167,7 @@ static UC b64unbase[256];
76/*-------------------------------------------------------------------------*\ 167/*-------------------------------------------------------------------------*\
77* Initializes module 168* Initializes module
78\*-------------------------------------------------------------------------*/ 169\*-------------------------------------------------------------------------*/
79MIME_API int luaopen_mime_core(lua_State *L) 170LUASOCKET_API int luaopen_mime_core(lua_State *L)
80{ 171{
81 lua_newtable(L); 172 lua_newtable(L);
82 luaL_setfuncs(L, func, 0); 173 luaL_setfuncs(L, func, 0);
@@ -85,8 +176,8 @@ MIME_API int luaopen_mime_core(lua_State *L)
85 lua_pushstring(L, MIME_VERSION); 176 lua_pushstring(L, MIME_VERSION);
86 lua_rawset(L, -3); 177 lua_rawset(L, -3);
87 /* initialize lookup tables */ 178 /* initialize lookup tables */
88 qpsetup(qpclass, qpunbase); 179 /*qpsetup(qpclass, qpunbase);*/
89 b64setup(b64unbase); 180 /*b64setup(b64unbase);*/
90 return 1; 181 return 1;
91} 182}
92 183
@@ -142,6 +233,7 @@ static int mime_global_wrp(lua_State *L)
142 return 2; 233 return 2;
143} 234}
144 235
236#if 0
145/*-------------------------------------------------------------------------*\ 237/*-------------------------------------------------------------------------*\
146* Fill base64 decode map. 238* Fill base64 decode map.
147\*-------------------------------------------------------------------------*/ 239\*-------------------------------------------------------------------------*/
@@ -151,7 +243,14 @@ static void b64setup(UC *unbase)
151 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; 243 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
152 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; 244 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
153 unbase['='] = 0; 245 unbase['='] = 0;
246
247 printf("static const UC b64unbase[] = {\n");
248 for (int i = 0; i < 256; i++) {
249 printf("%d, ", unbase[i]);
250 }
251 printf("\n}\n;");
154} 252}
253#endif
155 254
156/*-------------------------------------------------------------------------*\ 255/*-------------------------------------------------------------------------*\
157* Acumulates bytes in input buffer until 3 bytes are available. 256* Acumulates bytes in input buffer until 3 bytes are available.
@@ -345,12 +444,14 @@ static int mime_global_unb64(lua_State *L)
345* To encode one byte, we need to see the next two. 444* To encode one byte, we need to see the next two.
346* Worst case is when we see a space, and wonder if a CRLF is comming 445* Worst case is when we see a space, and wonder if a CRLF is comming
347\*-------------------------------------------------------------------------*/ 446\*-------------------------------------------------------------------------*/
447#if 0
348/*-------------------------------------------------------------------------*\ 448/*-------------------------------------------------------------------------*\
349* Split quoted-printable characters into classes 449* Split quoted-printable characters into classes
350* Precompute reverse map for encoding 450* Precompute reverse map for encoding
351\*-------------------------------------------------------------------------*/ 451\*-------------------------------------------------------------------------*/
352static void qpsetup(UC *cl, UC *unbase) 452static void qpsetup(UC *cl, UC *unbase)
353{ 453{
454
354 int i; 455 int i;
355 for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; 456 for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
356 for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; 457 for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
@@ -367,7 +468,37 @@ static void qpsetup(UC *cl, UC *unbase)
367 unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; 468 unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
368 unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; 469 unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
369 unbase['f'] = 15; 470 unbase['f'] = 15;
471
472printf("static UC qpclass[] = {");
473 for (int i = 0; i < 256; i++) {
474 if (i % 6 == 0) {
475 printf("\n ");
476 }
477 switch(cl[i]) {
478 case QP_QUOTED:
479 printf("QP_QUOTED, ");
480 break;
481 case QP_PLAIN:
482 printf("QP_PLAIN, ");
483 break;
484 case QP_CR:
485 printf("QP_CR, ");
486 break;
487 case QP_IF_LAST:
488 printf("QP_IF_LAST, ");
489 break;
490 }
491 }
492printf("\n};\n");
493
494printf("static const UC qpunbase[] = {");
495 for (int i = 0; i < 256; i++) {
496 int c = qpunbase[i];
497 printf("%d, ", c);
498 }
499printf("\";\n");
370} 500}
501#endif
371 502
372/*-------------------------------------------------------------------------*\ 503/*-------------------------------------------------------------------------*\
373* Output one character in form =XX 504* Output one character in form =XX
@@ -447,7 +578,6 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
447\*-------------------------------------------------------------------------*/ 578\*-------------------------------------------------------------------------*/
448static int mime_global_qp(lua_State *L) 579static int mime_global_qp(lua_State *L)
449{ 580{
450
451 size_t asize = 0, isize = 0; 581 size_t asize = 0, isize = 0;
452 UC atom[3]; 582 UC atom[3];
453 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); 583 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
@@ -654,7 +784,7 @@ static int eolprocess(int c, int last, const char *marker,
654\*-------------------------------------------------------------------------*/ 784\*-------------------------------------------------------------------------*/
655static int mime_global_eol(lua_State *L) 785static int mime_global_eol(lua_State *L)
656{ 786{
657 int ctx = luaL_checkinteger(L, 1); 787 int ctx = (int) luaL_checkinteger(L, 1);
658 size_t isize = 0; 788 size_t isize = 0;
659 const char *input = luaL_optlstring(L, 2, NULL, &isize); 789 const char *input = luaL_optlstring(L, 2, NULL, &isize);
660 const char *last = input + isize; 790 const char *last = input + isize;
@@ -689,6 +819,7 @@ static size_t dot(int c, size_t state, luaL_Buffer *buffer)
689 case '.': 819 case '.':
690 if (state == 2) 820 if (state == 2)
691 luaL_addchar(buffer, '.'); 821 luaL_addchar(buffer, '.');
822 /* Falls through. */
692 default: 823 default:
693 return 0; 824 return 0;
694 } 825 }
diff --git a/src/mime.h b/src/mime.h
index 99968a5..4d938f4 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -8,7 +8,7 @@
8* and formatting conforming to RFC 2045. It is used by mime.lua, which 8* and formatting conforming to RFC 2045. It is used by mime.lua, which
9* provide a higher level interface to this functionality. 9* provide a higher level interface to this functionality.
10\*=========================================================================*/ 10\*=========================================================================*/
11#include "lua.h" 11#include "luasocket.h"
12 12
13/*-------------------------------------------------------------------------*\ 13/*-------------------------------------------------------------------------*\
14* Current MIME library version 14* Current MIME library version
@@ -17,13 +17,6 @@
17#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab" 17#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab"
18#define MIME_AUTHORS "Diego Nehab" 18#define MIME_AUTHORS "Diego Nehab"
19 19
20/*-------------------------------------------------------------------------*\ 20LUASOCKET_API int luaopen_mime_core(lua_State *L);
21* This macro prefixes all exported API functions
22\*-------------------------------------------------------------------------*/
23#ifndef MIME_API
24#define MIME_API extern
25#endif
26
27MIME_API int luaopen_mime_core(lua_State *L);
28 21
29#endif /* MIME_H */ 22#endif /* MIME_H */
diff --git a/src/mime.lua b/src/mime.lua
index 642cd9c..93539de 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -10,8 +10,6 @@
10local base = _G 10local base = _G
11local ltn12 = require("ltn12") 11local ltn12 = require("ltn12")
12local mime = require("mime.core") 12local mime = require("mime.core")
13local io = require("io")
14local string = require("string")
15local _M = mime 13local _M = mime
16 14
17-- encode, decode and wrap algorithm tables 15-- encode, decode and wrap algorithm tables
@@ -19,7 +17,7 @@ local encodet, decodet, wrapt = {},{},{}
19 17
20_M.encodet = encodet 18_M.encodet = encodet
21_M.decodet = decodet 19_M.decodet = decodet
22_M.wrapt = wrapt 20_M.wrapt = wrapt
23 21
24-- creates a function that chooses a filter by name from a given table 22-- creates a function that chooses a filter by name from a given table
25local function choose(table) 23local function choose(table)
@@ -28,7 +26,7 @@ local function choose(table)
28 name, opt1, opt2 = "default", name, opt1 26 name, opt1, opt2 = "default", name, opt1
29 end 27 end
30 local f = table[name or "nil"] 28 local f = table[name or "nil"]
31 if not f then 29 if not f then
32 base.error("unknown key (" .. base.tostring(name) .. ")", 3) 30 base.error("unknown key (" .. base.tostring(name) .. ")", 3)
33 else return f(opt1, opt2) end 31 else return f(opt1, opt2) end
34 end 32 end
@@ -53,13 +51,6 @@ decodet['quoted-printable'] = function()
53 return ltn12.filter.cycle(_M.unqp, "") 51 return ltn12.filter.cycle(_M.unqp, "")
54end 52end
55 53
56local function format(chunk)
57 if chunk then
58 if chunk == "" then return "''"
59 else return string.len(chunk) end
60 else return "nil" end
61end
62
63-- define the line-wrap filters 54-- define the line-wrap filters
64wrapt['text'] = function(length) 55wrapt['text'] = function(length)
65 length = length or 76 56 length = length or 76
@@ -87,4 +78,4 @@ function _M.stuff()
87 return ltn12.filter.cycle(_M.dot, 2) 78 return ltn12.filter.cycle(_M.dot, 2)
88end 79end
89 80
90return _M \ No newline at end of file 81return _M
diff --git a/src/options.c b/src/options.c
index 20f4c28..9dea6bd 100644
--- a/src/options.c
+++ b/src/options.c
@@ -2,14 +2,11 @@
2* Common option interface 2* Common option interface
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lauxlib.h"
8
9#include "auxiliar.h" 6#include "auxiliar.h"
10#include "options.h" 7#include "options.h"
11#include "inet.h" 8#include "inet.h"
12 9#include <string.h>
13 10
14/*=========================================================================*\ 11/*=========================================================================*\
15* Internal functions prototypes 12* Internal functions prototypes
@@ -37,7 +34,7 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
37 while (opt->name && strcmp(name, opt->name)) 34 while (opt->name && strcmp(name, opt->name))
38 opt++; 35 opt++;
39 if (!opt->func) { 36 if (!opt->func) {
40 char msg[45]; 37 char msg[57];
41 sprintf(msg, "unsupported option `%.35s'", name); 38 sprintf(msg, "unsupported option `%.35s'", name);
42 luaL_argerror(L, 2, msg); 39 luaL_argerror(L, 2, msg);
43 } 40 }
@@ -50,13 +47,41 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
50 while (opt->name && strcmp(name, opt->name)) 47 while (opt->name && strcmp(name, opt->name))
51 opt++; 48 opt++;
52 if (!opt->func) { 49 if (!opt->func) {
53 char msg[45]; 50 char msg[57];
54 sprintf(msg, "unsupported option `%.35s'", name); 51 sprintf(msg, "unsupported option `%.35s'", name);
55 luaL_argerror(L, 2, msg); 52 luaL_argerror(L, 2, msg);
56 } 53 }
57 return opt->func(L, ps); 54 return opt->func(L, ps);
58} 55}
59 56
57/*------------------------------------------------------*/
58/* binds socket to network interface */
59int opt_set_bindtodevice(lua_State *L, p_socket ps)
60{
61#ifndef SO_BINDTODEVICE
62 return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
63#else
64 const char *dev = luaL_checkstring(L, 3);
65 return opt_set(L, ps, SOL_SOCKET, SO_BINDTODEVICE, (char*)dev, strlen(dev)+1);
66#endif
67}
68
69int opt_get_bindtodevice(lua_State *L, p_socket ps)
70{
71#ifndef SO_BINDTODEVICE
72 return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
73#else
74 char dev[IFNAMSIZ];
75 int len = sizeof(dev);
76 int err = opt_get(L, ps, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len);
77 if (err)
78 return err;
79 lua_pushstring(L, dev);
80 return 1;
81#endif
82}
83
84/*------------------------------------------------------*/
60/* enables reuse of local address */ 85/* enables reuse of local address */
61int opt_set_reuseaddr(lua_State *L, p_socket ps) 86int opt_set_reuseaddr(lua_State *L, p_socket ps)
62{ 87{
@@ -68,6 +93,7 @@ int opt_get_reuseaddr(lua_State *L, p_socket ps)
68 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); 93 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
69} 94}
70 95
96/*------------------------------------------------------*/
71/* enables reuse of local port */ 97/* enables reuse of local port */
72int opt_set_reuseport(lua_State *L, p_socket ps) 98int opt_set_reuseport(lua_State *L, p_socket ps)
73{ 99{
@@ -79,7 +105,8 @@ int opt_get_reuseport(lua_State *L, p_socket ps)
79 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); 105 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
80} 106}
81 107
82/* disables the Naggle algorithm */ 108/*------------------------------------------------------*/
109/* disables the Nagle algorithm */
83int opt_set_tcp_nodelay(lua_State *L, p_socket ps) 110int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
84{ 111{
85 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 112 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
@@ -90,6 +117,52 @@ int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
90 return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 117 return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
91} 118}
92 119
120/*------------------------------------------------------*/
121#ifdef TCP_KEEPIDLE
122
123int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
124{
125 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
126}
127
128int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
129{
130 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
131}
132
133#endif
134
135/*------------------------------------------------------*/
136#ifdef TCP_KEEPCNT
137
138int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
139{
140 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
141}
142
143int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
144{
145 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
146}
147
148#endif
149
150/*------------------------------------------------------*/
151#ifdef TCP_KEEPINTVL
152
153int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
154{
155 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
156}
157
158int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
159{
160 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
161}
162
163#endif
164
165/*------------------------------------------------------*/
93int opt_set_keepalive(lua_State *L, p_socket ps) 166int opt_set_keepalive(lua_State *L, p_socket ps)
94{ 167{
95 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 168 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
@@ -100,6 +173,7 @@ int opt_get_keepalive(lua_State *L, p_socket ps)
100 return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 173 return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
101} 174}
102 175
176/*------------------------------------------------------*/
103int opt_set_dontroute(lua_State *L, p_socket ps) 177int opt_set_dontroute(lua_State *L, p_socket ps)
104{ 178{
105 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); 179 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
@@ -110,6 +184,7 @@ int opt_get_dontroute(lua_State *L, p_socket ps)
110 return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); 184 return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
111} 185}
112 186
187/*------------------------------------------------------*/
113int opt_set_broadcast(lua_State *L, p_socket ps) 188int opt_set_broadcast(lua_State *L, p_socket ps)
114{ 189{
115 return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); 190 return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
@@ -120,6 +195,54 @@ int opt_get_broadcast(lua_State *L, p_socket ps)
120 return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); 195 return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
121} 196}
122 197
198/*------------------------------------------------------*/
199int opt_set_recv_buf_size(lua_State *L, p_socket ps)
200{
201 return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
202}
203
204int opt_get_recv_buf_size(lua_State *L, p_socket ps)
205{
206 return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
207}
208
209/*------------------------------------------------------*/
210int opt_get_send_buf_size(lua_State *L, p_socket ps)
211{
212 return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
213}
214
215int opt_set_send_buf_size(lua_State *L, p_socket ps)
216{
217 return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
218}
219
220/*------------------------------------------------------*/
221
222#ifdef TCP_FASTOPEN
223int opt_set_tcp_fastopen(lua_State *L, p_socket ps)
224{
225 return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN);
226}
227#endif
228
229#ifdef TCP_FASTOPEN_CONNECT
230int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps)
231{
232 return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT);
233}
234#endif
235
236/*------------------------------------------------------*/
237
238#ifdef TCP_DEFER_ACCEPT
239int opt_set_tcp_defer_accept(lua_State *L, p_socket ps)
240{
241 return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT);
242}
243#endif
244
245/*------------------------------------------------------*/
123int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) 246int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
124{ 247{
125 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); 248 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
@@ -130,6 +253,7 @@ int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
130 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); 253 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
131} 254}
132 255
256/*------------------------------------------------------*/
133int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) 257int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
134{ 258{
135 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); 259 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
@@ -140,6 +264,7 @@ int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
140 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); 264 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
141} 265}
142 266
267/*------------------------------------------------------*/
143int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) 268int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
144{ 269{
145 return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); 270 return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
@@ -150,6 +275,7 @@ int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
150 return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); 275 return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
151} 276}
152 277
278/*------------------------------------------------------*/
153int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) 279int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
154{ 280{
155 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); 281 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
@@ -160,6 +286,7 @@ int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
160 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); 286 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
161} 287}
162 288
289/*------------------------------------------------------*/
163int opt_set_linger(lua_State *L, p_socket ps) 290int opt_set_linger(lua_State *L, p_socket ps)
164{ 291{
165 struct linger li; /* obj, name, table */ 292 struct linger li; /* obj, name, table */
@@ -192,11 +319,13 @@ int opt_get_linger(lua_State *L, p_socket ps)
192 return 1; 319 return 1;
193} 320}
194 321
322/*------------------------------------------------------*/
195int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) 323int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
196{ 324{
197 return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); 325 return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
198} 326}
199 327
328/*------------------------------------------------------*/
200int opt_set_ip_multicast_if(lua_State *L, p_socket ps) 329int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
201{ 330{
202 const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ 331 const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
@@ -221,6 +350,7 @@ int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
221 return 1; 350 return 1;
222} 351}
223 352
353/*------------------------------------------------------*/
224int opt_set_ip_add_membership(lua_State *L, p_socket ps) 354int opt_set_ip_add_membership(lua_State *L, p_socket ps)
225{ 355{
226 return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); 356 return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
@@ -231,6 +361,7 @@ int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
231 return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); 361 return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
232} 362}
233 363
364/*------------------------------------------------------*/
234int opt_set_ip6_add_membership(lua_State *L, p_socket ps) 365int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
235{ 366{
236 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); 367 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
@@ -241,6 +372,7 @@ int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
241 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); 372 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
242} 373}
243 374
375/*------------------------------------------------------*/
244int opt_get_ip6_v6only(lua_State *L, p_socket ps) 376int opt_get_ip6_v6only(lua_State *L, p_socket ps)
245{ 377{
246 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); 378 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
@@ -251,6 +383,20 @@ int opt_set_ip6_v6only(lua_State *L, p_socket ps)
251 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); 383 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
252} 384}
253 385
386/*------------------------------------------------------*/
387int opt_get_error(lua_State *L, p_socket ps)
388{
389 int val = 0;
390 socklen_t len = sizeof(val);
391 if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
392 lua_pushnil(L);
393 lua_pushstring(L, "getsockopt failed");
394 return 2;
395 }
396 lua_pushstring(L, socket_strerror(val));
397 return 1;
398}
399
254/*=========================================================================*\ 400/*=========================================================================*\
255* Auxiliar functions 401* Auxiliar functions
256\*=========================================================================*/ 402\*=========================================================================*/
@@ -337,19 +483,6 @@ static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
337 return 1; 483 return 1;
338} 484}
339 485
340int opt_get_error(lua_State *L, p_socket ps)
341{
342 int val = 0;
343 socklen_t len = sizeof(val);
344 if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
345 lua_pushnil(L);
346 lua_pushstring(L, "getsockopt failed");
347 return 2;
348 }
349 lua_pushstring(L, socket_strerror(val));
350 return 1;
351}
352
353static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) 486static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
354{ 487{
355 int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ 488 int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
diff --git a/src/options.h b/src/options.h
index ad1b00d..26d6f02 100644
--- a/src/options.h
+++ b/src/options.h
@@ -8,7 +8,7 @@
8* modules UDP and TCP. 8* modules UDP and TCP.
9\*=========================================================================*/ 9\*=========================================================================*/
10 10
11#include "lua.h" 11#include "luasocket.h"
12#include "socket.h" 12#include "socket.h"
13 13
14/* option registry */ 14/* option registry */
@@ -18,45 +18,99 @@ typedef struct t_opt {
18} t_opt; 18} t_opt;
19typedef t_opt *p_opt; 19typedef t_opt *p_opt;
20 20
21/* supported options for setoption */ 21#ifndef _WIN32
22int opt_set_dontroute(lua_State *L, p_socket ps); 22#pragma GCC visibility push(hidden)
23int opt_set_broadcast(lua_State *L, p_socket ps); 23#endif
24
25int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
26int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
27
24int opt_set_reuseaddr(lua_State *L, p_socket ps); 28int opt_set_reuseaddr(lua_State *L, p_socket ps);
29int opt_get_reuseaddr(lua_State *L, p_socket ps);
30
31int opt_set_reuseport(lua_State *L, p_socket ps);
32int opt_get_reuseport(lua_State *L, p_socket ps);
33
25int opt_set_tcp_nodelay(lua_State *L, p_socket ps); 34int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
35int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
36
37#ifdef TCP_KEEPIDLE
38int opt_set_tcp_keepidle(lua_State *L, p_socket ps);
39int opt_get_tcp_keepidle(lua_State *L, p_socket ps);
40#endif
41
42#ifdef TCP_KEEPCNT
43int opt_set_tcp_keepcnt(lua_State *L, p_socket ps);
44int opt_get_tcp_keepcnt(lua_State *L, p_socket ps);
45#endif
46
47#ifdef TCP_KEEPINTVL
48int opt_set_tcp_keepintvl(lua_State *L, p_socket ps);
49int opt_get_tcp_keepintvl(lua_State *L, p_socket ps);
50#endif
51
52#ifdef TCP_DEFER_ACCEPT
53int opt_set_tcp_defer_accept(lua_State *L, p_socket ps);
54#endif
55
56int opt_set_bindtodevice(lua_State *L, p_socket ps);
57int opt_get_bindtodevice(lua_State *L, p_socket ps);
58
26int opt_set_keepalive(lua_State *L, p_socket ps); 59int opt_set_keepalive(lua_State *L, p_socket ps);
60int opt_get_keepalive(lua_State *L, p_socket ps);
61
62int opt_set_dontroute(lua_State *L, p_socket ps);
63int opt_get_dontroute(lua_State *L, p_socket ps);
64
65int opt_set_broadcast(lua_State *L, p_socket ps);
66int opt_get_broadcast(lua_State *L, p_socket ps);
67
68int opt_set_recv_buf_size(lua_State *L, p_socket ps);
69int opt_get_recv_buf_size(lua_State *L, p_socket ps);
70
71int opt_set_send_buf_size(lua_State *L, p_socket ps);
72int opt_get_send_buf_size(lua_State *L, p_socket ps);
73
74#ifdef TCP_FASTOPEN
75int opt_set_tcp_fastopen(lua_State *L, p_socket ps);
76#endif
77#ifdef TCP_FASTOPEN_CONNECT
78int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps);
79#endif
80
81int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
82int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
83
84int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
85int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
86
87int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
88int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
89
90int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
91int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
92
27int opt_set_linger(lua_State *L, p_socket ps); 93int opt_set_linger(lua_State *L, p_socket ps);
28int opt_set_reuseaddr(lua_State *L, p_socket ps); 94int opt_get_linger(lua_State *L, p_socket ps);
29int opt_set_reuseport(lua_State *L, p_socket ps); 95
30int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
31int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); 96int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
32int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); 97
98int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
99int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
100
33int opt_set_ip_add_membership(lua_State *L, p_socket ps); 101int opt_set_ip_add_membership(lua_State *L, p_socket ps);
34int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); 102int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
35int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); 103
36int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
37int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
38int opt_set_ip6_add_membership(lua_State *L, p_socket ps); 104int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
39int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); 105int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
106
40int opt_set_ip6_v6only(lua_State *L, p_socket ps); 107int opt_set_ip6_v6only(lua_State *L, p_socket ps);
108int opt_get_ip6_v6only(lua_State *L, p_socket ps);
41 109
42/* supported options for getoption */
43int opt_get_dontroute(lua_State *L, p_socket ps);
44int opt_get_broadcast(lua_State *L, p_socket ps);
45int opt_get_reuseaddr(lua_State *L, p_socket ps);
46int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
47int opt_get_keepalive(lua_State *L, p_socket ps);
48int opt_get_linger(lua_State *L, p_socket ps);
49int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
50int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
51int opt_get_error(lua_State *L, p_socket ps); 110int opt_get_error(lua_State *L, p_socket ps);
52int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
53int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
54int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
55int opt_get_ip6_v6only(lua_State *L, p_socket ps);
56int opt_get_reuseport(lua_State *L, p_socket ps);
57 111
58/* invokes the appropriate option handler */ 112#ifndef _WIN32
59int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); 113#pragma GCC visibility pop
60int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); 114#endif
61 115
62#endif 116#endif
diff --git a/src/select.c b/src/select.c
index d14c40a..bb47c45 100644
--- a/src/select.c
+++ b/src/select.c
@@ -2,16 +2,14 @@
2* Select implementation 2* Select implementation
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10 6
11#include "socket.h" 7#include "socket.h"
12#include "timeout.h" 8#include "timeout.h"
13#include "select.h" 9#include "select.h"
14 10
11#include <string.h>
12
15/*=========================================================================*\ 13/*=========================================================================*\
16* Internal function prototypes. 14* Internal function prototypes.
17\*=========================================================================*/ 15\*=========================================================================*/
@@ -31,15 +29,15 @@ static luaL_Reg func[] = {
31 {NULL, NULL} 29 {NULL, NULL}
32}; 30};
33 31
34/*=========================================================================*\
35* Exported functions
36\*=========================================================================*/
37/*-------------------------------------------------------------------------*\ 32/*-------------------------------------------------------------------------*\
38* Initializes module 33* Initializes module
39\*-------------------------------------------------------------------------*/ 34\*-------------------------------------------------------------------------*/
40int select_open(lua_State *L) { 35int select_open(lua_State *L) {
41 lua_pushstring(L, "_SETSIZE"); 36 lua_pushstring(L, "_SETSIZE");
42 lua_pushnumber(L, FD_SETSIZE); 37 lua_pushinteger(L, FD_SETSIZE);
38 lua_rawset(L, -3);
39 lua_pushstring(L, "_SOCKETINVALID");
40 lua_pushinteger(L, SOCKET_INVALID);
43 lua_rawset(L, -3); 41 lua_rawset(L, -3);
44 luaL_setfuncs(L, func, 0); 42 luaL_setfuncs(L, func, 0);
45 return 0; 43 return 0;
@@ -214,4 +212,3 @@ static void make_assoc(lua_State *L, int tab) {
214 i = i+1; 212 i = i+1;
215 } 213 }
216} 214}
217
diff --git a/src/select.h b/src/select.h
index 8750200..5d45fe7 100644
--- a/src/select.h
+++ b/src/select.h
@@ -10,6 +10,14 @@
10* true if there is data ready for reading (required for buffered input). 10* true if there is data ready for reading (required for buffered input).
11\*=========================================================================*/ 11\*=========================================================================*/
12 12
13#ifndef _WIN32
14#pragma GCC visibility push(hidden)
15#endif
16
13int select_open(lua_State *L); 17int select_open(lua_State *L);
14 18
19#ifndef _WIN32
20#pragma GCC visibility pop
21#endif
22
15#endif /* SELECT_H */ 23#endif /* SELECT_H */
diff --git a/src/serial.c b/src/serial.c
index 7bdb21c..21485d3 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -2,15 +2,14 @@
2* Serial stream 2* Serial stream
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9 6
10#include "auxiliar.h" 7#include "auxiliar.h"
11#include "socket.h" 8#include "socket.h"
12#include "options.h" 9#include "options.h"
13#include "unix.h" 10#include "unix.h"
11
12#include <string.h>
14#include <sys/un.h> 13#include <sys/un.h>
15 14
16/* 15/*
diff --git a/src/socket.h b/src/socket.h
index 63573de..2555bab 100644..100755
--- a/src/socket.h
+++ b/src/socket.h
@@ -16,8 +16,10 @@
16\*=========================================================================*/ 16\*=========================================================================*/
17#ifdef _WIN32 17#ifdef _WIN32
18#include "wsocket.h" 18#include "wsocket.h"
19#define LUA_GAI_STRERROR gai_strerrorA
19#else 20#else
20#include "usocket.h" 21#include "usocket.h"
22#define LUA_GAI_STRERROR gai_strerror
21#endif 23#endif
22 24
23/*=========================================================================*\ 25/*=========================================================================*\
@@ -28,51 +30,46 @@
28\*=========================================================================*/ 30\*=========================================================================*/
29#include "timeout.h" 31#include "timeout.h"
30 32
31/* we are lazy... */ 33/* convenient shorthand */
32typedef struct sockaddr SA; 34typedef struct sockaddr SA;
33 35
34/*=========================================================================*\ 36/*=========================================================================*\
35* Functions bellow implement a comfortable platform independent 37* Functions bellow implement a comfortable platform independent
36* interface to sockets 38* interface to sockets
37\*=========================================================================*/ 39\*=========================================================================*/
38int socket_open(void);
39int socket_close(void);
40void socket_destroy(p_socket ps);
41void socket_shutdown(p_socket ps, int how);
42int socket_sendto(p_socket ps, const char *data, size_t count,
43 size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
44int socket_recvfrom(p_socket ps, char *data, size_t count,
45 size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
46 40
47void socket_setnonblocking(p_socket ps); 41#ifndef _WIN32
48void socket_setblocking(p_socket ps); 42#pragma GCC visibility push(hidden)
43#endif
49 44
50int socket_waitfd(p_socket ps, int sw, p_timeout tm); 45int socket_waitfd(p_socket ps, int sw, p_timeout tm);
51int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 46int socket_open(void);
52 p_timeout tm); 47int socket_close(void);
53 48void socket_destroy(p_socket ps);
54int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); 49int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_timeout tm);
55int socket_create(p_socket ps, int domain, int type, int protocol); 50int socket_create(p_socket ps, int domain, int type, int protocol);
56int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); 51int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
57int socket_listen(p_socket ps, int backlog); 52int socket_listen(p_socket ps, int backlog);
58int socket_accept(p_socket ps, p_socket pa, SA *addr, 53void socket_shutdown(p_socket ps, int how);
59 socklen_t *addr_len, p_timeout tm); 54int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
60 55int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *addr_len, p_timeout tm);
61const char *socket_hoststrerror(int err); 56int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
62const char *socket_gaistrerror(int err); 57int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
63const char *socket_strerror(int err);
64
65/* these are perfect to use with the io abstraction module
66 and the buffered input module */
67int socket_send(p_socket ps, const char *data, size_t count,
68 size_t *sent, p_timeout tm);
69int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 58int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
70int socket_write(p_socket ps, const char *data, size_t count, 59int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
71 size_t *sent, p_timeout tm); 60int socket_write(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
72int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 61int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
73const char *socket_ioerror(p_socket ps, int err); 62void socket_setblocking(p_socket ps);
74 63void socket_setnonblocking(p_socket ps);
75int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); 64int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
76int socket_gethostbyname(const char *addr, struct hostent **hp); 65int socket_gethostbyname(const char *addr, struct hostent **hp);
66const char *socket_hoststrerror(int err);
67const char *socket_strerror(int err);
68const char *socket_ioerror(p_socket ps, int err);
69const char *socket_gaistrerror(int err);
70
71#ifndef _WIN32
72#pragma GCC visibility pop
73#endif
77 74
78#endif /* SOCKET_H */ 75#endif /* SOCKET_H */
diff --git a/src/tcp.c b/src/tcp.c
index 7bf1af5..f001206 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -2,11 +2,7 @@
2* TCP object 2* TCP object
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10 6
11#include "auxiliar.h" 7#include "auxiliar.h"
12#include "socket.h" 8#include "socket.h"
@@ -14,6 +10,8 @@
14#include "options.h" 10#include "options.h"
15#include "tcp.h" 11#include "tcp.h"
16 12
13#include <string.h>
14
17/*=========================================================================*\ 15/*=========================================================================*\
18* Internal function prototypes 16* Internal function prototypes
19\*=========================================================================*/ 17\*=========================================================================*/
@@ -36,6 +34,7 @@ static int meth_accept(lua_State *L);
36static int meth_close(lua_State *L); 34static int meth_close(lua_State *L);
37static int meth_getoption(lua_State *L); 35static int meth_getoption(lua_State *L);
38static int meth_setoption(lua_State *L); 36static int meth_setoption(lua_State *L);
37static int meth_gettimeout(lua_State *L);
39static int meth_settimeout(lua_State *L); 38static int meth_settimeout(lua_State *L);
40static int meth_getfd(lua_State *L); 39static int meth_getfd(lua_State *L);
41static int meth_setfd(lua_State *L); 40static int meth_setfd(lua_State *L);
@@ -65,26 +64,62 @@ static luaL_Reg tcp_methods[] = {
65 {"setpeername", meth_connect}, 64 {"setpeername", meth_connect},
66 {"setsockname", meth_bind}, 65 {"setsockname", meth_bind},
67 {"settimeout", meth_settimeout}, 66 {"settimeout", meth_settimeout},
67 {"gettimeout", meth_gettimeout},
68 {"shutdown", meth_shutdown}, 68 {"shutdown", meth_shutdown},
69 {NULL, NULL} 69 {NULL, NULL}
70}; 70};
71 71
72/* socket option handlers */ 72/* socket option handlers */
73static t_opt optget[] = { 73static t_opt optget[] = {
74 {"bindtodevice", opt_get_bindtodevice},
74 {"keepalive", opt_get_keepalive}, 75 {"keepalive", opt_get_keepalive},
75 {"reuseaddr", opt_get_reuseaddr}, 76 {"reuseaddr", opt_get_reuseaddr},
77 {"reuseport", opt_get_reuseport},
76 {"tcp-nodelay", opt_get_tcp_nodelay}, 78 {"tcp-nodelay", opt_get_tcp_nodelay},
79#ifdef TCP_KEEPIDLE
80 {"tcp-keepidle", opt_get_tcp_keepidle},
81#endif
82#ifdef TCP_KEEPCNT
83 {"tcp-keepcnt", opt_get_tcp_keepcnt},
84#endif
85#ifdef TCP_KEEPINTVL
86 {"tcp-keepintvl", opt_get_tcp_keepintvl},
87#endif
77 {"linger", opt_get_linger}, 88 {"linger", opt_get_linger},
78 {"error", opt_get_error}, 89 {"error", opt_get_error},
90 {"recv-buffer-size", opt_get_recv_buf_size},
91 {"send-buffer-size", opt_get_send_buf_size},
79 {NULL, NULL} 92 {NULL, NULL}
80}; 93};
81 94
82static t_opt optset[] = { 95static t_opt optset[] = {
96 {"bindtodevice", opt_set_bindtodevice},
83 {"keepalive", opt_set_keepalive}, 97 {"keepalive", opt_set_keepalive},
84 {"reuseaddr", opt_set_reuseaddr}, 98 {"reuseaddr", opt_set_reuseaddr},
99 {"reuseport", opt_set_reuseport},
85 {"tcp-nodelay", opt_set_tcp_nodelay}, 100 {"tcp-nodelay", opt_set_tcp_nodelay},
101#ifdef TCP_KEEPIDLE
102 {"tcp-keepidle", opt_set_tcp_keepidle},
103#endif
104#ifdef TCP_KEEPCNT
105 {"tcp-keepcnt", opt_set_tcp_keepcnt},
106#endif
107#ifdef TCP_KEEPINTVL
108 {"tcp-keepintvl", opt_set_tcp_keepintvl},
109#endif
86 {"ipv6-v6only", opt_set_ip6_v6only}, 110 {"ipv6-v6only", opt_set_ip6_v6only},
87 {"linger", opt_set_linger}, 111 {"linger", opt_set_linger},
112 {"recv-buffer-size", opt_set_recv_buf_size},
113 {"send-buffer-size", opt_set_send_buf_size},
114#ifdef TCP_DEFER_ACCEPT
115 {"tcp-defer-accept", opt_set_tcp_defer_accept},
116#endif
117#ifdef TCP_FASTOPEN
118 {"tcp-fastopen", opt_set_tcp_fastopen},
119#endif
120#ifdef TCP_FASTOPEN_CONNECT
121 {"tcp-fastopen-connect", opt_set_tcp_fastopen_connect},
122#endif
88 {NULL, NULL} 123 {NULL, NULL}
89}; 124};
90 125
@@ -348,6 +383,12 @@ static int meth_settimeout(lua_State *L)
348 return timeout_meth_settimeout(L, &tcp->tm); 383 return timeout_meth_settimeout(L, &tcp->tm);
349} 384}
350 385
386static int meth_gettimeout(lua_State *L)
387{
388 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
389 return timeout_meth_gettimeout(L, &tcp->tm);
390}
391
351/*=========================================================================*\ 392/*=========================================================================*\
352* Library functions 393* Library functions
353\*=========================================================================*/ 394\*=========================================================================*/
@@ -415,7 +456,7 @@ static int global_connect(lua_State *L) {
415 bindhints.ai_family = family; 456 bindhints.ai_family = family;
416 bindhints.ai_flags = AI_PASSIVE; 457 bindhints.ai_flags = AI_PASSIVE;
417 if (localaddr) { 458 if (localaddr) {
418 err = inet_trybind(&tcp->sock, &tcp->family, localaddr, 459 err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
419 localserv, &bindhints); 460 localserv, &bindhints);
420 if (err) { 461 if (err) {
421 lua_pushnil(L); 462 lua_pushnil(L);
@@ -427,7 +468,7 @@ static int global_connect(lua_State *L) {
427 memset(&connecthints, 0, sizeof(connecthints)); 468 memset(&connecthints, 0, sizeof(connecthints));
428 connecthints.ai_socktype = SOCK_STREAM; 469 connecthints.ai_socktype = SOCK_STREAM;
429 /* make sure we try to connect only to the same family */ 470 /* make sure we try to connect only to the same family */
430 connecthints.ai_family = tcp->family; 471 connecthints.ai_family = tcp->family;
431 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, 472 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
432 &tcp->tm, &connecthints); 473 &tcp->tm, &connecthints);
433 if (err) { 474 if (err) {
diff --git a/src/tcp.h b/src/tcp.h
index eded620..9b282ef 100644
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -14,7 +14,7 @@
14* tcp objects either connected to some address or returned by the accept 14* tcp objects either connected to some address or returned by the accept
15* method of a server object. 15* method of a server object.
16\*=========================================================================*/ 16\*=========================================================================*/
17#include "lua.h" 17#include "luasocket.h"
18 18
19#include "buffer.h" 19#include "buffer.h"
20#include "timeout.h" 20#include "timeout.h"
@@ -30,6 +30,14 @@ typedef struct t_tcp_ {
30 30
31typedef t_tcp *p_tcp; 31typedef t_tcp *p_tcp;
32 32
33#ifndef _WIN32
34#pragma GCC visibility push(hidden)
35#endif
36
33int tcp_open(lua_State *L); 37int tcp_open(lua_State *L);
34 38
39#ifndef _WIN32
40#pragma GCC visibility pop
41#endif
42
35#endif /* TCP_H */ 43#endif /* TCP_H */
diff --git a/src/timeout.c b/src/timeout.c
index 087d033..2bdc069 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -2,17 +2,15 @@
2* Timeout management functions 2* Timeout management functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <stdio.h> 5#include "luasocket.h"
6#include <limits.h>
7#include <float.h>
8
9#include "lua.h"
10#include "lauxlib.h"
11#include "compat.h"
12 6
13#include "auxiliar.h" 7#include "auxiliar.h"
14#include "timeout.h" 8#include "timeout.h"
15 9
10#include <stdio.h>
11#include <limits.h>
12#include <float.h>
13
16#ifdef _WIN32 14#ifdef _WIN32
17#include <windows.h> 15#include <windows.h>
18#else 16#else
@@ -173,6 +171,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
173 return 1; 171 return 1;
174} 172}
175 173
174/*-------------------------------------------------------------------------*\
175* Gets timeout values for IO operations
176* Lua Output: block, total
177\*-------------------------------------------------------------------------*/
178int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
179 lua_pushnumber(L, tm->block);
180 lua_pushnumber(L, tm->total);
181 return 2;
182}
183
176/*=========================================================================*\ 184/*=========================================================================*\
177* Test support functions 185* Test support functions
178\*=========================================================================*/ 186\*=========================================================================*/
diff --git a/src/timeout.h b/src/timeout.h
index 6715ca7..9e5250d 100644
--- a/src/timeout.h
+++ b/src/timeout.h
@@ -4,7 +4,7 @@
4* Timeout management functions 4* Timeout management functions
5* LuaSocket toolkit 5* LuaSocket toolkit
6\*=========================================================================*/ 6\*=========================================================================*/
7#include "lua.h" 7#include "luasocket.h"
8 8
9/* timeout control structure */ 9/* timeout control structure */
10typedef struct t_timeout_ { 10typedef struct t_timeout_ {
@@ -14,14 +14,26 @@ typedef struct t_timeout_ {
14} t_timeout; 14} t_timeout;
15typedef t_timeout *p_timeout; 15typedef t_timeout *p_timeout;
16 16
17int timeout_open(lua_State *L); 17#ifndef _WIN32
18#pragma GCC visibility push(hidden)
19#endif
20
18void timeout_init(p_timeout tm, double block, double total); 21void timeout_init(p_timeout tm, double block, double total);
19double timeout_get(p_timeout tm); 22double timeout_get(p_timeout tm);
23double timeout_getstart(p_timeout tm);
20double timeout_getretry(p_timeout tm); 24double timeout_getretry(p_timeout tm);
21p_timeout timeout_markstart(p_timeout tm); 25p_timeout timeout_markstart(p_timeout tm);
22double timeout_getstart(p_timeout tm); 26
23double timeout_gettime(void); 27double timeout_gettime(void);
28
29int timeout_open(lua_State *L);
30
24int timeout_meth_settimeout(lua_State *L, p_timeout tm); 31int timeout_meth_settimeout(lua_State *L, p_timeout tm);
32int timeout_meth_gettimeout(lua_State *L, p_timeout tm);
33
34#ifndef _WIN32
35#pragma GCC visibility pop
36#endif
25 37
26#define timeout_iszero(tm) ((tm)->block == 0.0) 38#define timeout_iszero(tm) ((tm)->block == 0.0)
27 39
diff --git a/src/tp.lua b/src/tp.lua
index cbeff56..b8ebc56 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -46,6 +46,14 @@ end
46-- metatable for sock object 46-- metatable for sock object
47local metat = { __index = {} } 47local metat = { __index = {} }
48 48
49function metat.__index:getpeername()
50 return self.c:getpeername()
51end
52
53function metat.__index:getsockname()
54 return self.c:getpeername()
55end
56
49function metat.__index:check(ok) 57function metat.__index:check(ok)
50 local code, reply = get_reply(self.c) 58 local code, reply = get_reply(self.c)
51 if not code then return nil, reply end 59 if not code then return nil, reply end
@@ -74,7 +82,7 @@ function metat.__index:command(cmd, arg)
74end 82end
75 83
76function metat.__index:sink(snk, pat) 84function metat.__index:sink(snk, pat)
77 local chunk, err = c:receive(pat) 85 local chunk, err = self.c:receive(pat)
78 return snk(chunk, err) 86 return snk(chunk, err)
79end 87end
80 88
@@ -123,4 +131,4 @@ function _M.connect(host, port, timeout, create)
123 return base.setmetatable({c = c}, metat) 131 return base.setmetatable({c = c}, metat)
124end 132end
125 133
126return _M \ No newline at end of file 134return _M
diff --git a/src/udp.c b/src/udp.c
index 17d932a..712ad50 100644..100755
--- a/src/udp.c
+++ b/src/udp.c
@@ -2,12 +2,7 @@
2* UDP object 2* UDP object
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6#include <stdlib.h>
7
8#include "lua.h"
9#include "lauxlib.h"
10#include "compat.h"
11 6
12#include "auxiliar.h" 7#include "auxiliar.h"
13#include "socket.h" 8#include "socket.h"
@@ -15,6 +10,9 @@
15#include "options.h" 10#include "options.h"
16#include "udp.h" 11#include "udp.h"
17 12
13#include <string.h>
14#include <stdlib.h>
15
18/* min and max macros */ 16/* min and max macros */
19#ifndef MIN 17#ifndef MIN
20#define MIN(x, y) ((x) < (y) ? x : y) 18#define MIN(x, y) ((x) < (y) ? x : y)
@@ -36,6 +34,7 @@ static int meth_receivefrom(lua_State *L);
36static int meth_getfamily(lua_State *L); 34static int meth_getfamily(lua_State *L);
37static int meth_getsockname(lua_State *L); 35static int meth_getsockname(lua_State *L);
38static int meth_getpeername(lua_State *L); 36static int meth_getpeername(lua_State *L);
37static int meth_gettimeout(lua_State *L);
39static int meth_setsockname(lua_State *L); 38static int meth_setsockname(lua_State *L);
40static int meth_setpeername(lua_State *L); 39static int meth_setpeername(lua_State *L);
41static int meth_close(lua_State *L); 40static int meth_close(lua_State *L);
@@ -66,6 +65,7 @@ static luaL_Reg udp_methods[] = {
66 {"setpeername", meth_setpeername}, 65 {"setpeername", meth_setpeername},
67 {"setsockname", meth_setsockname}, 66 {"setsockname", meth_setsockname},
68 {"settimeout", meth_settimeout}, 67 {"settimeout", meth_settimeout},
68 {"gettimeout", meth_gettimeout},
69 {NULL, NULL} 69 {NULL, NULL}
70}; 70};
71 71
@@ -86,6 +86,8 @@ static t_opt optset[] = {
86 {"ipv6-add-membership", opt_set_ip6_add_membership}, 86 {"ipv6-add-membership", opt_set_ip6_add_membership},
87 {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, 87 {"ipv6-drop-membership", opt_set_ip6_drop_membersip},
88 {"ipv6-v6only", opt_set_ip6_v6only}, 88 {"ipv6-v6only", opt_set_ip6_v6only},
89 {"recv-buffer-size", opt_set_recv_buf_size},
90 {"send-buffer-size", opt_set_send_buf_size},
89 {NULL, NULL} 91 {NULL, NULL}
90}; 92};
91 93
@@ -102,6 +104,8 @@ static t_opt optget[] = {
102 {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, 104 {"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
103 {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, 105 {"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
104 {"ipv6-v6only", opt_get_ip6_v6only}, 106 {"ipv6-v6only", opt_get_ip6_v6only},
107 {"recv-buffer-size", opt_get_recv_buf_size},
108 {"send-buffer-size", opt_get_send_buf_size},
105 {NULL, NULL} 109 {NULL, NULL}
106}; 110};
107 111
@@ -116,8 +120,7 @@ static luaL_Reg func[] = {
116/*-------------------------------------------------------------------------*\ 120/*-------------------------------------------------------------------------*\
117* Initializes module 121* Initializes module
118\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
119int udp_open(lua_State *L) 123int udp_open(lua_State *L) {
120{
121 /* create classes */ 124 /* create classes */
122 auxiliar_newclass(L, "udp{connected}", udp_methods); 125 auxiliar_newclass(L, "udp{connected}", udp_methods);
123 auxiliar_newclass(L, "udp{unconnected}", udp_methods); 126 auxiliar_newclass(L, "udp{unconnected}", udp_methods);
@@ -128,6 +131,10 @@ int udp_open(lua_State *L)
128 auxiliar_add2group(L, "udp{unconnected}", "select{able}"); 131 auxiliar_add2group(L, "udp{unconnected}", "select{able}");
129 /* define library functions */ 132 /* define library functions */
130 luaL_setfuncs(L, func, 0); 133 luaL_setfuncs(L, func, 0);
134 /* export default UDP size */
135 lua_pushliteral(L, "_DATAGRAMSIZE");
136 lua_pushinteger(L, UDP_DATAGRAMSIZE);
137 lua_rawset(L, -3);
131 return 0; 138 return 0;
132} 139}
133 140
@@ -177,13 +184,37 @@ static int meth_sendto(lua_State *L) {
177 memset(&aihint, 0, sizeof(aihint)); 184 memset(&aihint, 0, sizeof(aihint));
178 aihint.ai_family = udp->family; 185 aihint.ai_family = udp->family;
179 aihint.ai_socktype = SOCK_DGRAM; 186 aihint.ai_socktype = SOCK_DGRAM;
180 aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; 187 aihint.ai_flags = AI_NUMERICHOST;
188#ifdef AI_NUMERICSERV
189 aihint.ai_flags |= AI_NUMERICSERV;
190#endif
181 err = getaddrinfo(ip, port, &aihint, &ai); 191 err = getaddrinfo(ip, port, &aihint, &ai);
182 if (err) { 192 if (err) {
183 lua_pushnil(L); 193 lua_pushnil(L);
184 lua_pushstring(L, gai_strerror(err)); 194 lua_pushstring(L, LUA_GAI_STRERROR(err));
185 return 2; 195 return 2;
186 } 196 }
197
198 /* create socket if on first sendto if AF_UNSPEC was set */
199 if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) {
200 struct addrinfo *ap;
201 const char *errstr = NULL;
202 for (ap = ai; ap != NULL; ap = ap->ai_next) {
203 errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0);
204 if (errstr == NULL) {
205 socket_setnonblocking(&udp->sock);
206 udp->family = ap->ai_family;
207 break;
208 }
209 }
210 if (errstr != NULL) {
211 lua_pushnil(L);
212 lua_pushstring(L, errstr);
213 freeaddrinfo(ai);
214 return 2;
215 }
216 }
217
187 timeout_markstart(tm); 218 timeout_markstart(tm);
188 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, 219 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
189 (socklen_t) ai->ai_addrlen, tm); 220 (socklen_t) ai->ai_addrlen, tm);
@@ -202,69 +233,78 @@ static int meth_sendto(lua_State *L) {
202\*-------------------------------------------------------------------------*/ 233\*-------------------------------------------------------------------------*/
203static int meth_receive(lua_State *L) { 234static int meth_receive(lua_State *L) {
204 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 235 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
205 char buffer[UDP_DATAGRAMSIZE]; 236 char buf[UDP_DATAGRAMSIZE];
206 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 237 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
238 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
207 int err; 239 int err;
208 p_timeout tm = &udp->tm; 240 p_timeout tm = &udp->tm;
209 count = MIN(count, sizeof(buffer));
210 timeout_markstart(tm); 241 timeout_markstart(tm);
211 err = socket_recv(&udp->sock, buffer, count, &got, tm); 242 if (!dgram) {
243 lua_pushnil(L);
244 lua_pushliteral(L, "out of memory");
245 return 2;
246 }
247 err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
212 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ 248 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
213 if (err == IO_CLOSED) 249 if (err != IO_DONE && err != IO_CLOSED) {
214 err = IO_DONE;
215 if (err != IO_DONE) {
216 lua_pushnil(L); 250 lua_pushnil(L);
217 lua_pushstring(L, udp_strerror(err)); 251 lua_pushstring(L, udp_strerror(err));
252 if (wanted > sizeof(buf)) free(dgram);
218 return 2; 253 return 2;
219 } 254 }
220 lua_pushlstring(L, buffer, got); 255 lua_pushlstring(L, dgram, got);
256 if (wanted > sizeof(buf)) free(dgram);
221 return 1; 257 return 1;
222} 258}
223 259
224/*-------------------------------------------------------------------------*\ 260/*-------------------------------------------------------------------------*\
225* Receives data and sender from a UDP socket 261* Receives data and sender from a UDP socket
226\*-------------------------------------------------------------------------*/ 262\*-------------------------------------------------------------------------*/
227static int meth_receivefrom(lua_State *L) 263static int meth_receivefrom(lua_State *L) {
228{
229 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); 264 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
230 char buffer[UDP_DATAGRAMSIZE]; 265 char buf[UDP_DATAGRAMSIZE];
231 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 266 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
232 int err; 267 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
233 p_timeout tm = &udp->tm;
234 struct sockaddr_storage addr; 268 struct sockaddr_storage addr;
235 socklen_t addr_len = sizeof(addr); 269 socklen_t addr_len = sizeof(addr);
236 char addrstr[INET6_ADDRSTRLEN]; 270 char addrstr[INET6_ADDRSTRLEN];
237 char portstr[6]; 271 char portstr[6];
272 int err;
273 p_timeout tm = &udp->tm;
238 timeout_markstart(tm); 274 timeout_markstart(tm);
239 count = MIN(count, sizeof(buffer)); 275 if (!dgram) {
240 err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, 276 lua_pushnil(L);
277 lua_pushliteral(L, "out of memory");
278 return 2;
279 }
280 err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
241 &addr_len, tm); 281 &addr_len, tm);
242 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ 282 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
243 if (err == IO_CLOSED) 283 if (err != IO_DONE && err != IO_CLOSED) {
244 err = IO_DONE;
245 if (err != IO_DONE) {
246 lua_pushnil(L); 284 lua_pushnil(L);
247 lua_pushstring(L, udp_strerror(err)); 285 lua_pushstring(L, udp_strerror(err));
286 if (wanted > sizeof(buf)) free(dgram);
248 return 2; 287 return 2;
249 } 288 }
250 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, 289 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
251 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); 290 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
252 if (err) { 291 if (err) {
253 lua_pushnil(L); 292 lua_pushnil(L);
254 lua_pushstring(L, gai_strerror(err)); 293 lua_pushstring(L, LUA_GAI_STRERROR(err));
294 if (wanted > sizeof(buf)) free(dgram);
255 return 2; 295 return 2;
256 } 296 }
257 lua_pushlstring(L, buffer, got); 297 lua_pushlstring(L, dgram, got);
258 lua_pushstring(L, addrstr); 298 lua_pushstring(L, addrstr);
259 lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); 299 lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
300 if (wanted > sizeof(buf)) free(dgram);
260 return 3; 301 return 3;
261} 302}
262 303
263/*-------------------------------------------------------------------------*\ 304/*-------------------------------------------------------------------------*\
264* Returns family as string 305* Returns family as string
265\*-------------------------------------------------------------------------*/ 306\*-------------------------------------------------------------------------*/
266static int meth_getfamily(lua_State *L) 307static int meth_getfamily(lua_State *L) {
267{
268 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 308 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
269 if (udp->family == AF_INET6) { 309 if (udp->family == AF_INET6) {
270 lua_pushliteral(L, "inet6"); 310 lua_pushliteral(L, "inet6");
@@ -335,6 +375,11 @@ static int meth_settimeout(lua_State *L) {
335 return timeout_meth_settimeout(L, &udp->tm); 375 return timeout_meth_settimeout(L, &udp->tm);
336} 376}
337 377
378static int meth_gettimeout(lua_State *L) {
379 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
380 return timeout_meth_gettimeout(L, &udp->tm);
381}
382
338/*-------------------------------------------------------------------------*\ 383/*-------------------------------------------------------------------------*\
339* Turns a master udp object into a client object. 384* Turns a master udp object into a client object.
340\*-------------------------------------------------------------------------*/ 385\*-------------------------------------------------------------------------*/
diff --git a/src/udp.h b/src/udp.h
index 2b831a5..07d5247 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -8,16 +8,15 @@
8* (AF_INET, SOCK_DGRAM). 8* (AF_INET, SOCK_DGRAM).
9* 9*
10* Two classes are defined: connected and unconnected. UDP objects are 10* Two classes are defined: connected and unconnected. UDP objects are
11* originally unconnected. They can be "connected" to a given address 11* originally unconnected. They can be "connected" to a given address
12* with a call to the setpeername function. The same function can be used to 12* with a call to the setpeername function. The same function can be used to
13* break the connection. 13* break the connection.
14\*=========================================================================*/ 14\*=========================================================================*/
15#include "lua.h" 15#include "luasocket.h"
16 16
17#include "timeout.h" 17#include "timeout.h"
18#include "socket.h" 18#include "socket.h"
19 19
20/* can't be larger than wsocket.c MAXCHUNK!!! */
21#define UDP_DATAGRAMSIZE 8192 20#define UDP_DATAGRAMSIZE 8192
22 21
23typedef struct t_udp_ { 22typedef struct t_udp_ {
@@ -27,6 +26,14 @@ typedef struct t_udp_ {
27} t_udp; 26} t_udp;
28typedef t_udp *p_udp; 27typedef t_udp *p_udp;
29 28
29#ifndef _WIN32
30#pragma GCC visibility push(hidden)
31#endif
32
30int udp_open(lua_State *L); 33int udp_open(lua_State *L);
31 34
35#ifndef _WIN32
36#pragma GCC visibility pop
37#endif
38
32#endif /* UDP_H */ 39#endif /* UDP_H */
diff --git a/src/unix.c b/src/unix.c
index 5bc3148..268d8b2 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -2,329 +2,68 @@
2* Unix domain socket 2* Unix domain socket
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6 6
7#include "lua.h" 7#include "unixstream.h"
8#include "lauxlib.h" 8#include "unixdgram.h"
9
10#include "auxiliar.h"
11#include "socket.h"
12#include "options.h"
13#include "unix.h"
14#include <sys/un.h>
15
16/*=========================================================================*\
17* Internal function prototypes
18\*=========================================================================*/
19static int global_create(lua_State *L);
20static int meth_connect(lua_State *L);
21static int meth_listen(lua_State *L);
22static int meth_bind(lua_State *L);
23static int meth_send(lua_State *L);
24static int meth_shutdown(lua_State *L);
25static int meth_receive(lua_State *L);
26static int meth_accept(lua_State *L);
27static int meth_close(lua_State *L);
28static int meth_setoption(lua_State *L);
29static int meth_settimeout(lua_State *L);
30static int meth_getfd(lua_State *L);
31static int meth_setfd(lua_State *L);
32static int meth_dirty(lua_State *L);
33static int meth_getstats(lua_State *L);
34static int meth_setstats(lua_State *L);
35
36static const char *unix_tryconnect(p_unix un, const char *path);
37static const char *unix_trybind(p_unix un, const char *path);
38
39/* unix object methods */
40static luaL_Reg unix_methods[] = {
41 {"__gc", meth_close},
42 {"__tostring", auxiliar_tostring},
43 {"accept", meth_accept},
44 {"bind", meth_bind},
45 {"close", meth_close},
46 {"connect", meth_connect},
47 {"dirty", meth_dirty},
48 {"getfd", meth_getfd},
49 {"getstats", meth_getstats},
50 {"setstats", meth_setstats},
51 {"listen", meth_listen},
52 {"receive", meth_receive},
53 {"send", meth_send},
54 {"setfd", meth_setfd},
55 {"setoption", meth_setoption},
56 {"setpeername", meth_connect},
57 {"setsockname", meth_bind},
58 {"settimeout", meth_settimeout},
59 {"shutdown", meth_shutdown},
60 {NULL, NULL}
61};
62
63/* socket option handlers */
64static t_opt optset[] = {
65 {"keepalive", opt_set_keepalive},
66 {"reuseaddr", opt_set_reuseaddr},
67 {"linger", opt_set_linger},
68 {NULL, NULL}
69};
70 9
71/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------*\
72* Initializes module 11* Modules and functions
73\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
74int luaopen_socket_unix(lua_State *L) { 13static const luaL_Reg mod[] = {
75 /* create classes */ 14 {"stream", unixstream_open},
76 auxiliar_newclass(L, "unix{master}", unix_methods); 15 {"dgram", unixdgram_open},
77 auxiliar_newclass(L, "unix{client}", unix_methods); 16 {NULL, NULL}
78 auxiliar_newclass(L, "unix{server}", unix_methods); 17};
79 /* create class groups */
80 auxiliar_add2group(L, "unix{master}", "unix{any}");
81 auxiliar_add2group(L, "unix{client}", "unix{any}");
82 auxiliar_add2group(L, "unix{server}", "unix{any}");
83 /* return the function instead of the 'socket' table */
84 lua_pushcfunction(L, global_create);
85 return 1;
86}
87
88/*=========================================================================*\
89* Lua methods
90\*=========================================================================*/
91/*-------------------------------------------------------------------------*\
92* Just call buffered IO methods
93\*-------------------------------------------------------------------------*/
94static int meth_send(lua_State *L) {
95 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
96 return buffer_meth_send(L, &un->buf);
97}
98
99static int meth_receive(lua_State *L) {
100 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
101 return buffer_meth_receive(L, &un->buf);
102}
103
104static int meth_getstats(lua_State *L) {
105 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
106 return buffer_meth_getstats(L, &un->buf);
107}
108
109static int meth_setstats(lua_State *L) {
110 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
111 return buffer_meth_setstats(L, &un->buf);
112}
113
114/*-------------------------------------------------------------------------*\
115* Just call option handler
116\*-------------------------------------------------------------------------*/
117static int meth_setoption(lua_State *L) {
118 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
119 return opt_meth_setoption(L, optset, &un->sock);
120}
121
122/*-------------------------------------------------------------------------*\
123* Select support methods
124\*-------------------------------------------------------------------------*/
125static int meth_getfd(lua_State *L) {
126 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
127 lua_pushnumber(L, (int) un->sock);
128 return 1;
129}
130
131/* this is very dangerous, but can be handy for those that are brave enough */
132static int meth_setfd(lua_State *L) {
133 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
134 un->sock = (t_socket) luaL_checknumber(L, 2);
135 return 0;
136}
137 18
138static int meth_dirty(lua_State *L) { 19static void add_alias(lua_State *L, int index, const char *name, const char *target)
139 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); 20{
140 lua_pushboolean(L, !buffer_isempty(&un->buf)); 21 lua_getfield(L, index, target);
141 return 1; 22 lua_setfield(L, index, name);
142} 23}
143 24
144/*-------------------------------------------------------------------------*\ 25static int compat_socket_unix_call(lua_State *L)
145* Waits for and returns a client object attempting connection to the 26{
146* server object 27 /* Look up socket.unix.stream in the socket.unix table (which is the first
147\*-------------------------------------------------------------------------*/ 28 * argument). */
148static int meth_accept(lua_State *L) { 29 lua_getfield(L, 1, "stream");
149 p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
150 p_timeout tm = timeout_markstart(&server->tm);
151 t_socket sock;
152 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
153 /* if successful, push client socket */
154 if (err == IO_DONE) {
155 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
156 auxiliar_setclass(L, "unix{client}", -1);
157 /* initialize structure fields */
158 socket_setnonblocking(&sock);
159 clnt->sock = sock;
160 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
161 (p_error) socket_ioerror, &clnt->sock);
162 timeout_init(&clnt->tm, -1, -1);
163 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
164 return 1;
165 } else {
166 lua_pushnil(L);
167 lua_pushstring(L, socket_strerror(err));
168 return 2;
169 }
170}
171 30
172/*-------------------------------------------------------------------------*\ 31 /* Replace the stack entry for the socket.unix table with the
173* Binds an object to an address 32 * socket.unix.stream function. */
174\*-------------------------------------------------------------------------*/ 33 lua_replace(L, 1);
175static const char *unix_trybind(p_unix un, const char *path) {
176 struct sockaddr_un local;
177 size_t len = strlen(path);
178 int err;
179 if (len >= sizeof(local.sun_path)) return "path too long";
180 memset(&local, 0, sizeof(local));
181 strcpy(local.sun_path, path);
182 local.sun_family = AF_UNIX;
183#ifdef UNIX_HAS_SUN_LEN
184 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
185 + len + 1;
186 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
187 34
188#else 35 /* Call socket.unix.stream, passing along any arguments. */
189 err = socket_bind(&un->sock, (SA *) &local, 36 int n = lua_gettop(L);
190 sizeof(local.sun_family) + len); 37 lua_call(L, n-1, LUA_MULTRET);
191#endif
192 if (err != IO_DONE) socket_destroy(&un->sock);
193 return socket_strerror(err);
194}
195 38
196static int meth_bind(lua_State *L) { 39 /* Pass along the return values from socket.unix.stream. */
197 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); 40 n = lua_gettop(L);
198 const char *path = luaL_checkstring(L, 2); 41 return n;
199 const char *err = unix_trybind(un, path);
200 if (err) {
201 lua_pushnil(L);
202 lua_pushstring(L, err);
203 return 2;
204 }
205 lua_pushnumber(L, 1);
206 return 1;
207} 42}
208 43
209/*-------------------------------------------------------------------------*\ 44/*-------------------------------------------------------------------------*\
210* Turns a master unix object into a client object. 45* Initializes module
211\*-------------------------------------------------------------------------*/ 46\*-------------------------------------------------------------------------*/
212static const char *unix_tryconnect(p_unix un, const char *path) 47LUASOCKET_API int luaopen_socket_unix(lua_State *L)
213{ 48{
214 struct sockaddr_un remote; 49 int i;
215 int err; 50 lua_newtable(L);
216 size_t len = strlen(path); 51 int socket_unix_table = lua_gettop(L);
217 if (len >= sizeof(remote.sun_path)) return "path too long";
218 memset(&remote, 0, sizeof(remote));
219 strcpy(remote.sun_path, path);
220 remote.sun_family = AF_UNIX;
221 timeout_markstart(&un->tm);
222#ifdef UNIX_HAS_SUN_LEN
223 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
224 + len + 1;
225 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
226#else
227 err = socket_connect(&un->sock, (SA *) &remote,
228 sizeof(remote.sun_family) + len, &un->tm);
229#endif
230 if (err != IO_DONE) socket_destroy(&un->sock);
231 return socket_strerror(err);
232}
233 52
234static int meth_connect(lua_State *L) 53 for (i = 0; mod[i].name; i++)
235{ 54 mod[i].func(L);
236 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
237 const char *path = luaL_checkstring(L, 2);
238 const char *err = unix_tryconnect(un, path);
239 if (err) {
240 lua_pushnil(L);
241 lua_pushstring(L, err);
242 return 2;
243 }
244 /* turn master object into a client object */
245 auxiliar_setclass(L, "unix{client}", 1);
246 lua_pushnumber(L, 1);
247 return 1;
248}
249 55
250/*-------------------------------------------------------------------------*\ 56 /* Add backwards compatibility aliases "tcp" and "udp" for the "stream" and
251* Closes socket used by object 57 * "dgram" functions. */
252\*-------------------------------------------------------------------------*/ 58 add_alias(L, socket_unix_table, "tcp", "stream");
253static int meth_close(lua_State *L) 59 add_alias(L, socket_unix_table, "udp", "dgram");
254{
255 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
256 socket_destroy(&un->sock);
257 lua_pushnumber(L, 1);
258 return 1;
259}
260 60
261/*-------------------------------------------------------------------------*\ 61 /* Add a backwards compatibility function and a metatable setup to call it
262* Puts the sockt in listen mode 62 * for the old socket.unix() interface. */
263\*-------------------------------------------------------------------------*/ 63 lua_pushcfunction(L, compat_socket_unix_call);
264static int meth_listen(lua_State *L) 64 lua_setfield(L, socket_unix_table, "__call");
265{ 65 lua_pushvalue(L, socket_unix_table);
266 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); 66 lua_setmetatable(L, socket_unix_table);
267 int backlog = (int) luaL_optnumber(L, 2, 32);
268 int err = socket_listen(&un->sock, backlog);
269 if (err != IO_DONE) {
270 lua_pushnil(L);
271 lua_pushstring(L, socket_strerror(err));
272 return 2;
273 }
274 /* turn master object into a server object */
275 auxiliar_setclass(L, "unix{server}", 1);
276 lua_pushnumber(L, 1);
277 return 1;
278}
279 67
280/*-------------------------------------------------------------------------*\
281* Shuts the connection down partially
282\*-------------------------------------------------------------------------*/
283static int meth_shutdown(lua_State *L)
284{
285 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
286 static const char* methods[] = { "receive", "send", "both", NULL };
287 p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
288 int how = luaL_checkoption(L, 2, "both", methods);
289 socket_shutdown(&tcp->sock, how);
290 lua_pushnumber(L, 1);
291 return 1; 68 return 1;
292} 69}
293
294/*-------------------------------------------------------------------------*\
295* Just call tm methods
296\*-------------------------------------------------------------------------*/
297static int meth_settimeout(lua_State *L) {
298 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
299 return timeout_meth_settimeout(L, &un->tm);
300}
301
302/*=========================================================================*\
303* Library functions
304\*=========================================================================*/
305/*-------------------------------------------------------------------------*\
306* Creates a master unix object
307\*-------------------------------------------------------------------------*/
308static int global_create(lua_State *L) {
309 t_socket sock;
310 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
311 /* try to allocate a system socket */
312 if (err == IO_DONE) {
313 /* allocate unix object */
314 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
315 /* set its type as master object */
316 auxiliar_setclass(L, "unix{master}", -1);
317 /* initialize remaining structure fields */
318 socket_setnonblocking(&sock);
319 un->sock = sock;
320 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
321 (p_error) socket_ioerror, &un->sock);
322 timeout_init(&un->tm, -1, -1);
323 buffer_init(&un->buf, &un->io, &un->tm);
324 return 1;
325 } else {
326 lua_pushnil(L);
327 lua_pushstring(L, socket_strerror(err));
328 return 2;
329 }
330}
diff --git a/src/unix.h b/src/unix.h
index 8cc7a79..c203561 100644
--- a/src/unix.h
+++ b/src/unix.h
@@ -7,16 +7,12 @@
7* This module is just an example of how to extend LuaSocket with a new 7* This module is just an example of how to extend LuaSocket with a new
8* domain. 8* domain.
9\*=========================================================================*/ 9\*=========================================================================*/
10#include "lua.h" 10#include "luasocket.h"
11 11
12#include "buffer.h" 12#include "buffer.h"
13#include "timeout.h" 13#include "timeout.h"
14#include "socket.h" 14#include "socket.h"
15 15
16#ifndef UNIX_API
17#define UNIX_API extern
18#endif
19
20typedef struct t_unix_ { 16typedef struct t_unix_ {
21 t_socket sock; 17 t_socket sock;
22 t_io io; 18 t_io io;
@@ -25,6 +21,6 @@ typedef struct t_unix_ {
25} t_unix; 21} t_unix;
26typedef t_unix *p_unix; 22typedef t_unix *p_unix;
27 23
28UNIX_API int luaopen_socket_unix(lua_State *L); 24LUASOCKET_API int luaopen_socket_unix(lua_State *L);
29 25
30#endif /* UNIX_H */ 26#endif /* UNIX_H */
diff --git a/src/unixdgram.c b/src/unixdgram.c
new file mode 100644
index 0000000..69093d7
--- /dev/null
+++ b/src/unixdgram.c
@@ -0,0 +1,405 @@
1/*=========================================================================*\
2* Unix domain socket dgram submodule
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6
7#include "auxiliar.h"
8#include "socket.h"
9#include "options.h"
10#include "unix.h"
11
12#include <string.h>
13#include <stdlib.h>
14
15#include <sys/un.h>
16
17#define UNIXDGRAM_DATAGRAMSIZE 8192
18
19/* provide a SUN_LEN macro if sys/un.h doesn't (e.g. Android) */
20#ifndef SUN_LEN
21#define SUN_LEN(ptr) \
22 ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
23 + strlen ((ptr)->sun_path))
24#endif
25
26/*=========================================================================*\
27* Internal function prototypes
28\*=========================================================================*/
29static int global_create(lua_State *L);
30static int meth_connect(lua_State *L);
31static int meth_bind(lua_State *L);
32static int meth_send(lua_State *L);
33static int meth_receive(lua_State *L);
34static int meth_close(lua_State *L);
35static int meth_setoption(lua_State *L);
36static int meth_settimeout(lua_State *L);
37static int meth_gettimeout(lua_State *L);
38static int meth_getfd(lua_State *L);
39static int meth_setfd(lua_State *L);
40static int meth_dirty(lua_State *L);
41static int meth_receivefrom(lua_State *L);
42static int meth_sendto(lua_State *L);
43static int meth_getsockname(lua_State *L);
44
45static const char *unixdgram_tryconnect(p_unix un, const char *path);
46static const char *unixdgram_trybind(p_unix un, const char *path);
47
48/* unixdgram object methods */
49static luaL_Reg unixdgram_methods[] = {
50 {"__gc", meth_close},
51 {"__tostring", auxiliar_tostring},
52 {"bind", meth_bind},
53 {"close", meth_close},
54 {"connect", meth_connect},
55 {"dirty", meth_dirty},
56 {"getfd", meth_getfd},
57 {"send", meth_send},
58 {"sendto", meth_sendto},
59 {"receive", meth_receive},
60 {"receivefrom", meth_receivefrom},
61 {"setfd", meth_setfd},
62 {"setoption", meth_setoption},
63 {"setpeername", meth_connect},
64 {"setsockname", meth_bind},
65 {"getsockname", meth_getsockname},
66 {"settimeout", meth_settimeout},
67 {"gettimeout", meth_gettimeout},
68 {NULL, NULL}
69};
70
71/* socket option handlers */
72static t_opt optset[] = {
73 {"reuseaddr", opt_set_reuseaddr},
74 {NULL, NULL}
75};
76
77/* functions in library namespace */
78static luaL_Reg func[] = {
79 {"dgram", global_create},
80 {NULL, NULL}
81};
82
83/*-------------------------------------------------------------------------*\
84* Initializes module
85\*-------------------------------------------------------------------------*/
86int unixdgram_open(lua_State *L)
87{
88 /* create classes */
89 auxiliar_newclass(L, "unixdgram{connected}", unixdgram_methods);
90 auxiliar_newclass(L, "unixdgram{unconnected}", unixdgram_methods);
91 /* create class groups */
92 auxiliar_add2group(L, "unixdgram{connected}", "unixdgram{any}");
93 auxiliar_add2group(L, "unixdgram{unconnected}", "unixdgram{any}");
94 auxiliar_add2group(L, "unixdgram{connected}", "select{able}");
95 auxiliar_add2group(L, "unixdgram{unconnected}", "select{able}");
96
97 luaL_setfuncs(L, func, 0);
98 return 0;
99}
100
101/*=========================================================================*\
102* Lua methods
103\*=========================================================================*/
104static const char *unixdgram_strerror(int err)
105{
106 /* a 'closed' error on an unconnected means the target address was not
107 * accepted by the transport layer */
108 if (err == IO_CLOSED) return "refused";
109 else return socket_strerror(err);
110}
111
112static int meth_send(lua_State *L)
113{
114 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{connected}", 1);
115 p_timeout tm = &un->tm;
116 size_t count, sent = 0;
117 int err;
118 const char *data = luaL_checklstring(L, 2, &count);
119 timeout_markstart(tm);
120 err = socket_send(&un->sock, data, count, &sent, tm);
121 if (err != IO_DONE) {
122 lua_pushnil(L);
123 lua_pushstring(L, unixdgram_strerror(err));
124 return 2;
125 }
126 lua_pushnumber(L, (lua_Number) sent);
127 return 1;
128}
129
130/*-------------------------------------------------------------------------*\
131* Send data through unconnected unixdgram socket
132\*-------------------------------------------------------------------------*/
133static int meth_sendto(lua_State *L)
134{
135 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
136 size_t count, sent = 0;
137 const char *data = luaL_checklstring(L, 2, &count);
138 const char *path = luaL_checkstring(L, 3);
139 p_timeout tm = &un->tm;
140 int err;
141 struct sockaddr_un remote;
142 size_t len = strlen(path);
143
144 if (len >= sizeof(remote.sun_path)) {
145 lua_pushnil(L);
146 lua_pushstring(L, "path too long");
147 return 2;
148 }
149
150 memset(&remote, 0, sizeof(remote));
151 strcpy(remote.sun_path, path);
152 remote.sun_family = AF_UNIX;
153 timeout_markstart(tm);
154#ifdef UNIX_HAS_SUN_LEN
155 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
156 + len + 1;
157 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm);
158#else
159 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote,
160 sizeof(remote.sun_family) + len, tm);
161#endif
162 if (err != IO_DONE) {
163 lua_pushnil(L);
164 lua_pushstring(L, unixdgram_strerror(err));
165 return 2;
166 }
167 lua_pushnumber(L, (lua_Number) sent);
168 return 1;
169}
170
171static int meth_receive(lua_State *L) {
172 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
173 char buf[UNIXDGRAM_DATAGRAMSIZE];
174 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
175 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
176 int err;
177 p_timeout tm = &un->tm;
178 timeout_markstart(tm);
179 if (!dgram) {
180 lua_pushnil(L);
181 lua_pushliteral(L, "out of memory");
182 return 2;
183 }
184 err = socket_recv(&un->sock, dgram, wanted, &got, tm);
185 /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
186 if (err != IO_DONE && err != IO_CLOSED) {
187 lua_pushnil(L);
188 lua_pushstring(L, unixdgram_strerror(err));
189 if (wanted > sizeof(buf)) free(dgram);
190 return 2;
191 }
192 lua_pushlstring(L, dgram, got);
193 if (wanted > sizeof(buf)) free(dgram);
194 return 1;
195}
196
197/*-------------------------------------------------------------------------*\
198* Receives data and sender from a DGRAM socket
199\*-------------------------------------------------------------------------*/
200static int meth_receivefrom(lua_State *L) {
201 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
202 char buf[UNIXDGRAM_DATAGRAMSIZE];
203 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
204 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
205 struct sockaddr_un addr;
206 socklen_t addr_len = sizeof(addr);
207 int err;
208 p_timeout tm = &un->tm;
209 timeout_markstart(tm);
210 if (!dgram) {
211 lua_pushnil(L);
212 lua_pushliteral(L, "out of memory");
213 return 2;
214 }
215 addr.sun_path[0] = '\0';
216 err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr,
217 &addr_len, tm);
218 /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
219 if (err != IO_DONE && err != IO_CLOSED) {
220 lua_pushnil(L);
221 lua_pushstring(L, unixdgram_strerror(err));
222 if (wanted > sizeof(buf)) free(dgram);
223 return 2;
224 }
225
226 lua_pushlstring(L, dgram, got);
227 /* the path may be empty, when client send without bind */
228 lua_pushstring(L, addr.sun_path);
229 if (wanted > sizeof(buf)) free(dgram);
230 return 2;
231}
232
233/*-------------------------------------------------------------------------*\
234* Just call option handler
235\*-------------------------------------------------------------------------*/
236static int meth_setoption(lua_State *L) {
237 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
238 return opt_meth_setoption(L, optset, &un->sock);
239}
240
241/*-------------------------------------------------------------------------*\
242* Select support methods
243\*-------------------------------------------------------------------------*/
244static int meth_getfd(lua_State *L) {
245 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
246 lua_pushnumber(L, (int) un->sock);
247 return 1;
248}
249
250/* this is very dangerous, but can be handy for those that are brave enough */
251static int meth_setfd(lua_State *L) {
252 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
253 un->sock = (t_socket) luaL_checknumber(L, 2);
254 return 0;
255}
256
257static int meth_dirty(lua_State *L) {
258 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
259 (void) un;
260 lua_pushboolean(L, 0);
261 return 1;
262}
263
264/*-------------------------------------------------------------------------*\
265* Binds an object to an address
266\*-------------------------------------------------------------------------*/
267static const char *unixdgram_trybind(p_unix un, const char *path) {
268 struct sockaddr_un local;
269 size_t len = strlen(path);
270 if (len >= sizeof(local.sun_path)) return "path too long";
271 memset(&local, 0, sizeof(local));
272 strcpy(local.sun_path, path);
273 local.sun_family = AF_UNIX;
274 size_t addrlen = SUN_LEN(&local);
275#ifdef UNIX_HAS_SUN_LEN
276 local.sun_len = addrlen + 1;
277#endif
278 int err = socket_bind(&un->sock, (SA *) &local, addrlen);
279 if (err != IO_DONE) socket_destroy(&un->sock);
280 return socket_strerror(err);
281}
282
283static int meth_bind(lua_State *L)
284{
285 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
286 const char *path = luaL_checkstring(L, 2);
287 const char *err = unixdgram_trybind(un, path);
288 if (err) {
289 lua_pushnil(L);
290 lua_pushstring(L, err);
291 return 2;
292 }
293 lua_pushnumber(L, 1);
294 return 1;
295}
296
297static int meth_getsockname(lua_State *L)
298{
299 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
300 struct sockaddr_un peer = {0};
301 socklen_t peer_len = sizeof(peer);
302
303 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
304 lua_pushnil(L);
305 lua_pushstring(L, socket_strerror(errno));
306 return 2;
307 }
308
309 lua_pushstring(L, peer.sun_path);
310 return 1;
311}
312
313/*-------------------------------------------------------------------------*\
314* Turns a master unixdgram object into a client object.
315\*-------------------------------------------------------------------------*/
316static const char *unixdgram_tryconnect(p_unix un, const char *path)
317{
318 struct sockaddr_un remote;
319 size_t len = strlen(path);
320 if (len >= sizeof(remote.sun_path)) return "path too long";
321 memset(&remote, 0, sizeof(remote));
322 strcpy(remote.sun_path, path);
323 remote.sun_family = AF_UNIX;
324 timeout_markstart(&un->tm);
325 size_t addrlen = SUN_LEN(&remote);
326#ifdef UNIX_HAS_SUN_LEN
327 remote.sun_len = addrlen + 1;
328#endif
329 int err = socket_connect(&un->sock, (SA *) &remote, addrlen, &un->tm);
330 if (err != IO_DONE) socket_destroy(&un->sock);
331 return socket_strerror(err);
332}
333
334static int meth_connect(lua_State *L)
335{
336 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
337 const char *path = luaL_checkstring(L, 2);
338 const char *err = unixdgram_tryconnect(un, path);
339 if (err) {
340 lua_pushnil(L);
341 lua_pushstring(L, err);
342 return 2;
343 }
344 /* turn unconnected object into a connected object */
345 auxiliar_setclass(L, "unixdgram{connected}", 1);
346 lua_pushnumber(L, 1);
347 return 1;
348}
349
350/*-------------------------------------------------------------------------*\
351* Closes socket used by object
352\*-------------------------------------------------------------------------*/
353static int meth_close(lua_State *L)
354{
355 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
356 socket_destroy(&un->sock);
357 lua_pushnumber(L, 1);
358 return 1;
359}
360
361/*-------------------------------------------------------------------------*\
362* Just call tm methods
363\*-------------------------------------------------------------------------*/
364static int meth_settimeout(lua_State *L)
365{
366 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
367 return timeout_meth_settimeout(L, &un->tm);
368}
369
370static int meth_gettimeout(lua_State *L)
371{
372 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
373 return timeout_meth_gettimeout(L, &un->tm);
374}
375
376/*=========================================================================*\
377* Library functions
378\*=========================================================================*/
379/*-------------------------------------------------------------------------*\
380* Creates a master unixdgram object
381\*-------------------------------------------------------------------------*/
382static int global_create(lua_State *L)
383{
384 t_socket sock;
385 int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0);
386 /* try to allocate a system socket */
387 if (err == IO_DONE) {
388 /* allocate unixdgram object */
389 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
390 /* set its type as master object */
391 auxiliar_setclass(L, "unixdgram{unconnected}", -1);
392 /* initialize remaining structure fields */
393 socket_setnonblocking(&sock);
394 un->sock = sock;
395 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
396 (p_error) socket_ioerror, &un->sock);
397 timeout_init(&un->tm, -1, -1);
398 buffer_init(&un->buf, &un->io, &un->tm);
399 return 1;
400 } else {
401 lua_pushnil(L);
402 lua_pushstring(L, socket_strerror(err));
403 return 2;
404 }
405}
diff --git a/src/unixdgram.h b/src/unixdgram.h
new file mode 100644
index 0000000..a1a0166
--- /dev/null
+++ b/src/unixdgram.h
@@ -0,0 +1,28 @@
1#ifndef UNIXDGRAM_H
2#define UNIXDGRAM_H
3/*=========================================================================*\
4* DGRAM object
5* LuaSocket toolkit
6*
7* The dgram.h module provides LuaSocket with support for DGRAM protocol
8* (AF_INET, SOCK_DGRAM).
9*
10* Two classes are defined: connected and unconnected. DGRAM objects are
11* originally unconnected. They can be "connected" to a given address
12* with a call to the setpeername function. The same function can be used to
13* break the connection.
14\*=========================================================================*/
15
16#include "unix.h"
17
18#ifndef _WIN32
19#pragma GCC visibility push(hidden)
20#endif
21
22int unixdgram_open(lua_State *L);
23
24#ifndef _WIN32
25#pragma GCC visibility pop
26#endif
27
28#endif /* UNIXDGRAM_H */
diff --git a/src/unixstream.c b/src/unixstream.c
new file mode 100644
index 0000000..02aced9
--- /dev/null
+++ b/src/unixstream.c
@@ -0,0 +1,355 @@
1/*=========================================================================*\
2* Unix domain socket stream sub module
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6
7#include "auxiliar.h"
8#include "socket.h"
9#include "options.h"
10#include "unixstream.h"
11
12#include <string.h>
13#include <sys/un.h>
14
15/*=========================================================================*\
16* Internal function prototypes
17\*=========================================================================*/
18static int global_create(lua_State *L);
19static int meth_connect(lua_State *L);
20static int meth_listen(lua_State *L);
21static int meth_bind(lua_State *L);
22static int meth_send(lua_State *L);
23static int meth_shutdown(lua_State *L);
24static int meth_receive(lua_State *L);
25static int meth_accept(lua_State *L);
26static int meth_close(lua_State *L);
27static int meth_setoption(lua_State *L);
28static int meth_settimeout(lua_State *L);
29static int meth_getfd(lua_State *L);
30static int meth_setfd(lua_State *L);
31static int meth_dirty(lua_State *L);
32static int meth_getstats(lua_State *L);
33static int meth_setstats(lua_State *L);
34static int meth_getsockname(lua_State *L);
35
36static const char *unixstream_tryconnect(p_unix un, const char *path);
37static const char *unixstream_trybind(p_unix un, const char *path);
38
39/* unixstream object methods */
40static luaL_Reg unixstream_methods[] = {
41 {"__gc", meth_close},
42 {"__tostring", auxiliar_tostring},
43 {"accept", meth_accept},
44 {"bind", meth_bind},
45 {"close", meth_close},
46 {"connect", meth_connect},
47 {"dirty", meth_dirty},
48 {"getfd", meth_getfd},
49 {"getstats", meth_getstats},
50 {"setstats", meth_setstats},
51 {"listen", meth_listen},
52 {"receive", meth_receive},
53 {"send", meth_send},
54 {"setfd", meth_setfd},
55 {"setoption", meth_setoption},
56 {"setpeername", meth_connect},
57 {"setsockname", meth_bind},
58 {"getsockname", meth_getsockname},
59 {"settimeout", meth_settimeout},
60 {"shutdown", meth_shutdown},
61 {NULL, NULL}
62};
63
64/* socket option handlers */
65static t_opt optset[] = {
66 {"keepalive", opt_set_keepalive},
67 {"reuseaddr", opt_set_reuseaddr},
68 {"linger", opt_set_linger},
69 {NULL, NULL}
70};
71
72/* functions in library namespace */
73static luaL_Reg func[] = {
74 {"stream", global_create},
75 {NULL, NULL}
76};
77
78/*-------------------------------------------------------------------------*\
79* Initializes module
80\*-------------------------------------------------------------------------*/
81int unixstream_open(lua_State *L)
82{
83 /* create classes */
84 auxiliar_newclass(L, "unixstream{master}", unixstream_methods);
85 auxiliar_newclass(L, "unixstream{client}", unixstream_methods);
86 auxiliar_newclass(L, "unixstream{server}", unixstream_methods);
87
88 /* create class groups */
89 auxiliar_add2group(L, "unixstream{master}", "unixstream{any}");
90 auxiliar_add2group(L, "unixstream{client}", "unixstream{any}");
91 auxiliar_add2group(L, "unixstream{server}", "unixstream{any}");
92
93 luaL_setfuncs(L, func, 0);
94 return 0;
95}
96
97/*=========================================================================*\
98* Lua methods
99\*=========================================================================*/
100/*-------------------------------------------------------------------------*\
101* Just call buffered IO methods
102\*-------------------------------------------------------------------------*/
103static int meth_send(lua_State *L) {
104 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
105 return buffer_meth_send(L, &un->buf);
106}
107
108static int meth_receive(lua_State *L) {
109 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
110 return buffer_meth_receive(L, &un->buf);
111}
112
113static int meth_getstats(lua_State *L) {
114 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
115 return buffer_meth_getstats(L, &un->buf);
116}
117
118static int meth_setstats(lua_State *L) {
119 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
120 return buffer_meth_setstats(L, &un->buf);
121}
122
123/*-------------------------------------------------------------------------*\
124* Just call option handler
125\*-------------------------------------------------------------------------*/
126static int meth_setoption(lua_State *L) {
127 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
128 return opt_meth_setoption(L, optset, &un->sock);
129}
130
131/*-------------------------------------------------------------------------*\
132* Select support methods
133\*-------------------------------------------------------------------------*/
134static int meth_getfd(lua_State *L) {
135 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
136 lua_pushnumber(L, (int) un->sock);
137 return 1;
138}
139
140/* this is very dangerous, but can be handy for those that are brave enough */
141static int meth_setfd(lua_State *L) {
142 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
143 un->sock = (t_socket) luaL_checknumber(L, 2);
144 return 0;
145}
146
147static int meth_dirty(lua_State *L) {
148 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
149 lua_pushboolean(L, !buffer_isempty(&un->buf));
150 return 1;
151}
152
153/*-------------------------------------------------------------------------*\
154* Waits for and returns a client object attempting connection to the
155* server object
156\*-------------------------------------------------------------------------*/
157static int meth_accept(lua_State *L) {
158 p_unix server = (p_unix) auxiliar_checkclass(L, "unixstream{server}", 1);
159 p_timeout tm = timeout_markstart(&server->tm);
160 t_socket sock;
161 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
162 /* if successful, push client socket */
163 if (err == IO_DONE) {
164 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
165 auxiliar_setclass(L, "unixstream{client}", -1);
166 /* initialize structure fields */
167 socket_setnonblocking(&sock);
168 clnt->sock = sock;
169 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
170 (p_error) socket_ioerror, &clnt->sock);
171 timeout_init(&clnt->tm, -1, -1);
172 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
173 return 1;
174 } else {
175 lua_pushnil(L);
176 lua_pushstring(L, socket_strerror(err));
177 return 2;
178 }
179}
180
181/*-------------------------------------------------------------------------*\
182* Binds an object to an address
183\*-------------------------------------------------------------------------*/
184static const char *unixstream_trybind(p_unix un, const char *path) {
185 struct sockaddr_un local;
186 size_t len = strlen(path);
187 int err;
188 if (len >= sizeof(local.sun_path)) return "path too long";
189 memset(&local, 0, sizeof(local));
190 strcpy(local.sun_path, path);
191 local.sun_family = AF_UNIX;
192#ifdef UNIX_HAS_SUN_LEN
193 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
194 + len + 1;
195 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
196
197#else
198 err = socket_bind(&un->sock, (SA *) &local,
199 sizeof(local.sun_family) + len);
200#endif
201 if (err != IO_DONE) socket_destroy(&un->sock);
202 return socket_strerror(err);
203}
204
205static int meth_bind(lua_State *L) {
206 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
207 const char *path = luaL_checkstring(L, 2);
208 const char *err = unixstream_trybind(un, path);
209 if (err) {
210 lua_pushnil(L);
211 lua_pushstring(L, err);
212 return 2;
213 }
214 lua_pushnumber(L, 1);
215 return 1;
216}
217
218static int meth_getsockname(lua_State *L)
219{
220 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
221 struct sockaddr_un peer = {0};
222 socklen_t peer_len = sizeof(peer);
223
224 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
225 lua_pushnil(L);
226 lua_pushstring(L, socket_strerror(errno));
227 return 2;
228 }
229
230 lua_pushstring(L, peer.sun_path);
231 return 1;
232}
233
234/*-------------------------------------------------------------------------*\
235* Turns a master unixstream object into a client object.
236\*-------------------------------------------------------------------------*/
237static const char *unixstream_tryconnect(p_unix un, const char *path)
238{
239 struct sockaddr_un remote;
240 int err;
241 size_t len = strlen(path);
242 if (len >= sizeof(remote.sun_path)) return "path too long";
243 memset(&remote, 0, sizeof(remote));
244 strcpy(remote.sun_path, path);
245 remote.sun_family = AF_UNIX;
246 timeout_markstart(&un->tm);
247#ifdef UNIX_HAS_SUN_LEN
248 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
249 + len + 1;
250 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
251#else
252 err = socket_connect(&un->sock, (SA *) &remote,
253 sizeof(remote.sun_family) + len, &un->tm);
254#endif
255 if (err != IO_DONE) socket_destroy(&un->sock);
256 return socket_strerror(err);
257}
258
259static int meth_connect(lua_State *L)
260{
261 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
262 const char *path = luaL_checkstring(L, 2);
263 const char *err = unixstream_tryconnect(un, path);
264 if (err) {
265 lua_pushnil(L);
266 lua_pushstring(L, err);
267 return 2;
268 }
269 /* turn master object into a client object */
270 auxiliar_setclass(L, "unixstream{client}", 1);
271 lua_pushnumber(L, 1);
272 return 1;
273}
274
275/*-------------------------------------------------------------------------*\
276* Closes socket used by object
277\*-------------------------------------------------------------------------*/
278static int meth_close(lua_State *L)
279{
280 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
281 socket_destroy(&un->sock);
282 lua_pushnumber(L, 1);
283 return 1;
284}
285
286/*-------------------------------------------------------------------------*\
287* Puts the sockt in listen mode
288\*-------------------------------------------------------------------------*/
289static int meth_listen(lua_State *L)
290{
291 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
292 int backlog = (int) luaL_optnumber(L, 2, 32);
293 int err = socket_listen(&un->sock, backlog);
294 if (err != IO_DONE) {
295 lua_pushnil(L);
296 lua_pushstring(L, socket_strerror(err));
297 return 2;
298 }
299 /* turn master object into a server object */
300 auxiliar_setclass(L, "unixstream{server}", 1);
301 lua_pushnumber(L, 1);
302 return 1;
303}
304
305/*-------------------------------------------------------------------------*\
306* Shuts the connection down partially
307\*-------------------------------------------------------------------------*/
308static int meth_shutdown(lua_State *L)
309{
310 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
311 static const char* methods[] = { "receive", "send", "both", NULL };
312 p_unix stream = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
313 int how = luaL_checkoption(L, 2, "both", methods);
314 socket_shutdown(&stream->sock, how);
315 lua_pushnumber(L, 1);
316 return 1;
317}
318
319/*-------------------------------------------------------------------------*\
320* Just call tm methods
321\*-------------------------------------------------------------------------*/
322static int meth_settimeout(lua_State *L) {
323 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
324 return timeout_meth_settimeout(L, &un->tm);
325}
326
327/*=========================================================================*\
328* Library functions
329\*=========================================================================*/
330/*-------------------------------------------------------------------------*\
331* Creates a master unixstream object
332\*-------------------------------------------------------------------------*/
333static int global_create(lua_State *L) {
334 t_socket sock;
335 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
336 /* try to allocate a system socket */
337 if (err == IO_DONE) {
338 /* allocate unixstream object */
339 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
340 /* set its type as master object */
341 auxiliar_setclass(L, "unixstream{master}", -1);
342 /* initialize remaining structure fields */
343 socket_setnonblocking(&sock);
344 un->sock = sock;
345 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
346 (p_error) socket_ioerror, &un->sock);
347 timeout_init(&un->tm, -1, -1);
348 buffer_init(&un->buf, &un->io, &un->tm);
349 return 1;
350 } else {
351 lua_pushnil(L);
352 lua_pushstring(L, socket_strerror(err));
353 return 2;
354 }
355}
diff --git a/src/unixstream.h b/src/unixstream.h
new file mode 100644
index 0000000..7916aff
--- /dev/null
+++ b/src/unixstream.h
@@ -0,0 +1,29 @@
1#ifndef UNIXSTREAM_H
2#define UNIXSTREAM_H
3/*=========================================================================*\
4* UNIX STREAM object
5* LuaSocket toolkit
6*
7* The unixstream.h module is basicly a glue that puts together modules buffer.h,
8* timeout.h socket.h and inet.h to provide the LuaSocket UNIX STREAM (AF_UNIX,
9* SOCK_STREAM) support.
10*
11* Three classes are defined: master, client and server. The master class is
12* a newly created unixstream object, that has not been bound or connected. Server
13* objects are unixstream objects bound to some local address. Client objects are
14* unixstream objects either connected to some address or returned by the accept
15* method of a server object.
16\*=========================================================================*/
17#include "unix.h"
18
19#ifndef _WIN32
20#pragma GCC visibility push(hidden)
21#endif
22
23int unixstream_open(lua_State *L);
24
25#ifndef _WIN32
26#pragma GCC visibility pop
27#endif
28
29#endif /* UNIXSTREAM_H */
diff --git a/src/url.lua b/src/url.lua
index 7809535..8e0dc5c 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -49,7 +49,7 @@ local function make_set(t)
49 return s 49 return s
50end 50end
51 51
52-- these are allowed withing a path segment, along with alphanum 52-- these are allowed within a path segment, along with alphanum
53-- other characters must be escaped 53-- other characters must be escaped
54local segment_set = make_set { 54local segment_set = make_set {
55 "-", "_", ".", "!", "~", "*", "'", "(", 55 "-", "_", ".", "!", "~", "*", "'", "(",
@@ -59,16 +59,16 @@ local segment_set = make_set {
59local function protect_segment(s) 59local function protect_segment(s)
60 return string.gsub(s, "([^A-Za-z0-9_])", function (c) 60 return string.gsub(s, "([^A-Za-z0-9_])", function (c)
61 if segment_set[c] then return c 61 if segment_set[c] then return c
62 else return string.format("%%%02x", string.byte(c)) end 62 else return string.format("%%%02X", string.byte(c)) end
63 end) 63 end)
64end 64end
65 65
66----------------------------------------------------------------------------- 66-----------------------------------------------------------------------------
67-- Encodes a string into its escaped hexadecimal representation 67-- Unencodes a escaped hexadecimal string into its binary representation
68-- Input 68-- Input
69-- s: binary string to be encoded 69-- s: escaped hexadecimal string to be unencoded
70-- Returns 70-- Returns
71-- escaped representation of string binary 71-- unescaped binary representation of escaped hexadecimal binary
72----------------------------------------------------------------------------- 72-----------------------------------------------------------------------------
73function _M.unescape(s) 73function _M.unescape(s)
74 return (string.gsub(s, "%%(%x%x)", function(hex) 74 return (string.gsub(s, "%%(%x%x)", function(hex)
@@ -77,6 +77,34 @@ function _M.unescape(s)
77end 77end
78 78
79----------------------------------------------------------------------------- 79-----------------------------------------------------------------------------
80-- Removes '..' and '.' components appropriately from a path.
81-- Input
82-- path
83-- Returns
84-- dot-normalized path
85local function remove_dot_components(path)
86 local marker = string.char(1)
87 repeat
88 local was = path
89 path = path:gsub('//', '/'..marker..'/', 1)
90 until path == was
91 repeat
92 local was = path
93 path = path:gsub('/%./', '/', 1)
94 until path == was
95 repeat
96 local was = path
97 path = path:gsub('[^/]+/%.%./([^/]+)', '%1', 1)
98 until path == was
99 path = path:gsub('[^/]+/%.%./*$', '')
100 path = path:gsub('/%.%.$', '/')
101 path = path:gsub('/%.$', '/')
102 path = path:gsub('^/%.%./', '/')
103 path = path:gsub(marker, '')
104 return path
105end
106
107-----------------------------------------------------------------------------
80-- Builds a path from a base path and a relative path 108-- Builds a path from a base path and a relative path
81-- Input 109-- Input
82-- base_path 110-- base_path
@@ -85,23 +113,12 @@ end
85-- corresponding absolute path 113-- corresponding absolute path
86----------------------------------------------------------------------------- 114-----------------------------------------------------------------------------
87local function absolute_path(base_path, relative_path) 115local function absolute_path(base_path, relative_path)
88 if string.sub(relative_path, 1, 1) == "/" then return relative_path end 116 if string.sub(relative_path, 1, 1) == "/" then
89 local path = string.gsub(base_path, "[^/]*$", "") 117 return remove_dot_components(relative_path) end
90 path = path .. relative_path 118 base_path = base_path:gsub("[^/]*$", "")
91 path = string.gsub(path, "([^/]*%./)", function (s) 119 if not base_path:find'/$' then base_path = base_path .. '/' end
92 if s ~= "./" then return s else return "" end 120 local path = base_path .. relative_path
93 end) 121 path = remove_dot_components(path)
94 path = string.gsub(path, "/%.$", "/")
95 local reduced
96 while reduced ~= path do
97 reduced = path
98 path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
99 if s ~= "../../" then return "" else return s end
100 end)
101 end
102 path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
103 if s ~= "../.." then return "" else return s end
104 end)
105 return path 122 return path
106end 123end
107 124
@@ -131,11 +148,6 @@ function _M.parse(url, default)
131 if not url or url == "" then return nil, "invalid url" end 148 if not url or url == "" then return nil, "invalid url" end
132 -- remove whitespace 149 -- remove whitespace
133 -- url = string.gsub(url, "%s", "") 150 -- url = string.gsub(url, "%s", "")
134 -- get fragment
135 url = string.gsub(url, "#(.*)$", function(f)
136 parsed.fragment = f
137 return ""
138 end)
139 -- get scheme 151 -- get scheme
140 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", 152 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
141 function(s) parsed.scheme = s; return "" end) 153 function(s) parsed.scheme = s; return "" end)
@@ -144,6 +156,11 @@ function _M.parse(url, default)
144 parsed.authority = n 156 parsed.authority = n
145 return "" 157 return ""
146 end) 158 end)
159 -- get fragment
160 url = string.gsub(url, "#(.*)$", function(f)
161 parsed.fragment = f
162 return ""
163 end)
147 -- get query string 164 -- get query string
148 url = string.gsub(url, "%?(.*)", function(q) 165 url = string.gsub(url, "%?(.*)", function(q)
149 parsed.query = q 166 parsed.query = q
@@ -162,9 +179,9 @@ function _M.parse(url, default)
162 function(u) parsed.userinfo = u; return "" end) 179 function(u) parsed.userinfo = u; return "" end)
163 authority = string.gsub(authority, ":([^:%]]*)$", 180 authority = string.gsub(authority, ":([^:%]]*)$",
164 function(p) parsed.port = p; return "" end) 181 function(p) parsed.port = p; return "" end)
165 if authority ~= "" then 182 if authority ~= "" then
166 -- IPv6? 183 -- IPv6?
167 parsed.host = string.match(authority, "^%[(.+)%]$") or authority 184 parsed.host = string.match(authority, "^%[(.+)%]$") or authority
168 end 185 end
169 local userinfo = parsed.userinfo 186 local userinfo = parsed.userinfo
170 if not userinfo then return parsed end 187 if not userinfo then return parsed end
@@ -183,8 +200,9 @@ end
183-- a stringing with the corresponding URL 200-- a stringing with the corresponding URL
184----------------------------------------------------------------------------- 201-----------------------------------------------------------------------------
185function _M.build(parsed) 202function _M.build(parsed)
186 local ppath = _M.parse_path(parsed.path or "") 203 --local ppath = _M.parse_path(parsed.path or "")
187 local url = _M.build_path(ppath) 204 --local url = _M.build_path(ppath)
205 local url = parsed.path or ""
188 if parsed.params then url = url .. ";" .. parsed.params end 206 if parsed.params then url = url .. ";" .. parsed.params end
189 if parsed.query then url = url .. "?" .. parsed.query end 207 if parsed.query then url = url .. "?" .. parsed.query end
190 local authority = parsed.authority 208 local authority = parsed.authority
@@ -193,7 +211,7 @@ function _M.build(parsed)
193 if string.find(authority, ":") then -- IPv6? 211 if string.find(authority, ":") then -- IPv6?
194 authority = "[" .. authority .. "]" 212 authority = "[" .. authority .. "]"
195 end 213 end
196 if parsed.port then authority = authority .. ":" .. parsed.port end 214 if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end
197 local userinfo = parsed.userinfo 215 local userinfo = parsed.userinfo
198 if parsed.user then 216 if parsed.user then
199 userinfo = parsed.user 217 userinfo = parsed.user
@@ -219,16 +237,21 @@ end
219-- corresponding absolute url 237-- corresponding absolute url
220----------------------------------------------------------------------------- 238-----------------------------------------------------------------------------
221function _M.absolute(base_url, relative_url) 239function _M.absolute(base_url, relative_url)
240 local base_parsed
222 if base.type(base_url) == "table" then 241 if base.type(base_url) == "table" then
223 base_parsed = base_url 242 base_parsed = base_url
224 base_url = _M.build(base_parsed) 243 base_url = _M.build(base_parsed)
225 else 244 else
226 base_parsed = _M.parse(base_url) 245 base_parsed = _M.parse(base_url)
227 end 246 end
247 local result
228 local relative_parsed = _M.parse(relative_url) 248 local relative_parsed = _M.parse(relative_url)
229 if not base_parsed then return relative_url 249 if not base_parsed then
230 elseif not relative_parsed then return base_url 250 result = relative_url
231 elseif relative_parsed.scheme then return relative_url 251 elseif not relative_parsed then
252 result = base_url
253 elseif relative_parsed.scheme then
254 result = relative_url
232 else 255 else
233 relative_parsed.scheme = base_parsed.scheme 256 relative_parsed.scheme = base_parsed.scheme
234 if not relative_parsed.authority then 257 if not relative_parsed.authority then
@@ -241,13 +264,14 @@ function _M.absolute(base_url, relative_url)
241 relative_parsed.query = base_parsed.query 264 relative_parsed.query = base_parsed.query
242 end 265 end
243 end 266 end
244 else 267 else
245 relative_parsed.path = absolute_path(base_parsed.path or "", 268 relative_parsed.path = absolute_path(base_parsed.path or "",
246 relative_parsed.path) 269 relative_parsed.path)
247 end 270 end
248 end 271 end
249 return _M.build(relative_parsed) 272 result = _M.build(relative_parsed)
250 end 273 end
274 return remove_dot_components(result)
251end 275end
252 276
253----------------------------------------------------------------------------- 277-----------------------------------------------------------------------------
diff --git a/src/usocket.c b/src/usocket.c
index 8adc573..7965db6 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -6,12 +6,14 @@
6* The penalty of calling select to avoid busy-wait is only paid when 6* The penalty of calling select to avoid busy-wait is only paid when
7* the I/O call fail in the first place. 7* the I/O call fail in the first place.
8\*=========================================================================*/ 8\*=========================================================================*/
9#include <string.h> 9#include "luasocket.h"
10#include <signal.h>
11 10
12#include "socket.h" 11#include "socket.h"
13#include "pierror.h" 12#include "pierror.h"
14 13
14#include <string.h>
15#include <signal.h>
16
15/*-------------------------------------------------------------------------*\ 17/*-------------------------------------------------------------------------*\
16* Wait for readable/writable/connected socket with timeout 18* Wait for readable/writable/connected socket with timeout
17\*-------------------------------------------------------------------------*/ 19\*-------------------------------------------------------------------------*/
@@ -76,7 +78,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
76* Initializes module 78* Initializes module
77\*-------------------------------------------------------------------------*/ 79\*-------------------------------------------------------------------------*/
78int socket_open(void) { 80int socket_open(void) {
79 /* instals a handler to ignore sigpipe or it will crash us */ 81 /* installs a handler to ignore sigpipe or it will crash us */
80 signal(SIGPIPE, SIG_IGN); 82 signal(SIGPIPE, SIG_IGN);
81 return 1; 83 return 1;
82} 84}
@@ -234,7 +236,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
234 *sent = 0; 236 *sent = 0;
235 if (*ps == SOCKET_INVALID) return IO_CLOSED; 237 if (*ps == SOCKET_INVALID) return IO_CLOSED;
236 for ( ;; ) { 238 for ( ;; ) {
237 long put = (long) sendto(*ps, data, count, 0, addr, len); 239 long put = (long) sendto(*ps, data, count, 0, addr, len);
238 if (put >= 0) { 240 if (put >= 0) {
239 *sent = put; 241 *sent = put;
240 return IO_DONE; 242 return IO_DONE;
@@ -438,14 +440,15 @@ const char *socket_gaistrerror(int err) {
438 case EAI_FAMILY: return PIE_FAMILY; 440 case EAI_FAMILY: return PIE_FAMILY;
439 case EAI_MEMORY: return PIE_MEMORY; 441 case EAI_MEMORY: return PIE_MEMORY;
440 case EAI_NONAME: return PIE_NONAME; 442 case EAI_NONAME: return PIE_NONAME;
443#ifdef EAI_OVERFLOW
441 case EAI_OVERFLOW: return PIE_OVERFLOW; 444 case EAI_OVERFLOW: return PIE_OVERFLOW;
445#endif
442#ifdef EAI_PROTOCOL 446#ifdef EAI_PROTOCOL
443 case EAI_PROTOCOL: return PIE_PROTOCOL; 447 case EAI_PROTOCOL: return PIE_PROTOCOL;
444#endif 448#endif
445 case EAI_SERVICE: return PIE_SERVICE; 449 case EAI_SERVICE: return PIE_SERVICE;
446 case EAI_SOCKTYPE: return PIE_SOCKTYPE; 450 case EAI_SOCKTYPE: return PIE_SOCKTYPE;
447 case EAI_SYSTEM: return strerror(errno); 451 case EAI_SYSTEM: return strerror(errno);
448 default: return gai_strerror(err); 452 default: return LUA_GAI_STRERROR(err);
449 } 453 }
450} 454}
451
diff --git a/src/wsocket.c b/src/wsocket.c
index 8ecb0fc..6cb1e41 100644..100755
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -5,6 +5,8 @@
5* The penalty of calling select to avoid busy-wait is only paid when 5* The penalty of calling select to avoid busy-wait is only paid when
6* the I/O call fail in the first place. 6* the I/O call fail in the first place.
7\*=========================================================================*/ 7\*=========================================================================*/
8#include "luasocket.h"
9
8#include <string.h> 10#include <string.h>
9 11
10#include "socket.h" 12#include "socket.h"
@@ -131,11 +133,11 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
131 /* we wait until something happens */ 133 /* we wait until something happens */
132 err = socket_waitfd(ps, WAITFD_C, tm); 134 err = socket_waitfd(ps, WAITFD_C, tm);
133 if (err == IO_CLOSED) { 135 if (err == IO_CLOSED) {
134 int len = sizeof(err); 136 int elen = sizeof(err);
135 /* give windows time to set the error (yes, disgusting) */ 137 /* give windows time to set the error (yes, disgusting) */
136 Sleep(10); 138 Sleep(10);
137 /* find out why we failed */ 139 /* find out why we failed */
138 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); 140 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &elen);
139 /* we KNOW there was an error. if 'why' is 0, we will return 141 /* we KNOW there was an error. if 'why' is 0, we will return
140 * "unknown error", but it's not really our fault */ 142 * "unknown error", but it's not really our fault */
141 return err > 0? err: IO_UNKNOWN; 143 return err > 0? err: IO_UNKNOWN;
@@ -358,7 +360,7 @@ const char *socket_ioerror(p_socket ps, int err) {
358static const char *wstrerror(int err) { 360static const char *wstrerror(int err) {
359 switch (err) { 361 switch (err) {
360 case WSAEINTR: return "Interrupted function call"; 362 case WSAEINTR: return "Interrupted function call";
361 case WSAEACCES: return PIE_ACCESS; // "Permission denied"; 363 case WSAEACCES: return PIE_ACCESS; /* "Permission denied"; */
362 case WSAEFAULT: return "Bad address"; 364 case WSAEFAULT: return "Bad address";
363 case WSAEINVAL: return "Invalid argument"; 365 case WSAEINVAL: return "Invalid argument";
364 case WSAEMFILE: return "Too many open files"; 366 case WSAEMFILE: return "Too many open files";
@@ -371,23 +373,23 @@ static const char *wstrerror(int err) {
371 case WSAEPROTOTYPE: return "Protocol wrong type for socket"; 373 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
372 case WSAENOPROTOOPT: return "Bad protocol option"; 374 case WSAENOPROTOOPT: return "Bad protocol option";
373 case WSAEPROTONOSUPPORT: return "Protocol not supported"; 375 case WSAEPROTONOSUPPORT: return "Protocol not supported";
374 case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported"; 376 case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; /* "Socket type not supported"; */
375 case WSAEOPNOTSUPP: return "Operation not supported"; 377 case WSAEOPNOTSUPP: return "Operation not supported";
376 case WSAEPFNOSUPPORT: return "Protocol family not supported"; 378 case WSAEPFNOSUPPORT: return "Protocol family not supported";
377 case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family"; 379 case WSAEAFNOSUPPORT: return PIE_FAMILY; /* "Address family not supported by protocol family"; */
378 case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use"; 380 case WSAEADDRINUSE: return PIE_ADDRINUSE; /* "Address already in use"; */
379 case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; 381 case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
380 case WSAENETDOWN: return "Network is down"; 382 case WSAENETDOWN: return "Network is down";
381 case WSAENETUNREACH: return "Network is unreachable"; 383 case WSAENETUNREACH: return "Network is unreachable";
382 case WSAENETRESET: return "Network dropped connection on reset"; 384 case WSAENETRESET: return "Network dropped connection on reset";
383 case WSAECONNABORTED: return "Software caused connection abort"; 385 case WSAECONNABORTED: return "Software caused connection abort";
384 case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer"; 386 case WSAECONNRESET: return PIE_CONNRESET; /* "Connection reset by peer"; */
385 case WSAENOBUFS: return "No buffer space available"; 387 case WSAENOBUFS: return "No buffer space available";
386 case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected"; 388 case WSAEISCONN: return PIE_ISCONN; /* "Socket is already connected"; */
387 case WSAENOTCONN: return "Socket is not connected"; 389 case WSAENOTCONN: return "Socket is not connected";
388 case WSAESHUTDOWN: return "Cannot send after socket shutdown"; 390 case WSAESHUTDOWN: return "Cannot send after socket shutdown";
389 case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out"; 391 case WSAETIMEDOUT: return PIE_TIMEDOUT; /* "Connection timed out"; */
390 case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused"; 392 case WSAECONNREFUSED: return PIE_CONNREFUSED; /* "Connection refused"; */
391 case WSAEHOSTDOWN: return "Host is down"; 393 case WSAEHOSTDOWN: return "Host is down";
392 case WSAEHOSTUNREACH: return "No route to host"; 394 case WSAEHOSTUNREACH: return "No route to host";
393 case WSAEPROCLIM: return "Too many processes"; 395 case WSAEPROCLIM: return "Too many processes";
@@ -396,9 +398,9 @@ static const char *wstrerror(int err) {
396 case WSANOTINITIALISED: 398 case WSANOTINITIALISED:
397 return "Successful WSAStartup not yet performed"; 399 return "Successful WSAStartup not yet performed";
398 case WSAEDISCON: return "Graceful shutdown in progress"; 400 case WSAEDISCON: return "Graceful shutdown in progress";
399 case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found"; 401 case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; /* "Host not found"; */
400 case WSATRY_AGAIN: return "Nonauthoritative host not found"; 402 case WSATRY_AGAIN: return "Nonauthoritative host not found";
401 case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error"; 403 case WSANO_RECOVERY: return PIE_FAIL; /* "Nonrecoverable name lookup error"; */
402 case WSANO_DATA: return "Valid name, no data record of requested type"; 404 case WSANO_DATA: return "Valid name, no data record of requested type";
403 default: return "Unknown error"; 405 default: return "Unknown error";
404 } 406 }
@@ -427,7 +429,6 @@ const char *socket_gaistrerror(int err) {
427#ifdef EAI_SYSTEM 429#ifdef EAI_SYSTEM
428 case EAI_SYSTEM: return strerror(errno); 430 case EAI_SYSTEM: return strerror(errno);
429#endif 431#endif
430 default: return gai_strerror(err); 432 default: return LUA_GAI_STRERROR(err);
431 } 433 }
432} 434}
433
diff --git a/test/auth/.htaccess b/test/auth/.htaccess
index bb2794a..2509ae3 100644
--- a/test/auth/.htaccess
+++ b/test/auth/.htaccess
@@ -1,4 +1,4 @@
1AuthName "test-auth" 1AuthName "test-auth"
2 AuthType Basic 2 AuthType Basic
3 AuthUserFile /Users/diego/impa/luasocket/test/auth/.htpasswd 3 AuthUserFile /home/diego/impa/luasocket/test/auth/.htpasswd
4 Require valid-user 4 Require valid-user
diff --git a/test/excepttest.lua b/test/excepttest.lua
index ce9f197..80c9cb8 100644
--- a/test/excepttest.lua
+++ b/test/excepttest.lua
@@ -1,6 +1,30 @@
1local socket = require("socket") 1local socket = require("socket")
2try = socket.newtry(function() 2
3 print("finalized!!!") 3local finalizer_called
4
5local func = socket.protect(function(err, ...)
6 local try = socket.newtry(function()
7 finalizer_called = true
8 end)
9
10 if err then
11 return error(err, 0)
12 else
13 return try(...)
14 end
4end) 15end)
5try = socket.protect(try) 16
6print(try(nil, "it works")) 17local ret1, ret2, ret3 = func(false, 1, 2, 3)
18assert(not finalizer_called, "unexpected finalizer call")
19assert(ret1 == 1 and ret2 == 2 and ret3 == 3, "incorrect return values")
20
21ret1, ret2, ret3 = func(false, false, "error message")
22assert(finalizer_called, "finalizer not called")
23assert(ret1 == nil and ret2 == "error message" and ret3 == nil, "incorrect return values")
24
25local err = {key = "value"}
26ret1, ret2 = pcall(func, err)
27assert(not ret1, "error not rethrown")
28assert(ret2 == err, "incorrect error rethrown")
29
30print("OK")
diff --git a/test/find-connect-limit b/test/find-connect-limit
index ad0c3f5..199e515 100755
--- a/test/find-connect-limit
+++ b/test/find-connect-limit
@@ -10,7 +10,7 @@ ulimit -n
10You'll probably need to be root to do this. 10You'll probably need to be root to do this.
11]] 11]]
12 12
13require "socket" 13socket = require "socket"
14 14
15host = arg[1] or "google.com" 15host = arg[1] or "google.com"
16port = arg[2] or 80 16port = arg[2] or 80
diff --git a/test/ftptest.lua b/test/ftptest.lua
index fb13326..3ea0d39 100644
--- a/test/ftptest.lua
+++ b/test/ftptest.lua
@@ -3,19 +3,31 @@ local ftp = require("socket.ftp")
3local url = require("socket.url") 3local url = require("socket.url")
4local ltn12 = require("ltn12") 4local ltn12 = require("ltn12")
5 5
6-- use dscl to create user "luasocket" with password "password"
7-- with home in /Users/diego/luasocket/test/ftp
8-- with group com.apple.access_ftp
9-- with shell set to /sbin/nologin
10-- set /etc/ftpchroot to chroot luasocket
11-- must set group com.apple.access_ftp on user _ftp (for anonymous access)
12-- copy index.html to /var/empty/pub (home of user ftp)
13-- start ftp server with
14-- sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
15-- copy index.html to /Users/diego/luasocket/test/ftp
16-- stop with
17-- sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
18
6-- override protection to make sure we see all errors 19-- override protection to make sure we see all errors
7--socket.protect = function(s) return s end 20--socket.protect = function(s) return s end
8 21
9dofile("testsupport.lua") 22dofile("testsupport.lua")
10 23
11local host, port, index_file, index, back, err, ret 24local host = host or "localhost"
25local port, index_file, index, back, err, ret
12 26
13local t = socket.gettime() 27local t = socket.gettime()
14 28
15host = host or "localhost"
16index_file = "index.html" 29index_file = "index.html"
17 30
18
19-- a function that returns a directory listing 31-- a function that returns a directory listing
20local function nlst(u) 32local function nlst(u)
21 local t = {} 33 local t = {}
@@ -55,27 +67,27 @@ assert(not err and back == index, err)
55print("ok") 67print("ok")
56 68
57io.write("erasing before upload: ") 69io.write("erasing before upload: ")
58ret, err = dele("ftp://luasocket:pedrovian@" .. host .. "/index.up.html") 70ret, err = dele("ftp://luasocket:password@" .. host .. "/index.up.html")
59if not ret then print(err) 71if not ret then print(err)
60else print("ok") end 72else print("ok") end
61 73
62io.write("testing upload: ") 74io.write("testing upload: ")
63ret, err = ftp.put("ftp://luasocket:pedrovian@" .. host .. "/index.up.html;type=i", index) 75ret, err = ftp.put("ftp://luasocket:password@" .. host .. "/index.up.html;type=i", index)
64assert(ret and not err, err) 76assert(ret and not err, err)
65print("ok") 77print("ok")
66 78
67io.write("downloading uploaded file: ") 79io.write("downloading uploaded file: ")
68back, err = ftp.get("ftp://luasocket:pedrovian@" .. host .. "/index.up.html;type=i") 80back, err = ftp.get("ftp://luasocket:password@" .. host .. "/index.up.html;type=i")
69assert(ret and not err and index == back, err) 81assert(ret and not err and index == back, err)
70print("ok") 82print("ok")
71 83
72io.write("erasing after upload/download: ") 84io.write("erasing after upload/download: ")
73ret, err = dele("ftp://luasocket:pedrovian@" .. host .. "/index.up.html") 85ret, err = dele("ftp://luasocket:password@" .. host .. "/index.up.html")
74assert(ret and not err, err) 86assert(ret and not err, err)
75print("ok") 87print("ok")
76 88
77io.write("testing weird-character translation: ") 89io.write("testing weird-character translation: ")
78back, err = ftp.get("ftp://luasocket:pedrovian@" .. host .. "/%23%3f;type=i") 90back, err = ftp.get("ftp://luasocket:password@" .. host .. "/%23%3f;type=i")
79assert(not err and back == index, err) 91assert(not err and back == index, err)
80print("ok") 92print("ok")
81 93
@@ -84,7 +96,7 @@ local back = {}
84ret, err = ftp.get{ 96ret, err = ftp.get{
85 url = "//stupid:mistake@" .. host .. "/index.html", 97 url = "//stupid:mistake@" .. host .. "/index.html",
86 user = "luasocket", 98 user = "luasocket",
87 password = "pedrovian", 99 password = "password",
88 type = "i", 100 type = "i",
89 sink = ltn12.sink.table(back) 101 sink = ltn12.sink.table(back)
90} 102}
diff --git a/test/httptest.lua b/test/httptest.lua
index 63ff921..3457b07 100644
--- a/test/httptest.lua
+++ b/test/httptest.lua
@@ -265,6 +265,37 @@ ignore = {
265} 265}
266check_request(request, expect, ignore) 266check_request(request, expect, ignore)
267 267
268-- Use https://httpbin.org/#/Dynamic_data/get_base64__value_ for testing
269-----------------------------------------------------
270io.write("testing absolute https redirection: ")
271request = {
272 url = "https://httpbin.org/redirect-to?url=https://httpbin.org/base64/THVhIFNvY2tldA=="
273}
274expect = {
275 code = 200,
276 body = "Lua Socket"
277}
278ignore = {
279 status = 1,
280 headers = 1
281}
282check_request(request, expect, ignore)
283
284-----------------------------------------------------
285io.write("testing relative https redirection: ")
286request = {
287 url = "https://httpbin.org/redirect-to?url=/base64/THVhIFNvY2tldA=="
288}
289expect = {
290 code = 200,
291 body = "Lua Socket"
292}
293ignore = {
294 status = 1,
295 headers = 1
296}
297check_request(request, expect, ignore)
298
268------------------------------------------------------------------------ 299------------------------------------------------------------------------
269--[[ 300--[[
270io.write("testing proxy with redirection: ") 301io.write("testing proxy with redirection: ")
diff --git a/test/ltn12test.lua b/test/ltn12test.lua
index e3f85fb..0cafbc9 100644
--- a/test/ltn12test.lua
+++ b/test/ltn12test.lua
@@ -38,7 +38,7 @@ local function named(f, name)
38end 38end
39 39
40-------------------------------- 40--------------------------------
41local function split(size) 41local function split(size)
42 local buffer = "" 42 local buffer = ""
43 local last_out = "" 43 local last_out = ""
44 local last_in = "" 44 local last_in = ""
@@ -50,12 +50,12 @@ local function split(size)
50 return last_out 50 return last_out
51 end 51 end
52 return function(chunk, done) 52 return function(chunk, done)
53 if done then 53 if done then
54 return not last_in and not last_out 54 return not last_in and not last_out
55 end 55 end
56 -- check if argument is consistent with state 56 -- check if argument is consistent with state
57 if not chunk then 57 if not chunk then
58 if last_in and last_in ~= "" and last_out ~= "" then 58 if last_in and last_in ~= "" and last_out ~= "" then
59 error("nil chunk following data chunk", 2) 59 error("nil chunk following data chunk", 2)
60 end 60 end
61 if not last_out then error("extra nil chunk", 2) end 61 if not last_out then error("extra nil chunk", 2) end
@@ -67,8 +67,8 @@ local function split(size)
67 return output(chunk) 67 return output(chunk)
68 else 68 else
69 if not last_in then error("data chunk following nil chunk", 2) end 69 if not last_in then error("data chunk following nil chunk", 2) end
70 if last_in ~= "" and last_out ~= "" then 70 if last_in ~= "" and last_out ~= "" then
71 error("data chunk following data chunk", 2) 71 error("data chunk following data chunk", 2)
72 end 72 end
73 buffer = chunk 73 buffer = chunk
74 return output(chunk) 74 return output(chunk)
@@ -85,7 +85,7 @@ local function format(chunk)
85end 85end
86 86
87-------------------------------- 87--------------------------------
88local function merge(size) 88local function merge(size)
89 local buffer = "" 89 local buffer = ""
90 local last_out = "" 90 local last_out = ""
91 local last_in = "" 91 local last_in = ""
@@ -102,12 +102,12 @@ local function merge(size)
102 return last_out 102 return last_out
103 end 103 end
104 return function(chunk, done) 104 return function(chunk, done)
105 if done then 105 if done then
106 return not last_in and not last_out 106 return not last_in and not last_out
107 end 107 end
108 -- check if argument is consistent with state 108 -- check if argument is consistent with state
109 if not chunk then 109 if not chunk then
110 if last_in and last_in ~= "" and last_out ~= "" then 110 if last_in and last_in ~= "" and last_out ~= "" then
111 error("nil chunk following data chunk", 2) 111 error("nil chunk following data chunk", 2)
112 end 112 end
113 if not last_out then error("extra nil chunk", 2) end 113 if not last_out then error("extra nil chunk", 2) end
@@ -119,8 +119,8 @@ local function merge(size)
119 return output(chunk) 119 return output(chunk)
120 else 120 else
121 if not last_in then error("data chunk following nil chunk", 2) end 121 if not last_in then error("data chunk following nil chunk", 2) end
122 if last_in ~= "" and last_out ~= "" then 122 if last_in ~= "" and last_out ~= "" then
123 error("data chunk following data chunk", 2) 123 error("data chunk following data chunk", 2)
124 end 124 end
125 buffer = buffer .. chunk 125 buffer = buffer .. chunk
126 return output(chunk) 126 return output(chunk)
@@ -181,6 +181,15 @@ assert(table.concat(t) == s, "mismatch")
181print("ok") 181print("ok")
182 182
183-------------------------------- 183--------------------------------
184io.write("testing source.table: ")
185local inp = {'a','b','c','d','e'}
186local source = ltn12.source.table(inp)
187sink, t = ltn12.sink.table()
188assert(ltn12.pump.all(source, sink), "returned error")
189for i = 1, #inp do assert(t[i] == inp[i], "mismatch") end
190print("ok")
191
192--------------------------------
184io.write("testing source.chain (with split): ") 193io.write("testing source.chain (with split): ")
185source = ltn12.source.string(s) 194source = ltn12.source.string(s)
186filter = split(5) 195filter = split(5)
diff --git a/test/mimetest.lua b/test/mimetest.lua
index f5b3747..a3c89ac 100644
--- a/test/mimetest.lua
+++ b/test/mimetest.lua
@@ -15,27 +15,27 @@ local eb64test = "b64test.bin2"
15local db64test = "b64test.bin3" 15local db64test = "b64test.bin3"
16 16
17 17
18-- from Machado de Assis, "A Mão e a Rosa" 18-- from Machado de Assis, "A M�o e a Rosa"
19local mao = [[ 19local mao = [[
20 Cursavam estes dois moços a academia de S. Paulo, estando 20 Cursavam estes dois mo�os a academia de S. Paulo, estando
21 Luís Alves no quarto ano e Estêvão no terceiro. 21 Lu�s Alves no quarto ano e Est�v�o no terceiro.
22 Conheceram-se na academia, e ficaram amigos íntimos, tanto 22 Conheceram-se na academia, e ficaram amigos �ntimos, tanto
23 quanto podiam sê-lo dois espíritos diferentes, ou talvez por 23 quanto podiam s�-lo dois esp�ritos diferentes, ou talvez por
24 isso mesmo que o eram. Estêvão, dotado de extrema 24 isso mesmo que o eram. Est�v�o, dotado de extrema
25 sensibilidade, e não menor fraqueza de ânimo, afetuoso e 25 sensibilidade, e n�o menor fraqueza de �nimo, afetuoso e
26 bom, não daquela bondade varonil, que é apanágio de uma alma 26 bom, n�o daquela bondade varonil, que � apan�gio de uma alma
27 forte, mas dessa outra bondade mole e de cera, que vai à 27 forte, mas dessa outra bondade mole e de cera, que vai �
28 mercê de todas as circunstâncias, tinha, além de tudo isso, 28 merc� de todas as circunst�ncias, tinha, al�m de tudo isso,
29 o infortúnio de trazer ainda sobre o nariz os óculos 29 o infort�nio de trazer ainda sobre o nariz os �culos
30 cor-de-rosa de suas virginais ilusões. Luís Alves via bem 30 cor-de-rosa de suas virginais ilus�es. Lu�s Alves via bem
31 com os olhos da cara. Não era mau rapaz, mas tinha o seu 31 com os olhos da cara. N�o era mau rapaz, mas tinha o seu
32 grão de egoísmo, e se não era incapaz de afeições, sabia 32 gr�o de ego�smo, e se n�o era incapaz de afei��es, sabia
33 regê-las, moderá-las, e sobretudo guiá-las ao seu próprio 33 reg�-las, moder�-las, e sobretudo gui�-las ao seu pr�prio
34 interesse. Entre estes dois homens travara-se amizade 34 interesse. Entre estes dois homens travara-se amizade
35 íntima, nascida para um na simpatia, para outro no costume. 35 �ntima, nascida para um na simpatia, para outro no costume.
36 Eram eles os naturais confidentes um do outro, com a 36 Eram eles os naturais confidentes um do outro, com a
37 diferença que Luís Alves dava menos do que recebia, e, ainda 37 diferen�a que Lu�s Alves dava menos do que recebia, e, ainda
38 assim, nem tudo o que dava exprimia grande confiança. 38 assim, nem tudo o que dava exprimia grande confian�a.
39]] 39]]
40 40
41local function random(handle, io_err) 41local function random(handle, io_err)
@@ -44,8 +44,8 @@ local function random(handle, io_err)
44 if not handle then error("source is empty!", 2) end 44 if not handle then error("source is empty!", 2) end
45 local len = math.random(0, 1024) 45 local len = math.random(0, 1024)
46 local chunk = handle:read(len) 46 local chunk = handle:read(len)
47 if not chunk then 47 if not chunk then
48 handle:close() 48 handle:close()
49 handle = nil 49 handle = nil
50 end 50 end
51 return chunk 51 return chunk
@@ -62,7 +62,7 @@ local what = nil
62local function transform(input, output, filter) 62local function transform(input, output, filter)
63 local source = random(io.open(input, "rb")) 63 local source = random(io.open(input, "rb"))
64 local sink = ltn12.sink.file(io.open(output, "wb")) 64 local sink = ltn12.sink.file(io.open(output, "wb"))
65 if what then 65 if what then
66 sink = ltn12.sink.chain(filter, sink) 66 sink = ltn12.sink.chain(filter, sink)
67 else 67 else
68 source = ltn12.source.chain(source, filter) 68 source = ltn12.source.chain(source, filter)
@@ -147,7 +147,7 @@ local function create_qptest()
147 f:write(' ',string.char(32)) 147 f:write(' ',string.char(32))
148 end 148 end
149 f:write("\r\n") 149 f:write("\r\n")
150 150
151 f:close() 151 f:close()
152end 152end
153 153
@@ -157,7 +157,7 @@ local function cleanup_qptest()
157 os.remove(dqptest) 157 os.remove(dqptest)
158end 158end
159 159
160-- create test file 160-- create test file
161local function create_b64test() 161local function create_b64test()
162 local f = assert(io.open(b64test, "wb")) 162 local f = assert(io.open(b64test, "wb"))
163 local t = {} 163 local t = {}
diff --git a/test/smtptest.lua b/test/smtptest.lua
index b5380ff..9d06054 100644
--- a/test/smtptest.lua
+++ b/test/smtptest.lua
@@ -27,8 +27,8 @@ local total = function()
27end 27end
28 28
29local similar = function(s1, s2) 29local similar = function(s1, s2)
30 return 30 return
31 string.lower(string.gsub(s1, "%s", "")) == 31 string.lower(string.gsub(s1, "%s", "")) ==
32 string.lower(string.gsub(s2, "%s", "")) 32 string.lower(string.gsub(s2, "%s", ""))
33end 33end
34 34
@@ -40,9 +40,9 @@ end
40 40
41local readfile = function(name) 41local readfile = function(name)
42 local f = io.open(name, "r") 42 local f = io.open(name, "r")
43 if not f then 43 if not f then
44 fail("unable to open file!") 44 fail("unable to open file!")
45 return nil 45 return nil
46 end 46 end
47 local s = f:read("*a") 47 local s = f:read("*a")
48 f:close() 48 f:close()
@@ -52,7 +52,7 @@ end
52local empty = function() 52local empty = function()
53 for i,v in ipairs(files) do 53 for i,v in ipairs(files) do
54 local f = io.open(v, "w") 54 local f = io.open(v, "w")
55 if not f then 55 if not f then
56 fail("unable to open file!") 56 fail("unable to open file!")
57 end 57 end
58 f:close() 58 f:close()
@@ -116,8 +116,8 @@ local wait = function(sentinel, n)
116 while 1 do 116 while 1 do
117 local mbox = parse(get()) 117 local mbox = parse(get())
118 if n == #mbox then break end 118 if n == #mbox then break end
119 if socket.time() - sentinel.time > 50 then 119 if socket.time() - sentinel.time > 50 then
120 to = 1 120 to = 1
121 break 121 break
122 end 122 end
123 socket.sleep(1) 123 socket.sleep(1)
@@ -132,7 +132,7 @@ local stuffed_body = [[
132This message body needs to be 132This message body needs to be
133stuffed because it has a dot 133stuffed because it has a dot
134. 134.
135by itself on a line. 135by itself on a line.
136Otherwise the mailer would 136Otherwise the mailer would
137think that the dot 137think that the dot
138. 138.
@@ -219,7 +219,7 @@ else print("ok") end
219 219
220io.write("testing invalid from: ") 220io.write("testing invalid from: ")
221local ret, err = socket.smtp.mail{ 221local ret, err = socket.smtp.mail{
222 from = ' " " (( _ * ', 222 from = ' " " (( _ * ',
223 rcpt = rcpt, 223 rcpt = rcpt,
224} 224}
225if ret or not err then fail("wrong error message") 225if ret or not err then fail("wrong error message")
@@ -227,7 +227,7 @@ else print(err) end
227 227
228io.write("testing no rcpt: ") 228io.write("testing no rcpt: ")
229local ret, err = socket.smtp.mail{ 229local ret, err = socket.smtp.mail{
230 from = from, 230 from = from,
231} 231}
232if ret or not err then fail("wrong error message") 232if ret or not err then fail("wrong error message")
233else print(err) end 233else print(err) end
diff --git a/test/tcp-getoptions b/test/tcp-getoptions
index f9b3d1b..fbcc884 100755
--- a/test/tcp-getoptions
+++ b/test/tcp-getoptions
@@ -1,19 +1,35 @@
1#!/usr/bin/env lua 1#!/usr/bin/env lua
2 2
3require"socket" 3local socket = require"socket"
4 4
5port = 8765 5port = 8765
6 6
7function pcalltest(msg, o, opt)
8 local a = { pcall(o.getoption, o, opt) }
9 if a[1] then
10 print(msg, opt, unpack(a))
11 else
12 print(msg, opt, 'fail: ' .. a[2])
13 end
14end
15
7function options(o) 16function options(o)
8 print("options for", o) 17 print("options for", o)
9 18
10 for _, opt in ipairs{"keepalive", "reuseaddr", "tcp-nodelay"} do 19 for _, opt in ipairs{
11 print("getoption", opt, o:getoption(opt)) 20 "keepalive", "reuseaddr",
21 "tcp-nodelay", "tcp-keepidle", "tcp-keepcnt", "tcp-keepintvl"} do
22 pcalltest("getoption", o, opt)
12 end 23 end
13 24
14 print("getoption", "linger", 25 r = o:getoption'linger'
15 "on", o:getoption("linger").on, 26 if r then
16 "timeout", o:getoption("linger").timeout) 27 print("getoption", "linger",
28 "on", r.on,
29 "timeout", r.timeout)
30 else
31 print("getoption", "linger", "no result")
32 end
17end 33end
18 34
19local m = socket.tcp() 35local m = socket.tcp()
diff --git a/test/test_socket_error.lua b/test/test_socket_error.lua
index bda6408..1b4b601 100644
--- a/test/test_socket_error.lua
+++ b/test/test_socket_error.lua
@@ -19,7 +19,7 @@ for i = 1, 10 do
19 assert(ss == sock) 19 assert(ss == sock)
20 else 20 else
21 assert('timeout' == err, 'unexpected error :' .. tostring(err)) 21 assert('timeout' == err, 'unexpected error :' .. tostring(err))
22 end 22 end
23 err = sock:getoption("error") -- i get 'connection refused' on WinXP 23 err = sock:getoption("error") -- i get 'connection refused' on WinXP
24 if err then 24 if err then
25 print("Passed! Error is '" .. err .. "'.") 25 print("Passed! Error is '" .. err .. "'.")
diff --git a/test/testclnt.lua b/test/testclnt.lua
index ee1201f..170e187 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -669,7 +669,6 @@ local udp_methods = {
669 "settimeout" 669 "settimeout"
670} 670}
671 671
672
673------------------------------------------------------------------------ 672------------------------------------------------------------------------
674test_methods(socket.udp(), udp_methods) 673test_methods(socket.udp(), udp_methods)
675do local sock = socket.tcp6() 674do local sock = socket.tcp6()
diff --git a/test/testmesg.lua b/test/testmesg.lua
index 135a008..8c086d5 100644
--- a/test/testmesg.lua
+++ b/test/testmesg.lua
@@ -34,11 +34,11 @@ r, e = smtp.send{
34 34
35print(r, e) 35print(r, e)
36 36
37-- creates a source to send a message with two parts. The first part is 37-- creates a source to send a message with two parts. The first part is
38-- plain text, the second part is a PNG image, encoded as base64. 38-- plain text, the second part is a PNG image, encoded as base64.
39source = smtp.message{ 39source = smtp.message{
40 headers = { 40 headers = {
41 -- Remember that headers are *ignored* by smtp.send. 41 -- Remember that headers are *ignored* by smtp.send.
42 from = "Sicrano <sicrano@tecgraf.puc-rio.br>", 42 from = "Sicrano <sicrano@tecgraf.puc-rio.br>",
43 to = "Fulano <fulano@tecgraf.puc-rio.br>", 43 to = "Fulano <fulano@tecgraf.puc-rio.br>",
44 subject = "Here is a message with attachments" 44 subject = "Here is a message with attachments"
@@ -49,18 +49,18 @@ source = smtp.message{
49 "Preamble might show up even in a MIME enabled client.", 49 "Preamble might show up even in a MIME enabled client.",
50 -- first part: No headers means plain text, us-ascii. 50 -- first part: No headers means plain text, us-ascii.
51 -- The mime.eol low-level filter normalizes end-of-line markers. 51 -- The mime.eol low-level filter normalizes end-of-line markers.
52 [1] = { 52 [1] = {
53 body = mime.eol(0, [[ 53 body = mime.eol(0, [[
54 Lines in a message body should always end with CRLF. 54 Lines in a message body should always end with CRLF.
55 The smtp module will *NOT* perform translation. It will 55 The smtp module will *NOT* perform translation. It will
56 perform necessary stuffing, though. 56 perform necessary stuffing, though.
57 ]]) 57 ]])
58 }, 58 },
59 -- second part: Headers describe content the to be an image, 59 -- second part: Headers describe content the to be an image,
60 -- sent under the base64 transfer content encoding. 60 -- sent under the base64 transfer content encoding.
61 -- Notice that nothing happens until the message is sent. Small 61 -- Notice that nothing happens until the message is sent. Small
62 -- chunks are loaded into memory and translation happens on the fly. 62 -- chunks are loaded into memory and translation happens on the fly.
63 [2] = { 63 [2] = {
64 headers = { 64 headers = {
65 ["ConTenT-tYpE"] = 'image/png; name="luasocket.png"', 65 ["ConTenT-tYpE"] = 'image/png; name="luasocket.png"',
66 ["content-disposition"] = 'attachment; filename="luasocket.png"', 66 ["content-disposition"] = 'attachment; filename="luasocket.png"',
diff --git a/test/testsupport.lua b/test/testsupport.lua
index b986088..4360b6b 100644
--- a/test/testsupport.lua
+++ b/test/testsupport.lua
@@ -7,7 +7,7 @@ function readfile(name)
7end 7end
8 8
9function similar(s1, s2) 9function similar(s1, s2)
10 return string.lower(string.gsub(s1 or "", "%s", "")) == 10 return string.lower(string.gsub(s1 or "", "%s", "")) ==
11 string.lower(string.gsub(s2 or "", "%s", "")) 11 string.lower(string.gsub(s2 or "", "%s", ""))
12end 12end
13 13
diff --git a/test/udp-zero-length-send b/test/udp-zero-length-send
index a594944..9038c99 100755
--- a/test/udp-zero-length-send
+++ b/test/udp-zero-length-send
@@ -1,4 +1,4 @@
1#!/usr/bin/lua 1#!/usr/bin/env lua
2 2
3--[[ 3--[[
4Show that luasocket returns an error message on zero-length UDP sends, 4Show that luasocket returns an error message on zero-length UDP sends,
@@ -12,7 +12,7 @@ listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
12 12
13]] 13]]
14 14
15require"socket" 15socket = require"socket"
16 16
17s = assert(socket.udp()) 17s = assert(socket.udp())
18r = assert(socket.udp()) 18r = assert(socket.udp())
diff --git a/test/udp-zero-length-send-recv b/test/udp-zero-length-send-recv
index 541efd4..064ca52 100755
--- a/test/udp-zero-length-send-recv
+++ b/test/udp-zero-length-send-recv
@@ -1,4 +1,4 @@
1#!/usr/bin/lua 1#!/usr/bin/env lua
2 2
3--[[ 3--[[
4Show that luasocket returns an error message on zero-length UDP sends, 4Show that luasocket returns an error message on zero-length UDP sends,
@@ -12,7 +12,7 @@ listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
12 12
13]] 13]]
14 14
15require"socket" 15socket = require"socket"
16 16
17s = assert(socket.udp()) 17s = assert(socket.udp())
18r = assert(socket.udp()) 18r = assert(socket.udp())
diff --git a/test/unixdgramclnt.lua b/test/unixdgramclnt.lua
new file mode 100644
index 0000000..9bd60f7
--- /dev/null
+++ b/test/unixdgramclnt.lua
@@ -0,0 +1,9 @@
1socket = require"socket"
2socket.unix = require"socket.unix"
3c = assert(socket.unix.dgram())
4print(c:bind("/tmp/bar"))
5while 1 do
6 local l = io.read("*l")
7 assert(c:sendto(l, "/tmp/foo"))
8 print(assert(c:receivefrom()))
9end
diff --git a/test/unixdgramsrvr.lua b/test/unixdgramsrvr.lua
new file mode 100644
index 0000000..4c11f55
--- /dev/null
+++ b/test/unixdgramsrvr.lua
@@ -0,0 +1,9 @@
1 socket = require"socket"
2 socket.unix = require"socket.unix"
3 u = assert(socket.unix.dgram())
4 assert(u:bind("/tmp/foo"))
5 while 1 do
6 x, r = assert(u:receivefrom())
7 print(x, r)
8 assert(u:sendto(">" .. x, r))
9 end
diff --git a/test/unixclnt.lua b/test/unixstreamclnt.lua
index 5171535..4f2e1e3 100644
--- a/test/unixclnt.lua
+++ b/test/unixstreamclnt.lua
@@ -1,6 +1,6 @@
1socket = require"socket" 1socket = require"socket"
2socket.unix = require"socket.unix" 2socket.unix = require"socket.unix"
3c = assert(socket.unix()) 3c = assert(socket.unix.stream())
4assert(c:connect("/tmp/foo")) 4assert(c:connect("/tmp/foo"))
5while 1 do 5while 1 do
6 local l = io.read() 6 local l = io.read()
diff --git a/test/unixsrvr.lua b/test/unixstreamsrvr.lua
index 81b9c99..0a5c644 100644
--- a/test/unixsrvr.lua
+++ b/test/unixstreamsrvr.lua
@@ -1,6 +1,6 @@
1 socket = require"socket" 1 socket = require"socket"
2 socket.unix = require"socket.unix" 2 socket.unix = require"socket.unix"
3 u = assert(socket.unix()) 3 u = assert(socket.unix.stream())
4 assert(u:bind("/tmp/foo")) 4 assert(u:bind("/tmp/foo"))
5 assert(u:listen()) 5 assert(u:listen())
6 c = assert(u:accept()) 6 c = assert(u:accept())
diff --git a/test/urltest.lua b/test/urltest.lua
index 32cb348..9a3c470 100644
--- a/test/urltest.lua
+++ b/test/urltest.lua
@@ -60,8 +60,8 @@ end
60 60
61local check_absolute_url = function(base, relative, absolute) 61local check_absolute_url = function(base, relative, absolute)
62 local res = socket.url.absolute(base, relative) 62 local res = socket.url.absolute(base, relative)
63 if res ~= absolute then 63 if res ~= absolute then
64 io.write("absolute: In test for '", relative, "' expected '", 64 io.write("absolute: In test for base='", base, "', rel='", relative, "' expected '",
65 absolute, "' but got '", res, "'\n") 65 absolute, "' but got '", res, "'\n")
66 os.exit() 66 os.exit()
67 end 67 end
@@ -73,7 +73,7 @@ local check_parse_url = function(gaba)
73 local parsed = socket.url.parse(url) 73 local parsed = socket.url.parse(url)
74 for i, v in pairs(gaba) do 74 for i, v in pairs(gaba) do
75 if v ~= parsed[i] then 75 if v ~= parsed[i] then
76 io.write("parse: In test for '", url, "' expected ", i, " = '", 76 io.write("parse: In test for '", url, "' expected ", i, " = '",
77 v, "' but got '", tostring(parsed[i]), "'\n") 77 v, "' but got '", tostring(parsed[i]), "'\n")
78 for i,v in pairs(parsed) do print(i,v) end 78 for i,v in pairs(parsed) do print(i,v) end
79 os.exit() 79 os.exit()
@@ -81,7 +81,7 @@ local check_parse_url = function(gaba)
81 end 81 end
82 for i, v in pairs(parsed) do 82 for i, v in pairs(parsed) do
83 if v ~= gaba[i] then 83 if v ~= gaba[i] then
84 io.write("parse: In test for '", url, "' expected ", i, " = '", 84 io.write("parse: In test for '", url, "' expected ", i, " = '",
85 tostring(gaba[i]), "' but got '", v, "'\n") 85 tostring(gaba[i]), "' but got '", v, "'\n")
86 for i,v in pairs(parsed) do print(i,v) end 86 for i,v in pairs(parsed) do print(i,v) end
87 os.exit() 87 os.exit()
@@ -91,9 +91,78 @@ end
91 91
92print("testing URL parsing") 92print("testing URL parsing")
93check_parse_url{ 93check_parse_url{
94 url = "scheme://user:pass$%?#wd@host:port/path;params?query#fragment",
95 scheme = "scheme",
96 authority = "user:pass$%?#wd@host:port",
97 host = "host",
98 port = "port",
99 userinfo = "user:pass$%?#wd",
100 password = "pass$%?#wd",
101 user = "user",
102 path = "/path",
103 params = "params",
104 query = "query",
105 fragment = "fragment"
106}
107check_parse_url{
108 url = "scheme://user:pass?#wd@host:port/path;params?query#fragment",
109 scheme = "scheme",
110 authority = "user:pass?#wd@host:port",
111 host = "host",
112 port = "port",
113 userinfo = "user:pass?#wd",
114 password = "pass?#wd",
115 user = "user",
116 path = "/path",
117 params = "params",
118 query = "query",
119 fragment = "fragment"
120}
121check_parse_url{
122 url = "scheme://user:pass-wd@host:port/path;params?query#fragment",
123 scheme = "scheme",
124 authority = "user:pass-wd@host:port",
125 host = "host",
126 port = "port",
127 userinfo = "user:pass-wd",
128 password = "pass-wd",
129 user = "user",
130 path = "/path",
131 params = "params",
132 query = "query",
133 fragment = "fragment"
134}
135check_parse_url{
136 url = "scheme://user:pass#wd@host:port/path;params?query#fragment",
137 scheme = "scheme",
138 authority = "user:pass#wd@host:port",
139 host = "host",
140 port = "port",
141 userinfo = "user:pass#wd",
142 password = "pass#wd",
143 user = "user",
144 path = "/path",
145 params = "params",
146 query = "query",
147 fragment = "fragment"
148}
149check_parse_url{
150 url = "scheme://user:pass#wd@host:port/path;params?query",
151 scheme = "scheme",
152 authority = "user:pass#wd@host:port",
153 host = "host",
154 port = "port",
155 userinfo = "user:pass#wd",
156 password = "pass#wd",
157 user = "user",
158 path = "/path",
159 params = "params",
160 query = "query",
161}
162check_parse_url{
94 url = "scheme://userinfo@host:port/path;params?query#fragment", 163 url = "scheme://userinfo@host:port/path;params?query#fragment",
95 scheme = "scheme", 164 scheme = "scheme",
96 authority = "userinfo@host:port", 165 authority = "userinfo@host:port",
97 host = "host", 166 host = "host",
98 port = "port", 167 port = "port",
99 userinfo = "userinfo", 168 userinfo = "userinfo",
@@ -106,8 +175,8 @@ check_parse_url{
106 175
107check_parse_url{ 176check_parse_url{
108 url = "scheme://user:password@host:port/path;params?query#fragment", 177 url = "scheme://user:password@host:port/path;params?query#fragment",
109 scheme = "scheme", 178 scheme = "scheme",
110 authority = "user:password@host:port", 179 authority = "user:password@host:port",
111 host = "host", 180 host = "host",
112 port = "port", 181 port = "port",
113 userinfo = "user:password", 182 userinfo = "user:password",
@@ -121,8 +190,8 @@ check_parse_url{
121 190
122check_parse_url{ 191check_parse_url{
123 url = "scheme://userinfo@host:port/path;params?query#", 192 url = "scheme://userinfo@host:port/path;params?query#",
124 scheme = "scheme", 193 scheme = "scheme",
125 authority = "userinfo@host:port", 194 authority = "userinfo@host:port",
126 host = "host", 195 host = "host",
127 port = "port", 196 port = "port",
128 userinfo = "userinfo", 197 userinfo = "userinfo",
@@ -135,8 +204,8 @@ check_parse_url{
135 204
136check_parse_url{ 205check_parse_url{
137 url = "scheme://userinfo@host:port/path;params?#fragment", 206 url = "scheme://userinfo@host:port/path;params?#fragment",
138 scheme = "scheme", 207 scheme = "scheme",
139 authority = "userinfo@host:port", 208 authority = "userinfo@host:port",
140 host = "host", 209 host = "host",
141 port = "port", 210 port = "port",
142 userinfo = "userinfo", 211 userinfo = "userinfo",
@@ -149,8 +218,8 @@ check_parse_url{
149 218
150check_parse_url{ 219check_parse_url{
151 url = "scheme://userinfo@host:port/path;params#fragment", 220 url = "scheme://userinfo@host:port/path;params#fragment",
152 scheme = "scheme", 221 scheme = "scheme",
153 authority = "userinfo@host:port", 222 authority = "userinfo@host:port",
154 host = "host", 223 host = "host",
155 port = "port", 224 port = "port",
156 userinfo = "userinfo", 225 userinfo = "userinfo",
@@ -162,8 +231,8 @@ check_parse_url{
162 231
163check_parse_url{ 232check_parse_url{
164 url = "scheme://userinfo@host:port/path;?query#fragment", 233 url = "scheme://userinfo@host:port/path;?query#fragment",
165 scheme = "scheme", 234 scheme = "scheme",
166 authority = "userinfo@host:port", 235 authority = "userinfo@host:port",
167 host = "host", 236 host = "host",
168 port = "port", 237 port = "port",
169 userinfo = "userinfo", 238 userinfo = "userinfo",
@@ -176,8 +245,8 @@ check_parse_url{
176 245
177check_parse_url{ 246check_parse_url{
178 url = "scheme://userinfo@host:port/path?query#fragment", 247 url = "scheme://userinfo@host:port/path?query#fragment",
179 scheme = "scheme", 248 scheme = "scheme",
180 authority = "userinfo@host:port", 249 authority = "userinfo@host:port",
181 host = "host", 250 host = "host",
182 port = "port", 251 port = "port",
183 userinfo = "userinfo", 252 userinfo = "userinfo",
@@ -189,8 +258,8 @@ check_parse_url{
189 258
190check_parse_url{ 259check_parse_url{
191 url = "scheme://userinfo@host:port/;params?query#fragment", 260 url = "scheme://userinfo@host:port/;params?query#fragment",
192 scheme = "scheme", 261 scheme = "scheme",
193 authority = "userinfo@host:port", 262 authority = "userinfo@host:port",
194 host = "host", 263 host = "host",
195 port = "port", 264 port = "port",
196 userinfo = "userinfo", 265 userinfo = "userinfo",
@@ -203,8 +272,8 @@ check_parse_url{
203 272
204check_parse_url{ 273check_parse_url{
205 url = "scheme://userinfo@host:port", 274 url = "scheme://userinfo@host:port",
206 scheme = "scheme", 275 scheme = "scheme",
207 authority = "userinfo@host:port", 276 authority = "userinfo@host:port",
208 host = "host", 277 host = "host",
209 port = "port", 278 port = "port",
210 userinfo = "userinfo", 279 userinfo = "userinfo",
@@ -213,7 +282,7 @@ check_parse_url{
213 282
214check_parse_url{ 283check_parse_url{
215 url = "//userinfo@host:port/path;params?query#fragment", 284 url = "//userinfo@host:port/path;params?query#fragment",
216 authority = "userinfo@host:port", 285 authority = "userinfo@host:port",
217 host = "host", 286 host = "host",
218 port = "port", 287 port = "port",
219 userinfo = "userinfo", 288 userinfo = "userinfo",
@@ -226,7 +295,7 @@ check_parse_url{
226 295
227check_parse_url{ 296check_parse_url{
228 url = "//userinfo@host:port/path", 297 url = "//userinfo@host:port/path",
229 authority = "userinfo@host:port", 298 authority = "userinfo@host:port",
230 host = "host", 299 host = "host",
231 port = "port", 300 port = "port",
232 userinfo = "userinfo", 301 userinfo = "userinfo",
@@ -236,7 +305,7 @@ check_parse_url{
236 305
237check_parse_url{ 306check_parse_url{
238 url = "//userinfo@host/path", 307 url = "//userinfo@host/path",
239 authority = "userinfo@host", 308 authority = "userinfo@host",
240 host = "host", 309 host = "host",
241 userinfo = "userinfo", 310 userinfo = "userinfo",
242 user = "userinfo", 311 user = "userinfo",
@@ -245,7 +314,7 @@ check_parse_url{
245 314
246check_parse_url{ 315check_parse_url{
247 url = "//user:password@host/path", 316 url = "//user:password@host/path",
248 authority = "user:password@host", 317 authority = "user:password@host",
249 host = "host", 318 host = "host",
250 userinfo = "user:password", 319 userinfo = "user:password",
251 password = "password", 320 password = "password",
@@ -255,7 +324,7 @@ check_parse_url{
255 324
256check_parse_url{ 325check_parse_url{
257 url = "//user:@host/path", 326 url = "//user:@host/path",
258 authority = "user:@host", 327 authority = "user:@host",
259 host = "host", 328 host = "host",
260 userinfo = "user:", 329 userinfo = "user:",
261 password = "", 330 password = "",
@@ -265,7 +334,7 @@ check_parse_url{
265 334
266check_parse_url{ 335check_parse_url{
267 url = "//user@host:port/path", 336 url = "//user@host:port/path",
268 authority = "user@host:port", 337 authority = "user@host:port",
269 host = "host", 338 host = "host",
270 userinfo = "user", 339 userinfo = "user",
271 user = "user", 340 user = "user",
@@ -275,7 +344,7 @@ check_parse_url{
275 344
276check_parse_url{ 345check_parse_url{
277 url = "//host:port/path", 346 url = "//host:port/path",
278 authority = "host:port", 347 authority = "host:port",
279 port = "port", 348 port = "port",
280 host = "host", 349 host = "host",
281 path = "/path", 350 path = "/path",
@@ -283,14 +352,14 @@ check_parse_url{
283 352
284check_parse_url{ 353check_parse_url{
285 url = "//host/path", 354 url = "//host/path",
286 authority = "host", 355 authority = "host",
287 host = "host", 356 host = "host",
288 path = "/path", 357 path = "/path",
289} 358}
290 359
291check_parse_url{ 360check_parse_url{
292 url = "//host", 361 url = "//host",
293 authority = "host", 362 authority = "host",
294 host = "host", 363 host = "host",
295} 364}
296 365
@@ -364,7 +433,7 @@ check_parse_url{
364 433
365check_parse_url{ 434check_parse_url{
366 url = "//userinfo@[::FFFF:129.144.52.38]:port/path;params?query#fragment", 435 url = "//userinfo@[::FFFF:129.144.52.38]:port/path;params?query#fragment",
367 authority = "userinfo@[::FFFF:129.144.52.38]:port", 436 authority = "userinfo@[::FFFF:129.144.52.38]:port",
368 host = "::FFFF:129.144.52.38", 437 host = "::FFFF:129.144.52.38",
369 port = "port", 438 port = "port",
370 userinfo = "userinfo", 439 userinfo = "userinfo",
@@ -378,7 +447,7 @@ check_parse_url{
378check_parse_url{ 447check_parse_url{
379 url = "scheme://user:password@[::192.9.5.5]:port/path;params?query#fragment", 448 url = "scheme://user:password@[::192.9.5.5]:port/path;params?query#fragment",
380 scheme = "scheme", 449 scheme = "scheme",
381 authority = "user:password@[::192.9.5.5]:port", 450 authority = "user:password@[::192.9.5.5]:port",
382 host = "::192.9.5.5", 451 host = "::192.9.5.5",
383 port = "port", 452 port = "port",
384 userinfo = "user:password", 453 userinfo = "user:password",
@@ -393,7 +462,7 @@ check_parse_url{
393print("testing URL building") 462print("testing URL building")
394check_build_url { 463check_build_url {
395 url = "scheme://user:password@host:port/path;params?query#fragment", 464 url = "scheme://user:password@host:port/path;params?query#fragment",
396 scheme = "scheme", 465 scheme = "scheme",
397 host = "host", 466 host = "host",
398 port = "port", 467 port = "port",
399 user = "user", 468 user = "user",
@@ -430,7 +499,7 @@ check_build_url{
430 499
431check_build_url { 500check_build_url {
432 url = "scheme://user:password@host/path;params?query#fragment", 501 url = "scheme://user:password@host/path;params?query#fragment",
433 scheme = "scheme", 502 scheme = "scheme",
434 host = "host", 503 host = "host",
435 user = "user", 504 user = "user",
436 password = "password", 505 password = "password",
@@ -442,7 +511,7 @@ check_build_url {
442 511
443check_build_url { 512check_build_url {
444 url = "scheme://user@host/path;params?query#fragment", 513 url = "scheme://user@host/path;params?query#fragment",
445 scheme = "scheme", 514 scheme = "scheme",
446 host = "host", 515 host = "host",
447 user = "user", 516 user = "user",
448 path = "/path", 517 path = "/path",
@@ -453,7 +522,7 @@ check_build_url {
453 522
454check_build_url { 523check_build_url {
455 url = "scheme://host/path;params?query#fragment", 524 url = "scheme://host/path;params?query#fragment",
456 scheme = "scheme", 525 scheme = "scheme",
457 host = "host", 526 host = "host",
458 path = "/path", 527 path = "/path",
459 params = "params", 528 params = "params",
@@ -463,7 +532,7 @@ check_build_url {
463 532
464check_build_url { 533check_build_url {
465 url = "scheme://host/path;params#fragment", 534 url = "scheme://host/path;params#fragment",
466 scheme = "scheme", 535 scheme = "scheme",
467 host = "host", 536 host = "host",
468 path = "/path", 537 path = "/path",
469 params = "params", 538 params = "params",
@@ -472,7 +541,7 @@ check_build_url {
472 541
473check_build_url { 542check_build_url {
474 url = "scheme://host/path#fragment", 543 url = "scheme://host/path#fragment",
475 scheme = "scheme", 544 scheme = "scheme",
476 host = "host", 545 host = "host",
477 path = "/path", 546 path = "/path",
478 fragment = "fragment" 547 fragment = "fragment"
@@ -480,7 +549,7 @@ check_build_url {
480 549
481check_build_url { 550check_build_url {
482 url = "scheme://host/path", 551 url = "scheme://host/path",
483 scheme = "scheme", 552 scheme = "scheme",
484 host = "host", 553 host = "host",
485 path = "/path", 554 path = "/path",
486} 555}
@@ -498,7 +567,7 @@ check_build_url {
498 567
499check_build_url { 568check_build_url {
500 url = "scheme://user:password@host:port/path;params?query#fragment", 569 url = "scheme://user:password@host:port/path;params?query#fragment",
501 scheme = "scheme", 570 scheme = "scheme",
502 host = "host", 571 host = "host",
503 port = "port", 572 port = "port",
504 user = "user", 573 user = "user",
@@ -512,7 +581,7 @@ check_build_url {
512 581
513check_build_url { 582check_build_url {
514 url = "scheme://user:password@host:port/path;params?query#fragment", 583 url = "scheme://user:password@host:port/path;params?query#fragment",
515 scheme = "scheme", 584 scheme = "scheme",
516 host = "host", 585 host = "host",
517 port = "port", 586 port = "port",
518 user = "user", 587 user = "user",
@@ -527,7 +596,7 @@ check_build_url {
527 596
528check_build_url { 597check_build_url {
529 url = "scheme://user:password@host:port/path;params?query#fragment", 598 url = "scheme://user:password@host:port/path;params?query#fragment",
530 scheme = "scheme", 599 scheme = "scheme",
531 host = "host", 600 host = "host",
532 port = "port", 601 port = "port",
533 userinfo = "user:password", 602 userinfo = "user:password",
@@ -540,7 +609,7 @@ check_build_url {
540 609
541check_build_url { 610check_build_url {
542 url = "scheme://user:password@host:port/path;params?query#fragment", 611 url = "scheme://user:password@host:port/path;params?query#fragment",
543 scheme = "scheme", 612 scheme = "scheme",
544 authority = "user:password@host:port", 613 authority = "user:password@host:port",
545 path = "/path", 614 path = "/path",
546 params = "params", 615 params = "params",
@@ -558,25 +627,37 @@ check_absolute_url("http://a/b/c/d;p?q#f", "/g", "http://a/g")
558check_absolute_url("http://a/b/c/d;p?q#f", "//g", "http://g") 627check_absolute_url("http://a/b/c/d;p?q#f", "//g", "http://g")
559check_absolute_url("http://a/b/c/d;p?q#f", "?y", "http://a/b/c/d;p?y") 628check_absolute_url("http://a/b/c/d;p?q#f", "?y", "http://a/b/c/d;p?y")
560check_absolute_url("http://a/b/c/d;p?q#f", "g?y", "http://a/b/c/g?y") 629check_absolute_url("http://a/b/c/d;p?q#f", "g?y", "http://a/b/c/g?y")
561check_absolute_url("http://a/b/c/d;p?q#f", "g?y/./x", "http://a/b/c/g?y/./x") 630check_absolute_url("http://a/b/c/d;p?q#f", "g?y/./x", "http://a/b/c/g?y/x")
562check_absolute_url("http://a/b/c/d;p?q#f", "#s", "http://a/b/c/d;p?q#s") 631check_absolute_url("http://a/b/c/d;p?q#f", "#s", "http://a/b/c/d;p?q#s")
563check_absolute_url("http://a/b/c/d;p?q#f", "g#s", "http://a/b/c/g#s") 632check_absolute_url("http://a/b/c/d;p?q#f", "g#s", "http://a/b/c/g#s")
564check_absolute_url("http://a/b/c/d;p?q#f", "g#s/./x", "http://a/b/c/g#s/./x") 633check_absolute_url("http://a/b/c/d;p?q#f", "g#s/./x", "http://a/b/c/g#s/x")
565check_absolute_url("http://a/b/c/d;p?q#f", "g?y#s", "http://a/b/c/g?y#s") 634check_absolute_url("http://a/b/c/d;p?q#f", "g?y#s", "http://a/b/c/g?y#s")
566check_absolute_url("http://a/b/c/d;p?q#f", ";x", "http://a/b/c/d;x") 635check_absolute_url("http://a/b/c/d;p?q#f", ";x", "http://a/b/c/d;x")
567check_absolute_url("http://a/b/c/d;p?q#f", "g;x", "http://a/b/c/g;x") 636check_absolute_url("http://a/b/c/d;p?q#f", "g;x", "http://a/b/c/g;x")
568check_absolute_url("http://a/b/c/d;p?q#f", "g;x?y#s", "http://a/b/c/g;x?y#s") 637check_absolute_url("http://a/b/c/d;p?q#f", "g;x?y#s", "http://a/b/c/g;x?y#s")
569check_absolute_url("http://a/b/c/d;p?q#f", ".", "http://a/b/c/") 638check_absolute_url("http://a/b/c/d;p?q#f", ".", "http://a/b/c/")
570check_absolute_url("http://a/b/c/d;p?q#f", "./", "http://a/b/c/") 639check_absolute_url("http://a/b/c/d;p?q#f", "./", "http://a/b/c/")
640check_absolute_url("http://a/b/c/d;p?q#f", "./g", "http://a/b/c/g")
641check_absolute_url("http://a/b/c/d;p?q#f", "./g/", "http://a/b/c/g/")
642check_absolute_url("http://a/b/c/d;p?q#f", "././g", "http://a/b/c/g")
643check_absolute_url("http://a/b/c/d;p?q#f", "././g/", "http://a/b/c/g/")
644check_absolute_url("http://a/b/c/d;p?q#f", "g/.", "http://a/b/c/g/")
645check_absolute_url("http://a/b/c/d;p?q#f", "g/./", "http://a/b/c/g/")
646check_absolute_url("http://a/b/c/d;p?q#f", "g/./.", "http://a/b/c/g/")
647check_absolute_url("http://a/b/c/d;p?q#f", "g/././", "http://a/b/c/g/")
648check_absolute_url("http://a/b/c/d;p?q#f", "./.", "http://a/b/c/")
649check_absolute_url("http://a/b/c/d;p?q#f", "././.", "http://a/b/c/")
650check_absolute_url("http://a/b/c/d;p?q#f", "././g/./.", "http://a/b/c/g/")
571check_absolute_url("http://a/b/c/d;p?q#f", "..", "http://a/b/") 651check_absolute_url("http://a/b/c/d;p?q#f", "..", "http://a/b/")
572check_absolute_url("http://a/b/c/d;p?q#f", "../", "http://a/b/") 652check_absolute_url("http://a/b/c/d;p?q#f", "../", "http://a/b/")
573check_absolute_url("http://a/b/c/d;p?q#f", "../g", "http://a/b/g") 653check_absolute_url("http://a/b/c/d;p?q#f", "../g", "http://a/b/g")
574check_absolute_url("http://a/b/c/d;p?q#f", "../..", "http://a/") 654check_absolute_url("http://a/b/c/d;p?q#f", "../..", "http://a/")
575check_absolute_url("http://a/b/c/d;p?q#f", "../../", "http://a/") 655check_absolute_url("http://a/b/c/d;p?q#f", "../../", "http://a/")
576check_absolute_url("http://a/b/c/d;p?q#f", "../../g", "http://a/g") 656check_absolute_url("http://a/b/c/d;p?q#f", "../../g", "http://a/g")
657check_absolute_url("http://a/b/c/d;p?q#f", "../../../g", "http://a/g")
577check_absolute_url("http://a/b/c/d;p?q#f", "", "http://a/b/c/d;p?q#f") 658check_absolute_url("http://a/b/c/d;p?q#f", "", "http://a/b/c/d;p?q#f")
578check_absolute_url("http://a/b/c/d;p?q#f", "/./g", "http://a/./g") 659check_absolute_url("http://a/b/c/d;p?q#f", "/./g", "http://a/g")
579check_absolute_url("http://a/b/c/d;p?q#f", "/../g", "http://a/../g") 660check_absolute_url("http://a/b/c/d;p?q#f", "/../g", "http://a/g")
580check_absolute_url("http://a/b/c/d;p?q#f", "g.", "http://a/b/c/g.") 661check_absolute_url("http://a/b/c/d;p?q#f", "g.", "http://a/b/c/g.")
581check_absolute_url("http://a/b/c/d;p?q#f", ".g", "http://a/b/c/.g") 662check_absolute_url("http://a/b/c/d;p?q#f", ".g", "http://a/b/c/.g")
582check_absolute_url("http://a/b/c/d;p?q#f", "g..", "http://a/b/c/g..") 663check_absolute_url("http://a/b/c/d;p?q#f", "g..", "http://a/b/c/g..")
@@ -586,31 +667,53 @@ check_absolute_url("http://a/b/c/d;p?q#f", "./g/.", "http://a/b/c/g/")
586check_absolute_url("http://a/b/c/d;p?q#f", "g/./h", "http://a/b/c/g/h") 667check_absolute_url("http://a/b/c/d;p?q#f", "g/./h", "http://a/b/c/g/h")
587check_absolute_url("http://a/b/c/d;p?q#f", "g/../h", "http://a/b/c/h") 668check_absolute_url("http://a/b/c/d;p?q#f", "g/../h", "http://a/b/c/h")
588 669
670check_absolute_url("http://a/b/c/d:p?q#f/", "../g/", "http://a/b/g/")
671check_absolute_url("http://a/b/c/d:p?q#f/", "../g", "http://a/b/g")
672check_absolute_url("http://a/b/c/d:p?q#f/", "../.g/", "http://a/b/.g/")
673check_absolute_url("http://a/b/c/d:p?q#f/", "../.g", "http://a/b/.g")
674check_absolute_url("http://a/b/c/d:p?q#f/", "../.g.h/", "http://a/b/.g.h/")
675check_absolute_url("http://a/b/c/d:p?q#f/", "../.g.h", "http://a/b/.g.h")
676
677check_absolute_url("http://a/b/c/d:p?q#f/", "g.h/", "http://a/b/c/g.h/")
678check_absolute_url("http://a/b/c/d:p?q#f/", "../g.h/", "http://a/b/g.h/")
679check_absolute_url("http://a/", "../g.h/", "http://a/g.h/")
680
589-- extra tests 681-- extra tests
590check_absolute_url("//a/b/c/d;p?q#f", "d/e/f", "//a/b/c/d/e/f") 682check_absolute_url("//a/b/c/d;p?q#f", "d/e/f", "//a/b/c/d/e/f")
591check_absolute_url("/a/b/c/d;p?q#f", "d/e/f", "/a/b/c/d/e/f") 683check_absolute_url("/a/b/c/d;p?q#f", "d/e/f", "/a/b/c/d/e/f")
592check_absolute_url("a/b/c/d", "d/e/f", "a/b/c/d/e/f") 684check_absolute_url("a/b/c/d", "d/e/f", "a/b/c/d/e/f")
593check_absolute_url("a/b/c/d/../", "d/e/f", "a/b/c/d/e/f") 685check_absolute_url("a/b/c/d/../", "d/e/f", "a/b/c/d/e/f")
594check_absolute_url("http://velox.telemar.com.br", "/dashboard/index.html", 686check_absolute_url("http://velox.telemar.com.br", "/dashboard/index.html",
595 "http://velox.telemar.com.br/dashboard/index.html") 687 "http://velox.telemar.com.br/dashboard/index.html")
688check_absolute_url("http://example.com/", "../.badhost.com/", "http://example.com/.badhost.com/")
689check_absolute_url("http://example.com/", "...badhost.com/", "http://example.com/...badhost.com/")
690check_absolute_url("http://example.com/a/b/c/d/", "../q", "http://example.com/a/b/c/q")
691check_absolute_url("http://example.com/a/b/c/d/", "../../q", "http://example.com/a/b/q")
692check_absolute_url("http://example.com/a/b/c/d/", "../../../q", "http://example.com/a/q")
693check_absolute_url("http://example.com", ".badhost.com", "http://example.com/.badhost.com")
694check_absolute_url("http://example.com/a/b/c/d/", "..//../../../q", "http://example.com/a/q")
695check_absolute_url("http://example.com/a/b/c/d/", "..//a/../../../../q", "http://example.com/a/q")
696check_absolute_url("http://example.com/a/b/c/d/", "..//a/..//../../../q", "http://example.com/a/b/q")
697check_absolute_url("http://example.com/a/b/c/d/", "..//a/..///../../../../q", "http://example.com/a/b/q")
698check_absolute_url("http://example.com/a/b/c/d/", "../x/a/../y/z/../../../../q", "http://example.com/a/b/q")
596 699
597print("testing path parsing and composition") 700print("testing path parsing and composition")
598check_parse_path("/eu/tu/ele", { "eu", "tu", "ele"; is_absolute = 1 }) 701check_parse_path("/eu/tu/ele", { "eu", "tu", "ele"; is_absolute = 1 })
599check_parse_path("/eu/", { "eu"; is_absolute = 1, is_directory = 1 }) 702check_parse_path("/eu/", { "eu"; is_absolute = 1, is_directory = 1 })
600check_parse_path("eu/tu/ele/nos/vos/eles/", 703check_parse_path("eu/tu/ele/nos/vos/eles/",
601 { "eu", "tu", "ele", "nos", "vos", "eles"; is_directory = 1}) 704 { "eu", "tu", "ele", "nos", "vos", "eles"; is_directory = 1})
602check_parse_path("/", { is_absolute = 1, is_directory = 1}) 705check_parse_path("/", { is_absolute = 1, is_directory = 1})
603check_parse_path("", { }) 706check_parse_path("", { })
604check_parse_path("eu%01/%02tu/e%03l%04e/nos/vos%05/e%12les/", 707check_parse_path("eu%01/%02tu/e%03l%04e/nos/vos%05/e%12les/",
605 { "eu\1", "\2tu", "e\3l\4e", "nos", "vos\5", "e\18les"; is_directory = 1}) 708 { "eu\1", "\2tu", "e\3l\4e", "nos", "vos\5", "e\18les"; is_directory = 1})
606check_parse_path("eu/tu", { "eu", "tu" }) 709check_parse_path("eu/tu", { "eu", "tu" })
607 710
608print("testing path protection") 711print("testing path protection")
609check_protect({ "eu", "-_.!~*'():@&=+$,", "tu" }, "eu/-_.!~*'():@&=+$,/tu") 712check_protect({ "eu", "-_.!~*'():@&=+$,", "tu" }, "eu/-_.!~*'():@&=+$,/tu")
610check_protect({ "eu ", "~diego" }, "eu%20/~diego") 713check_protect({ "eu ", "~diego" }, "eu%20/~diego")
611check_protect({ "/eu>", "<diego?" }, "%2feu%3e/%3cdiego%3f") 714check_protect({ "/eu>", "<diego?" }, "%2Feu%3E/%3Cdiego%3F")
612check_protect({ "\\eu]", "[diego`" }, "%5ceu%5d/%5bdiego%60") 715check_protect({ "\\eu]", "[diego`" }, "%5Ceu%5D/%5Bdiego%60")
613check_protect({ "{eu}", "|diego\127" }, "%7beu%7d/%7cdiego%7f") 716check_protect({ "{eu}", "|diego\127" }, "%7Beu%7D/%7Cdiego%7F")
614check_protect({ "eu ", "~diego" }, "eu /~diego", 1) 717check_protect({ "eu ", "~diego" }, "eu /~diego", 1)
615check_protect({ "/eu>", "<diego?" }, "/eu>/<diego?", 1) 718check_protect({ "/eu>", "<diego?" }, "/eu>/<diego?", 1)
616check_protect({ "\\eu]", "[diego`" }, "\\eu]/[diego`", 1) 719check_protect({ "\\eu]", "[diego`" }, "\\eu]/[diego`", 1)
diff --git a/test/utestclnt.lua b/test/utestclnt.lua
index 34a0718..7f10643 100644
--- a/test/utestclnt.lua
+++ b/test/utestclnt.lua
@@ -54,30 +54,30 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
54 if not err then warn("must be buffered") 54 if not err then warn("must be buffered")
55 elseif err == "timeout" then pass("proper timeout") 55 elseif err == "timeout" then pass("proper timeout")
56 else fail("unexpected error '%s'", err) end 56 else fail("unexpected error '%s'", err) end
57 else 57 else
58 if err ~= "timeout" then fail("should have timed out") 58 if err ~= "timeout" then fail("should have timed out")
59 else pass("proper timeout") end 59 else pass("proper timeout") end
60 end 60 end
61 else 61 else
62 if mode == "total" then 62 if mode == "total" then
63 if elapsed > tm then 63 if elapsed > tm then
64 if err ~= "timeout" then fail("should have timed out") 64 if err ~= "timeout" then fail("should have timed out")
65 else pass("proper timeout") end 65 else pass("proper timeout") end
66 elseif elapsed < tm then 66 elseif elapsed < tm then
67 if err then fail(err) 67 if err then fail(err)
68 else pass("ok") end 68 else pass("ok") end
69 else 69 else
70 if alldone then 70 if alldone then
71 if err then fail("unexpected error '%s'", err) 71 if err then fail("unexpected error '%s'", err)
72 else pass("ok") end 72 else pass("ok") end
73 else 73 else
74 if err ~= "timeout" then fail(err) 74 if err ~= "timeout" then fail(err)
75 else pass("proper timeoutk") end 75 else pass("proper timeoutk") end
76 end 76 end
77 end 77 end
78 else 78 else
79 if err then fail(err) 79 if err then fail(err)
80 else pass("ok") end 80 else pass("ok") end
81 end 81 end
82 end 82 end
83end 83end
@@ -104,7 +104,7 @@ function reconnect()
104 print("done " .. i) 104 print("done " .. i)
105 ]] 105 ]]
106 data, err = uconnect(host, port) 106 data, err = uconnect(host, port)
107 if not data then fail(err) 107 if not data then fail(err)
108 else pass("connected!") end 108 else pass("connected!") end
109end 109end
110 110
@@ -116,8 +116,8 @@ else pass("connected!") end
116------------------------------------------------------------------------ 116------------------------------------------------------------------------
117function test_methods(sock, methods) 117function test_methods(sock, methods)
118 for _, v in pairs(methods) do 118 for _, v in pairs(methods) do
119 if type(sock[v]) ~= "function" then 119 if type(sock[v]) ~= "function" then
120 fail(sock.class .. " method '" .. v .. "' not registered") 120 fail(sock.class .. " method '" .. v .. "' not registered")
121 end 121 end
122 end 122 end
123 pass(sock.class .. " methods are ok") 123 pass(sock.class .. " methods are ok")
@@ -132,7 +132,7 @@ function test_mixed(len)
132 local p3 = "raw " .. string.rep("z", inter) .. "bytes" 132 local p3 = "raw " .. string.rep("z", inter) .. "bytes"
133 local p4 = "end" .. string.rep("w", inter) .. "bytes" 133 local p4 = "end" .. string.rep("w", inter) .. "bytes"
134 local bp1, bp2, bp3, bp4 134 local bp1, bp2, bp3, bp4
135remote (string.format("str = data:receive(%d)", 135remote (string.format("str = data:receive(%d)",
136 string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) 136 string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
137 sent, err = data:send(p1..p2..p3..p4) 137 sent, err = data:send(p1..p2..p3..p4)
138 if err then fail(err) end 138 if err then fail(err) end
@@ -172,7 +172,7 @@ function test_rawline(len)
172 reconnect() 172 reconnect()
173 local str, str10, back, err 173 local str, str10, back, err
174 str = string.rep(string.char(47), math.mod(len, 10)) 174 str = string.rep(string.char(47), math.mod(len, 10))
175 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), 175 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
176 math.floor(len/10)) 176 math.floor(len/10))
177 str = str .. str10 177 str = str .. str10
178remote "str = data:receive()" 178remote "str = data:receive()"
@@ -221,7 +221,7 @@ function test_totaltimeoutreceive(len, tm, sl)
221 data:settimeout(tm, "total") 221 data:settimeout(tm, "total")
222local t = socket.gettime() 222local t = socket.gettime()
223 str, err, partial, elapsed = data:receive(2*len) 223 str, err, partial, elapsed = data:receive(2*len)
224 check_timeout(tm, sl, elapsed, err, "receive", "total", 224 check_timeout(tm, sl, elapsed, err, "receive", "total",
225 string.len(str or partial) == 2*len) 225 string.len(str or partial) == 2*len)
226end 226end
227 227
@@ -241,7 +241,7 @@ function test_totaltimeoutsend(len, tm, sl)
241 data:settimeout(tm, "total") 241 data:settimeout(tm, "total")
242 str = string.rep("a", 2*len) 242 str = string.rep("a", 2*len)
243 total, err, partial, elapsed = data:send(str) 243 total, err, partial, elapsed = data:send(str)
244 check_timeout(tm, sl, elapsed, err, "send", "total", 244 check_timeout(tm, sl, elapsed, err, "send", "total",
245 total == 2*len) 245 total == 2*len)
246end 246end
247 247
@@ -261,7 +261,7 @@ function test_blockingtimeoutreceive(len, tm, sl)
261 ]], 2*tm, len, sl, sl)) 261 ]], 2*tm, len, sl, sl))
262 data:settimeout(tm) 262 data:settimeout(tm)
263 str, err, partial, elapsed = data:receive(2*len) 263 str, err, partial, elapsed = data:receive(2*len)
264 check_timeout(tm, sl, elapsed, err, "receive", "blocking", 264 check_timeout(tm, sl, elapsed, err, "receive", "blocking",
265 string.len(str or partial) == 2*len) 265 string.len(str or partial) == 2*len)
266end 266end
267 267
@@ -294,10 +294,10 @@ function empty_connect()
294 data = server:accept() 294 data = server:accept()
295 ]] 295 ]]
296 data, err = socket.connect("", port) 296 data, err = socket.connect("", port)
297 if not data then 297 if not data then
298 pass("ok") 298 pass("ok")
299 data = socket.connect(host, port) 299 data = socket.connect(host, port)
300 else 300 else
301 pass("gethostbyname returns localhost on empty string...") 301 pass("gethostbyname returns localhost on empty string...")
302 end 302 end
303end 303end
@@ -331,7 +331,7 @@ function test_closed()
331 data:close() 331 data:close()
332 data = nil 332 data = nil
333 ]], str)) 333 ]], str))
334 -- try to get a line 334 -- try to get a line
335 back, err, partial = data:receive() 335 back, err, partial = data:receive()
336 if not err then fail("should have gotten 'closed'.") 336 if not err then fail("should have gotten 'closed'.")
337 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") 337 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
@@ -344,25 +344,25 @@ function test_closed()
344 data = nil 344 data = nil
345 ]] 345 ]]
346 total, err, partial = data:send(string.rep("ugauga", 100000)) 346 total, err, partial = data:send(string.rep("ugauga", 100000))
347 if not err then 347 if not err then
348 pass("failed: output buffer is at least %d bytes long!", total) 348 pass("failed: output buffer is at least %d bytes long!", total)
349 elseif err ~= "closed" then 349 elseif err ~= "closed" then
350 fail("got '"..err.."' instead of 'closed'.") 350 fail("got '"..err.."' instead of 'closed'.")
351 else 351 else
352 pass("graceful 'closed' received after %d bytes were sent", partial) 352 pass("graceful 'closed' received after %d bytes were sent", partial)
353 end 353 end
354end 354end
355 355
356------------------------------------------------------------------------ 356------------------------------------------------------------------------
357function test_selectbugs() 357function test_selectbugs()
358 local r, s, e = socket.select(nil, nil, 0.1) 358 local r, s, e = socket.select(nil, nil, 0.1)
359 assert(type(r) == "table" and type(s) == "table" and 359 assert(type(r) == "table" and type(s) == "table" and
360 (e == "timeout" or e == "error")) 360 (e == "timeout" or e == "error"))
361 pass("both nil: ok") 361 pass("both nil: ok")
362 local udp = socket.udp() 362 local udp = socket.udp()
363 udp:close() 363 udp:close()
364 r, s, e = socket.select({ udp }, { udp }, 0.1) 364 r, s, e = socket.select({ udp }, { udp }, 0.1)
365 assert(type(r) == "table" and type(s) == "table" and 365 assert(type(r) == "table" and type(s) == "table" and
366 (e == "timeout" or e == "error")) 366 (e == "timeout" or e == "error"))
367 pass("closed sockets: ok") 367 pass("closed sockets: ok")
368 e = pcall(socket.select, "wrong", 1, 0.1) 368 e = pcall(socket.select, "wrong", 1, 0.1)
@@ -380,7 +380,7 @@ function accept_timeout()
380 local t = socket.gettime() 380 local t = socket.gettime()
381 s:settimeout(1) 381 s:settimeout(1)
382 local c, e = s:accept() 382 local c, e = s:accept()
383 assert(not c, "should not accept") 383 assert(not c, "should not accept")
384 assert(e == "timeout", string.format("wrong error message (%s)", e)) 384 assert(e == "timeout", string.format("wrong error message (%s)", e))
385 t = socket.gettime() - t 385 t = socket.gettime() - t
386 assert(t < 2, string.format("took to long to give up (%gs)", t)) 386 assert(t < 2, string.format("took to long to give up (%gs)", t))
@@ -398,9 +398,9 @@ function connect_timeout()
398 local t = socket.gettime() 398 local t = socket.gettime()
399 local r, e = c:connect("127.0.0.2", 80) 399 local r, e = c:connect("127.0.0.2", 80)
400 assert(not r, "should not connect") 400 assert(not r, "should not connect")
401 assert(socket.gettime() - t < 2, "took too long to give up.") 401 assert(socket.gettime() - t < 2, "took too long to give up.")
402 c:close() 402 c:close()
403 print("ok") 403 print("ok")
404end 404end
405 405
406------------------------------------------------------------------------ 406------------------------------------------------------------------------
@@ -463,9 +463,9 @@ function getstats_test()
463 data:receive(c) 463 data:receive(c)
464 t = t + c 464 t = t + c
465 local r, s, a = data:getstats() 465 local r, s, a = data:getstats()
466 assert(r == t, "received count failed" .. tostring(r) 466 assert(r == t, "received count failed" .. tostring(r)
467 .. "/" .. tostring(t)) 467 .. "/" .. tostring(t))
468 assert(s == t, "sent count failed" .. tostring(s) 468 assert(s == t, "sent count failed" .. tostring(s)
469 .. "/" .. tostring(t)) 469 .. "/" .. tostring(t))
470 end 470 end
471 print("ok") 471 print("ok")
@@ -473,7 +473,7 @@ end
473 473
474 474
475------------------------------------------------------------------------ 475------------------------------------------------------------------------
476function test_nonblocking(size) 476function test_nonblocking(size)
477 reconnect() 477 reconnect()
478print("Testing " .. 2*size .. " bytes") 478print("Testing " .. 2*size .. " bytes")
479remote(string.format([[ 479remote(string.format([[
diff --git a/test/utestsrvr.lua b/test/utestsrvr.lua
index a96b570..b6e4246 100644
--- a/test/utestsrvr.lua
+++ b/test/utestsrvr.lua
@@ -9,7 +9,7 @@ ack = "\n";
9while 1 do 9while 1 do
10 print("server: waiting for client connection..."); 10 print("server: waiting for client connection...");
11 control = assert(server:accept()); 11 control = assert(server:accept());
12 while 1 do 12 while 1 do
13 command = assert(control:receive()); 13 command = assert(control:receive());
14 assert(control:send(ack)); 14 assert(control:send(ack));
15 ((loadstring or load)(command))(); 15 ((loadstring or load)(command))();
diff --git a/vc32.bat b/vc32.bat
new file mode 100755
index 0000000..7ff8c0e
--- /dev/null
+++ b/vc32.bat
@@ -0,0 +1,3 @@
1call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
2cls
3"c:\Program Files\Git\git-bash.exe" --cd-to-home
diff --git a/vc64.bat b/vc64.bat
new file mode 100755
index 0000000..ed5cb3a
--- /dev/null
+++ b/vc64.bat
@@ -0,0 +1,3 @@
1call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
2cls
3"c:\Program Files\Git\git-bash.exe" --cd-to-home
diff --git a/win32.cmd b/win32.cmd
index 48522f0..5eda3b1 100644..100755
--- a/win32.cmd
+++ b/win32.cmd
@@ -1,12 +1 @@
1make PLAT=win32 LUAV=5.2 LUAINC_win32='c:\cygwin\home\diego\build\include' LUALIB_win32='c:\cygwin\home\diego\build\bin\release' LUAV=5.3 PLAT=win32 LUAPREFIX_win32=/z/data/build/vc14 make
2
3#!/bin/sh
4for p in Release Debug x64/Release x64/Debug; do
5 for el in mime socket; do
6 for e in dll lib; do
7 cp $p/$el/core.$e ../bin/$p/$el/
8 done;
9 done;
10 cp src/ltn12.lua src/socket.lua src/mime.lua ../bin/$p/
11 cp src/http.lua src/url.lua src/tp.lua src/ftp.lua src/headers.lua src/smtp.lua ../bin/$p/socket/
12done;
diff --git a/win64.cmd b/win64.cmd
new file mode 100755
index 0000000..b1f9ac0
--- /dev/null
+++ b/win64.cmd
@@ -0,0 +1 @@
LUAV=5.3 PLAT=win64 LUAPREFIX_win64=/z/data/build/vc14 make