This commit is contained in:
PhoebeHui 2023-11-09 23:43:17 -08:00
commit b91a378e3b
119 changed files with 2721 additions and 3729 deletions

23
.editorconfig Normal file
View File

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

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

@ -0,0 +1,50 @@
name: Build
on:
push:
branches:
- master
pull_request:
jobs:
build:
name: Test ${{ matrix.luaVersion }} on ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
luaVersion: [ "5.4", "5.3", "5.2", "5.1", "luajit", "luajit-openresty" ]
platform: [ "ubuntu-22.04", "macos-11", "windows-2022" ]
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup msvc
if: ${{ startsWith(matrix.platform, 'windows') && !startsWith(matrix.luaVersion, 'luajit') }}
uses: ilammy/msvc-dev-cmd@v1
- name: Setup lua
uses: leso-kn/gh-actions-lua@v11-staging
with:
luaVersion: ${{ matrix.luaVersion }}
- name: Setup luarocks
uses: hishamhm/gh-actions-luarocks@master
- name: Make and install
run: |
luarocks make -- luasocket-scm-3.rockspec
env:
DEBUG: DEBUG
- name: Run regression tests
shell: bash
run: |
cd test
lua hello.lua
lua testsrvr.lua > /dev/null &
lua testclnt.lua
lua stufftest.lua
lua excepttest.lua
lua test_bind.lua
lua test_getaddrinfo.lua
lua ltn12test.lua
lua mimetest.lua
lua urltest.lua
lua test_socket_error.lua
kill %1

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

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

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

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

29
.luacheckrc Normal file
View File

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

View File

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

65
CHANGELOG.md Normal file
View File

@ -0,0 +1,65 @@
# Changelog
## [v3.1.0](https://github.com/lunarmodules/luasocket/releases/v3.1.0) — 2022-07-27
* Add support for TCP Defer Accept @Zash
* Add support for TCP Fast Open @Zash
* Fix Windows (mingw32) builds @goldenstein64
* Avoid build warnings on 64-bit Windows @rpatters1
## [v3.0.0](https://github.com/lunarmodules/luasocket/releases/v3.0.0) — 2022-03-25
The last time LuaSocket had a stable release tag was 14 years ago when 2.0.2 was tagged.
A v3 release candidate was tagged 9 years ago.
Since then it has been downloaded over 3 million times.
Additionally the Git repository regularly gets several hundred clones a day.
But 9 years is a long time and even the release candidate has grown a bit long in the tooth.
Many Linux distros have packaged the current Git HEAD or some specific tested point as dated or otherwise labeled releases.
256 commits later and having been migrated to the @lunarmodules org namespace on GitHub, please welcome v3.
This release is a "safe-harbor" tag that represents a minimal amount of changes to get a release tagged.
Beyond some CI tooling, very little code has changed since migration to @lunarmodules ([5b18e47..e47d98f](https://github.com/lunarmodules/luasocket/compare/5b18e47..e47d98f?w=1)):
* Lua 5.4.3+ support @pkulchenko, @Zash
* Cleanup minor issues to get a code linter to pass @Tieske, @jyoui, @alerque
* Update Visual Studio build rules for Lua 5.1 @ewestbrook
* Set http transfer-encoding even without content-length @tokenrove
Prior to migration to @lunarmodules ([v3.0-rc1..5b18e47](https://github.com/lunarmodules/luasocket/compare/v3.0-rc1..5b18e47?w=1)) many things happened of which the author of this changelog is not fully apprised.
Your best bet if it affects your project somehow is to read the commit log & diffs yourself.
## [v3.0-rc1](https://github.com/lunarmodules/luasocket/releases/v3.0-rc1) — 2013-06-14
Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
* Added: Compatible with Lua 5.2
- Note that unless you define LUA_COMPAT_MODULE, package tables will not be exported as globals!
* Added: IPv6 support;
- Socket.connect and socket.bind support IPv6 addresses;
- Getpeername and getsockname support IPv6 addresses, and return the socket family as a third value;
- URL module updated to support IPv6 host names;
- New socket.tcp6 and socket.udp6 functions;
- New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
* Added: getoption method;
* Fixed: url.unescape was returning additional values;
* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could mistaking their own stack slots for functions arguments;
* Fixed: Receiving zero-length datagram is now possible;
* Improved: Hidden all internal library symbols;
* Improved: Better error messages;
* Improved: Better documentation of socket options.
* Fixed: manual sample of HTTP authentication now uses correct "authorization" header (Alexandre Ittner);
* Fixed: failure on bind() was destroying the socket (Sam Roberts);
* Fixed: receive() returns immediatelly if prefix can satisfy bytes requested (M Joonas Pihlaja);
* Fixed: multicast didn't work on Windows, or anywhere else for that matter (Herbert Leuwer, Adrian Sietsma);
* Fixed: select() now reports an error when called with more sockets than FD_SETSIZE (Lorenzo Leonini);
* Fixed: manual links to home.html changed to index.html (Robert Hahn);
* Fixed: mime.unb64() would return an empty string on results that started with a null character (Robert Raschke);
* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
* Fixed: calling sleep() with negative numbers could block forever, wasting CPU. Now it returns immediately (MPB);
* Improved: FTP commands are now sent in upper case to help buggy servers (Anders Eurenius);
* Improved: known headers now sent in canonic capitalization to help buggy servers (Joseph Stewart);
* Improved: Clarified tcp:receive() in the manual (MPB);
* Improved: Decent makefiles (LHF).
* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
## [v2.0.2](https://github.com/lunarmodules/luasocket/releases/v2.0.2) — 2007-09-11

28
FIX
View File

@ -1,28 +0,0 @@
http was preserving old host header during redirects
fix smtp.send hang on source error
add create field to FTP and SMTP and fix HTTP ugliness
clean timeout argument to open functions in SMTP, HTTP and FTP
eliminate globals from namespaces created by module().
url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class.
tcp{client}:send() now returns i+sent-1...
get rid of a = socket.try() in the manual, except for protected cases. replace it with assert.
get rid of "base." kludge in package.loaded
check all "require("http")" etc in the manual.
make sure sock_gethostname.* only return success if the hp is not null!
change 'l' prefix in C libraries to 'c' to avoid clash with LHF libraries
don't forget the declarations in luasocket.h and mime.h!!!
setpeername was using udp{unconnected}
fixed a bug in http.lua that caused some requests to fail (Florian Berger)
fixed a bug in select.c that prevented sockets with descriptor 0 from working (Renato Maia)
fixed a "bug" that caused dns.toip to crash under uLinux
fixed a "bug" that caused a crash in gethostbyname under VMS
DEBUG and VERSION became _DEBUG and _VERSION
send returns the right value if input is "". Alexander Marinov

View File

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

44
NEW
View File

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

11
README
View File

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

12
README.md Normal file
View File

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

81
TODO
View File

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

135
TODO.md Normal file
View File

@ -0,0 +1,135 @@
## FIX
http was preserving old host header during redirects
fix smtp.send hang on source error
add create field to FTP and SMTP and fix HTTP ugliness
clean timeout argument to open functions in SMTP, HTTP and FTP
eliminate globals from namespaces created by module().
url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class.
tcp{client}:send() now returns i+sent-1...
get rid of a = socket.try() in the manual, except for protected cases. replace it with assert.
get rid of "base." kludge in package.loaded
check all "require("http")" etc in the manual.
make sure sock_gethostname.* only return success if the hp is not null!
change 'l' prefix in C libraries to 'c' to avoid clash with LHF libraries
don't forget the declarations in luasocket.h and mime.h!!!
setpeername was using udp{unconnected}
fixed a bug in http.lua that caused some requests to fail (Florian Berger)
fixed a bug in select.c that prevented sockets with descriptor 0 from working (Renato Maia)
fixed a "bug" that caused dns.toip to crash under uLinux
fixed a "bug" that caused a crash in gethostbyname under VMS
DEBUG and VERSION became _DEBUG and _VERSION
send returns the right value if input is "". Alexander Marinov
## WISH
... as an l-value to get all results of a function call?
at least ...[i] and #...
extend to full tuples?
__and __or __not metamethods
lua_tostring, lua_tonumber, lua_touseradta etc push values in stack
__tostring,__tonumber, __touserdata metamethods are checked
and expected to push an object of correct type on stack
lua_rawtostring, lua_rawtonumber, lua_rawtouserdata don't
push anything on stack, return data of appropriate type,
skip metamethods and throw error if object not of exact type
package.findfile exported
module not polluting the global namespace
coxpcall with a coroutine pool for efficiency (reusing coroutines)
exception mechanism formalized? just like the package system was.
a nice bitlib in the core
## TODO
- bizarre default values for getnameinfo should throw error instead!
> It's just too bad it can't talk to gmail -
> reason 1: they absolutely want TLS
> reason 2: unlike all the other SMTP implementations, they
> don't
> tolerate missing < > around adresses
- document the new bind and connect behavior.
- shouldn't we instead make the code compatible to Lua 5.2
without any compat stuff, and use a compatibility layer to
make it work on 5.1?
- add what's new to manual
- should there be an equivalent to tohostname for IPv6?
- should we add service name resolution as well to getaddrinfo?
- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
- add http POST sample to manual
people keep asking stupid questions
- documentation of dirty/getfd/setfd is problematic because of portability
same for unix and serial.
what to do about this? add a stronger disclaimer?
- fix makefile with decent defaults?
## Done:
- added IPv6 support to getsockname
- simplified getpeername implementation
- added family to return of getsockname and getpeername
and added modification to the manual to describe
- connect and bind try all adresses returned by getaddrinfo
- document headers.lua?
- update copyright date everywhere?
- remove RCSID from files?
- move version to 2.1 rather than 2.1.1?
- fixed url package to support ipv6 hosts
- changed domain to family
- implement getfamily methods.
- remove references to Lua 5.0 from documentation, add 5.2?
- update lua and luasocket version in samples in documentation
- document ipv5_v6only default option being set?
- document tcp6 and udp6
- document dns.getaddrinfo
- documented zero-sized datagram change?
no.
- document unix socket and serial socket? add raw support?
no.
- document getoption
- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
replace \r\n with \0xD\0xA in everything
New mime support
ftp send should return server replies?
make sure there are no object files in the distribution tarball
http handling of 100-continue, see DB patch
DB ftp.lua bug.
test unix.c to return just a function and works with require"unix"
get rid of setmetatable(, nil) since packages don't need this anymore in 5.1
compat-5.1 novo
ajeitar pra lua-5.1
adicionar exemplos de expans<6E>o: pipe, local, named pipe
testar os options!
- Thread-unsafe functions to protect
gethostbyname(), gethostbyaddr(), gethostent(),
inet_ntoa(), strerror(),

22
WISH
View File

@ -1,22 +0,0 @@
... as an l-value to get all results of a function call?
at least ...[i] and #...
extend to full tuples?
__and __or __not metamethods
lua_tostring, lua_tonumber, lua_touseradta etc push values in stack
__tostring,__tonumber, __touserdata metamethods are checked
and expected to push an object of correct type on stack
lua_rawtostring, lua_rawtonumber, lua_rawtouserdata don't
push anything on stack, return data of appropriate type,
skip metamethods and throw error if object not of exact type
package.findfile exported
module not polluting the global namespace
coxpcall with a coroutine pool for efficiency (reusing coroutines)
exception mechanism formalized? just like the package system was.
a nice bitlib in the core

View File

@ -1,215 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="The LuaSocket Homepage">
<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
<title>LuaSocket: Network support for the Lua language </title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=whatis>What is LuaSocket?</h2>
<p>
LuaSocket is a <a href="http://www.lua.org">Lua</a> extension library
that is composed by two parts: a C core that provides support for the TCP
and UDP transport layers, and a set of Lua modules that add support for
functionality commonly needed by applications that deal with the Internet.
</p>
<p>
The core support has been implemented so that it is both efficient and
simple to use. It is available to any Lua application once it has been
properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and UNIX platforms. </p>
<p>
Among the support modules, the most commonly used implement the
<a href=smtp.html>SMTP</a>
(sending e-mails),
<a href=http.html>HTTP</a>
(WWW access) and
<a href=ftp.html>FTP</a>
(uploading and downloading files) client
protocols. These provide a very natural and generic interface to the
functionality defined by each protocol.
In addition, you will find that the
<a href=mime.html>MIME</a> (common encodings),
<a href=url.html>URL</a>
(anything you could possible want to do with one) and
<a href=ltn12.html>LTN12</a>
(filters, sinks, sources and pumps) modules can be very handy.
</p>
<p>
The library is available under the same
<a href="http://www.lua.org/copyright.html">
terms and conditions</a> as the Lua language, the MIT license. The idea is
that if you can use Lua in a project, you should also be able to use
LuaSocket.
</p>
<p>
Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
</p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=download>Download</h2>
<p>
LuaSocket version 3.0-rc1 is now available for download!
It is compatible with Lua&nbsp;5.1 and 5.2, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
are it works well on most UNIX distributions and Windows flavors.
</p>
<p>
The current version of the library can be found at
the <a href="https://github.com/diegonehab/luasocket">LuaSocket
project page</a> on GitHub. Besides the full C and Lua source code
for the library, the distribution contains several examples,
this user's manual and basic test procedures.
</p>
<p> Take a look at the <a
href=installation.html>installation</a> section of the
manual to find out how to properly install the library.
</p>
<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=thanks>Special thanks</h2>
<p>
This marks the first release of LuaSocket that
wholeheartedly embraces the open-source development
philosophy. After a long hiatus, Matthew Wild finally
convinced me it was time for a release including IPv6 and
Lua 5.2 support. It was more work than we anticipated.
Special thanks to Sam Roberts, Florian Zeitz, and Paul
Aurich, Liam Devine, Alexey Melnichuk, and everybody else
that has helped bring this library back to life.
</p>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=new>What's New</h2>
<p>
Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
and Lua&nbsp;5.2 compatibility.
</p>
<ul>
<li> Added: Compatible with Lua&nbsp;5.2
<ul>
<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
package tables will <em>not</em> be exported as globals!
</ul>
<li> Added: IPv6 support;
<ul>
<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
IPv6 addresses, and return the socket family as a third value;
<li> URL module updated to support IPv6 host names;
<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
<li> New <tt>socket.dns.getaddrinfo</tt> and
<tt>socket.dns.getnameinfo</tt> functions;
</ul>
<li> Added: <tt>getoption</tt> method;
<li> Fixed: <tt>url.unescape</tt> was returning additional values;
<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
<tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
mistaking their own stack slots for functions arguments;
<li> Fixed: Receiving zero-length datagram is now possible;
<li> Improved: Hidden all internal library symbols;
<li> Improved: Better error messages;
<li> Improved: Better documentation of socket options.
<li> Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
<li> Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
<li> Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
<li> Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
<li> Fixed: manual links to home.html changed to index.html
(Robert Hahn);
<li> Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
<li> Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
<li> Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
<li> Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
<li> Improved: Clarified tcp:receive() in the manual (MPB);
<li> Improved: Decent makefiles (LHF).
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
</ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=old>Old Versions</h2>
<p>
All previous versions of the LuaSocket library can be downloaded <a
href="http://www.impa.br/~diego/software/luasocket/old">
here</a>. Although these versions are no longer supported, they are
still available for those that have compatibility issues.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Tue Jun 11 18:50:23 HKT 2013
</small>
</p>
</center>
</div>
</body>
</html>

Binary file not shown.

View File

@ -13,17 +13,17 @@
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -36,13 +36,13 @@
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=dns>DNS</h2> <h2 id="dns">DNS</h2>
<p> <p>
IPv4 name resolution functions IPv4 name resolution functions
<a href=#toip><tt>dns.toip</tt></a> <a href="#toip"><tt>dns.toip</tt></a>
and and
<a href=#tohostname><tt>dns.tohostname</tt></a> <a href="#tohostname"><tt>dns.tohostname</tt></a>
return <em>all</em> information obtained from return <em>all</em> information obtained from
the resolver in a table of the form: the resolver in a table of the form:
</p> </p>
@ -61,7 +61,7 @@ Note that the <tt>alias</tt> list can be empty.
<p> <p>
The more general name resolution function The more general name resolution function
<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which <a href="#getaddrinfo"><tt>dns.getaddrinfo</tt></a>, which
supports both IPv6 and IPv4, supports both IPv6 and IPv4,
returns <em>all</em> information obtained from returns <em>all</em> information obtained from
the resolver in a table of the form: the resolver in a table of the form:
@ -88,19 +88,19 @@ addresses, and <tt>"inet6"</tt> for IPv6 addresses.
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getaddrinfo> <p class="name" id="getaddrinfo">
socket.dns.<b>getaddrinfo(</b>address<b>)</b> socket.dns.<b>getaddrinfo(</b>address<b>)</b>
</p> </p>
<p class=description> <p class="description">
Converts from host name to address. Converts from host name to address.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Address</tt> can be an IPv4 or IPv6 address or host name. <tt>Address</tt> can be an IPv4 or IPv6 address or host name.
</p> </p>
<p class=return> <p class="return">
The function returns a table with all information returned by The function returns a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b> the resolver. In case of error, the function returns <b><tt>nil</tt></b>
followed by an error message. followed by an error message.
@ -108,29 +108,29 @@ followed by an error message.
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gethostname> <p class="name" id="gethostname">
socket.dns.<b>gethostname()</b> socket.dns.<b>gethostname()</b>
</p> </p>
<p class=description> <p class="description">
Returns the standard host name for the machine as a string. Returns the standard host name for the machine as a string.
</p> </p>
<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=tohostname> <p class="name" id="tohostname">
socket.dns.<b>tohostname(</b>address<b>)</b> socket.dns.<b>tohostname(</b>address<b>)</b>
</p> </p>
<p class=description> <p class="description">
Converts from IPv4 address to host name. Converts from IPv4 address to host name.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Address</tt> can be an IP address or host name. <tt>Address</tt> can be an IP address or host name.
</p> </p>
<p class=return> <p class="return">
The function returns a string with the canonic host name of the given The function returns a string with the canonic host name of the given
<tt>address</tt>, followed by a table with all information returned by <tt>address</tt>, followed by a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b> the resolver. In case of error, the function returns <b><tt>nil</tt></b>
@ -139,19 +139,19 @@ followed by an error message.
<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=toip> <p class="name" id="toip">
socket.dns.<b>toip(</b>address<b>)</b> socket.dns.<b>toip(</b>address<b>)</b>
</p> </p>
<p class=description> <p class="description">
Converts from host name to IPv4 address. Converts from host name to IPv4 address.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Address</tt> can be an IP address or host name. <tt>Address</tt> can be an IP address or host name.
</p> </p>
<p class=return> <p class="return">
Returns a string with the first IP address found for <tt>address</tt>, Returns a string with the first IP address found for <tt>address</tt>,
followed by a table with all information returned by the resolver. followed by a table with all information returned by the resolver.
In case of error, the function returns <b><tt>nil</tt></b> followed by an error In case of error, the function returns <b><tt>nil</tt></b> followed by an error
@ -160,10 +160,10 @@ message.
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -13,17 +13,17 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -36,7 +36,7 @@
<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ftp>FTP</h2> <h2 id="ftp">FTP</h2>
<p> <p>
FTP (File Transfer Protocol) is a protocol used to transfer files FTP (File Transfer Protocol) is a protocol used to transfer files
@ -63,7 +63,7 @@ LTN012, Filters sources and sinks</a> is necessary.
To obtain the <tt>ftp</tt> namespace, run: To obtain the <tt>ftp</tt> namespace, run:
</p> </p>
<pre class=example> <pre class="example">
-- loads the FTP module and any libraries it requires -- loads the FTP module and any libraries it requires
local ftp = require("socket.ftp") local ftp = require("socket.ftp")
</pre> </pre>
@ -85,15 +85,15 @@ the FTP module:
</p> </p>
<ul> <ul>
<li> <tt>PASSWORD</tt>: default anonymous password. <li> <tt>PASSWORD</tt>: default anonymous password.</li>
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; <li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
<li> <tt>USER</tt>: default anonymous user; <li> <tt>USER</tt>: default anonymous user;</li>
</ul> </ul>
<!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=get> <p class="name" id="get">
ftp.<b>get(</b>url<b>)</b><br> ftp.<b>get(</b>url<b>)</b><br>
ftp.<b>get{</b><br> ftp.<b>get{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br> &nbsp;&nbsp;host = <i>string</i>,<br>
@ -109,14 +109,14 @@ ftp.<b>get{</b><br>
<b>}</b> <b>}</b>
</p> </p>
<p class=description> <p class="description">
The <tt>get</tt> function has two forms. The simple form has fixed The <tt>get</tt> function has two forms. The simple form has fixed
functionality: it downloads the contents of a URL and returns it as a functionality: it downloads the contents of a URL and returns it as a
string. The generic form allows a <em>lot</em> more control, as explained string. The generic form allows a <em>lot</em> more control, as explained
below. below.
</p> </p>
<p class=parameters> <p class="parameters">
If the argument of the <tt>get</tt> function is a table, the function If the argument of the <tt>get</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes <tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
@ -129,28 +129,28 @@ optional arguments are the following:
</p> </p>
<ul> <ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for <li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>"; authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
<li><tt>command</tt>: The FTP command used to obtain data. Defaults to <li><tt>command</tt>: The FTP command used to obtain data. Defaults to
"<tt>retr</tt>", but see example below; "<tt>retr</tt>", but see example below;</li>
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21; <li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or <li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default; "<tt>a</tt>". Defaults to whatever is the server default;</li>
<li><tt>step</tt>: <li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function; server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
<li><tt>create</tt>: An optional function to be used instead of <li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. <a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
</ul> </ul>
<p class=return> <p class="return">
If successful, the simple version returns the URL contents as a If successful, the simple version returns the URL contents as a
string, and the generic function returns 1. In case of error, both string, and the generic function returns 1. In case of error, both
functions return <b><tt>nil</tt></b> and an error message describing the functions return <b><tt>nil</tt></b> and an error message describing the
error. error.
</p> </p>
<pre class=example> <pre class="example">
-- load the ftp support -- load the ftp support
local ftp = require("socket.ftp") local ftp = require("socket.ftp")
@ -159,7 +159,7 @@ local ftp = require("socket.ftp")
f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i") f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
</pre> </pre>
<pre class=example> <pre class="example">
-- load needed modules -- load needed modules
local ftp = require("socket.ftp") local ftp = require("socket.ftp")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
@ -178,7 +178,7 @@ end
<!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=put> <p class="name" id="put">
ftp.<b>put(</b>url, content<b>)</b><br> ftp.<b>put(</b>url, content<b>)</b><br>
ftp.<b>put{</b><br> ftp.<b>put{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br> &nbsp;&nbsp;host = <i>string</i>,<br>
@ -194,13 +194,13 @@ ftp.<b>put{</b><br>
<b>}</b> <b>}</b>
</p> </p>
<p class=description> <p class="description">
The <tt>put</tt> function has two forms. The simple form has fixed The <tt>put</tt> function has two forms. The simple form has fixed
functionality: it uploads a string of content into a URL. The generic form functionality: it uploads a string of content into a URL. The generic form
allows a <em>lot</em> more control, as explained below. allows a <em>lot</em> more control, as explained below.
</p> </p>
<p class=parameters> <p class="parameters">
If the argument of the <tt>put</tt> function is a table, the function If the argument of the <tt>put</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes <tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
@ -214,26 +214,26 @@ optional arguments are the following:
</p> </p>
<ul> <ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for <li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>"; authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";</li>
<li><tt>command</tt>: The FTP command used to send data. Defaults to <li><tt>command</tt>: The FTP command used to send data. Defaults to
"<tt>stor</tt>", but see example below; "<tt>stor</tt>", but see example below;</li>
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21; <li><tt>port</tt>: The port to used for the control connection. Defaults to 21;</li>
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or <li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default; "<tt>a</tt>". Defaults to whatever is the server default;</li>
<li><tt>step</tt>: <li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function; server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
<li><tt>create</tt>: An optional function to be used instead of <li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. <a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
</ul> </ul>
<p class=return> <p class="return">
Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error
message describing the reason for failure. message describing the reason for failure.
</p> </p>
<pre class=example> <pre class="example">
-- load the ftp support -- load the ftp support
local ftp = require("socket.ftp") local ftp = require("socket.ftp")
@ -244,7 +244,7 @@ f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",
"wrong password, of course") "wrong password, of course")
</pre> </pre>
<pre class=example> <pre class="example">
-- load the ftp support -- load the ftp support
local ftp = require("socket.ftp") local ftp = require("socket.ftp")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
@ -265,10 +265,10 @@ f, e = ftp.put{
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -13,17 +13,17 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="introduction.html">introduction</a> &middot; <a href="introduction.html">introduction</a> &middot;
@ -59,7 +59,7 @@ string oriented requests, through generic
To obtain the <tt>http</tt> namespace, run: To obtain the <tt>http</tt> namespace, run:
</p> </p>
<pre class=example> <pre class="example">
-- loads the HTTP module and any libraries it requires -- loads the HTTP module and any libraries it requires
local http = require("socket.http") local http = require("socket.http")
</pre> </pre>
@ -97,11 +97,11 @@ headers = {<br>
<p> <p>
Field names are case insensitive (as specified by the standard) and all Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>). <a href="socket.html#headers.canonic"><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified. Field values are left unmodified.
</p> </p>
<p class=note> <p class="note">
Note: MIME headers are independent of order. Therefore, there is no problem Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table. in representing them in a Lua table.
</p> </p>
@ -112,19 +112,19 @@ the HTTP module:
</p> </p>
<ul> <ul>
<li> <tt>PROXY</tt>: default proxy used for connections; <li> <tt>PROXY</tt>: default proxy used for connections;</li>
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations; <li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;</li>
<li> <tt>USERAGENT</tt>: default user agent reported to server. <li> <tt>USERAGENT</tt>: default user agent reported to server.</li>
</ul> </ul>
<p class=note id="post"> <p class="note">
Note: These constants are global. Changing them will also Note: These constants are global. Changing them will also
change the behavior other code that might be using LuaSocket. change the behavior other code that might be using LuaSocket.
</p> </p>
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="request"> <p class="name" id="request">
http.<b>request(</b>url [, body]<b>)</b><br> http.<b>request(</b>url [, body]<b>)</b><br>
http.<b>request{</b><br> http.<b>request{</b><br>
&nbsp;&nbsp;url = <i>string</i>,<br> &nbsp;&nbsp;url = <i>string</i>,<br>
@ -140,14 +140,14 @@ http.<b>request{</b><br>
<b>}</b> <b>}</b>
</p> </p>
<p class=description> <p class="description">
The request function has two forms. The simple form downloads The request function has two forms. The simple form downloads
a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based
on strings. The generic form performs any HTTP method and is on strings. The generic form performs any HTTP method and is
<a href=http://lua-users.org/wiki/FiltersSourcesAndSinks>LTN12</a> based. <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based.
</p> </p>
<p class=parameters> <p class="parameters">
If the first argument of the <tt>request</tt> function is a string, it If the first argument of the <tt>request</tt> function is a string, it
should be an <tt>url</tt>. In that case, if a <tt>body</tt> should be an <tt>url</tt>. In that case, if a <tt>body</tt>
is provided as a string, the function will perform a <tt>POST</tt> method is provided as a string, the function will perform a <tt>POST</tt> method
@ -155,7 +155,7 @@ in the <tt>url</tt>. Otherwise, it performs a <tt>GET</tt> in the
<tt>url</tt> <tt>url</tt>
</p> </p>
<p class=parameters> <p class="parameters">
If the first argument is instead a table, the most important fields are If the first argument is instead a table, the most important fields are
the <tt>url</tt> and the <em>simple</em> the <tt>url</tt> and the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
@ -169,27 +169,29 @@ function discards the downloaded data. The optional parameters are the
following: following:
</p> </p>
<ul> <ul>
<li><tt>method</tt>: The HTTP request method. Defaults to "GET"; <li><tt>method</tt>: The HTTP request method. Defaults to "GET";</li>
<li><tt>headers</tt>: Any additional HTTP headers to send with the request; <li><tt>headers</tt>: Any additional HTTP headers to send with the request;</li>
<li><tt>source</tt>: <em>simple</em> <li><tt>source</tt>: <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source to provide the request body. If there source to provide the request body. If there
is a body, you need to provide an appropriate "<tt>content-length</tt>" is a body, you need to provide an appropriate "<tt>content-length</tt>"
request header field, or the function will attempt to send the body as request header field, or the function will attempt to send the body as
"<tt>chunked</tt>" (something few servers support). Defaults to the empty source; "<tt>chunked</tt>" (something few servers support). Defaults to the empty source;</li>
<li><tt>step</tt>: <li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to move data. pump step function used to move data.
Defaults to the LTN12 <tt>pump.step</tt> function. Defaults to the LTN12 <tt>pump.step</tt> function.</li>
<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy; <li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;</li>
<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the <li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
function from automatically following 301 or 302 server redirect messages; function from automatically following 301 or 302 server redirect messages;</li>
<li><tt>create</tt>: An optional function to be used instead of <li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. <a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
<li><tt>maxredirects</tt>: An optional number specifying the maximum number of redirects to follow. Defaults to <tt>5</tt> if not specified. A boolean <tt>false</tt> value means no maximum (unlimited). <li><tt>maxredirects</tt>: An optional number specifying the maximum number of
redirects to follow. Defaults to <tt>5</tt> if not specified. A boolean
<tt>false</tt> value means no maximum (unlimited).</li>
</ul> </ul>
<p class=return> <p class="return">
In case of failure, the function returns <tt><b>nil</b></tt> followed by an In case of failure, the function returns <tt><b>nil</b></tt> followed by an
error message. If successful, the simple form returns the response error message. If successful, the simple form returns the response
body as a string, followed by the response status code, the response body as a string, followed by the response status code, the response
@ -198,7 +200,7 @@ information, except the first return value is just the number 1 (the body
goes to the <tt>sink</tt>). goes to the <tt>sink</tt>).
</p> </p>
<p class=return> <p class="return">
Even when the server fails to provide the contents of the requested URL (URL not found, for example), Even when the server fails to provide the contents of the requested URL (URL not found, for example),
it usually returns a message body (a web page informing the it usually returns a message body (a web page informing the
URL was not found or some other useless page). To make sure the URL was not found or some other useless page). To make sure the
@ -207,11 +209,11 @@ a list of the possible values and their meanings, refer to <a
href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>. href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p> </p>
<p class=description> <p class="description">
Here are a few examples with the simple interface: Here are a few examples with the simple interface:
</p> </p>
<pre class=example> <pre class="example">
-- load the http module -- load the http module
local io = require("io") local io = require("io")
local http = require("socket.http") local http = require("socket.http")
@ -237,11 +239,11 @@ r, e = http.request("http://wrong.host/")
-- r is nil, and e returns with value "host not found" -- r is nil, and e returns with value "host not found"
</pre> </pre>
<p class=description> <p class="description">
And here is an example using the generic interface: And here is an example using the generic interface:
</p> </p>
<pre class=example> <pre class="example">
-- load the http module -- load the http module
http = require("socket.http") http = require("socket.http")
@ -263,7 +265,7 @@ r, c, h = http.request {
-- } -- }
</pre> </pre>
<p class=note id="post"> <p class="note" id="post">
Note: When sending a POST request, simple interface adds a Note: When sending a POST request, simple interface adds a
"<tt>Content-type: application/x-www-form-urlencoded</tt>" "<tt>Content-type: application/x-www-form-urlencoded</tt>"
header to the request. This is the type used by header to the request. This is the type used by
@ -271,21 +273,21 @@ HTML forms. If you need another type, use the generic
interface. interface.
</p> </p>
<p class=note id="authentication"> <p class="note" id="authentication">
Note: Some URLs are protected by their Note: Some URLs are protected by their
servers from anonymous download. For those URLs, the server must receive servers from anonymous download. For those URLs, the server must receive
some sort of authentication along with the request or it will deny some sort of authentication along with the request or it will deny
download and return status "401&nbsp;Authentication Required". download and return status "401&nbsp;Authentication Required".
</p> </p>
<p class=note> <p class="note">
The HTTP/1.1 standard defines two authentication methods: the Basic The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both Authentication Scheme and the Digest Authentication Scheme, both
explained in detail in explained in detail in
<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>. <a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
</p> </p>
<p class=note>The Basic Authentication Scheme sends <p class="note">The Basic Authentication Scheme sends
<tt>&lt;user&gt;</tt> and <tt>&lt;user&gt;</tt> and
<tt>&lt;password&gt;</tt> unencrypted to the server and is therefore <tt>&lt;password&gt;</tt> unencrypted to the server and is therefore
considered unsafe. Unfortunately, by the time of this implementation, considered unsafe. Unfortunately, by the time of this implementation,
@ -294,7 +296,7 @@ Therefore, this is the method used by the toolkit whenever
authentication is required. authentication is required.
</p> </p>
<pre class=example> <pre class="example">
-- load required modules -- load required modules
http = require("socket.http") http = require("socket.http")
mime = require("mime") mime = require("mime")
@ -314,10 +316,10 @@ r, c = http.request {
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

138
docs/index.html Normal file
View File

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

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -13,17 +13,17 @@
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -36,7 +36,7 @@
<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=mime>MIME</h2> <h2 id="mime">MIME</h2>
<p> <p>
The <tt>mime</tt> namespace offers filters that apply and remove common The <tt>mime</tt> namespace offers filters that apply and remove common
@ -62,7 +62,7 @@ LTN012, Filters sources and sinks</a>.
To obtain the <tt>mime</tt> namespace, run: To obtain the <tt>mime</tt> namespace, run:
</p> </p>
<pre class=example> <pre class="example">
-- loads the MIME module and everything it requires -- loads the MIME module and everything it requires
local mime = require("mime") local mime = require("mime")
</pre> </pre>
@ -70,40 +70,40 @@ local mime = require("mime")
<!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=high>High-level filters</h3> <h3 id="high">High-level filters</h3>
<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="decode"> <p class="name" id="decode">
mime.<b>decode(</b>"base64"<b>)</b><br> mime.<b>decode(</b>"base64"<b>)</b><br>
mime.<b>decode(</b>"quoted-printable"<b>)</b> mime.<b>decode(</b>"quoted-printable"<b>)</b>
</p> </p>
<p class=description> <p class="description">
Returns a filter that decodes data from a given transfer content Returns a filter that decodes data from a given transfer content
encoding. encoding.
</p> </p>
<!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="encode"> <p class="name" id="encode">
mime.<b>encode(</b>"base64"<b>)</b><br> mime.<b>encode(</b>"base64"<b>)</b><br>
mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b> mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Returns a filter that encodes data according to a given transfer content Returns a filter that encodes data according to a given transfer content
encoding. encoding.
</p> </p>
<p class=parameters> <p class="parameters">
In the Quoted-Printable case, the user can specify whether the data is In the Quoted-Printable case, the user can specify whether the data is
textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or
"<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>". "<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>".
</p> </p>
<p class=note> <p class="note">
Although both transfer content encodings specify a limit for the line Although both transfer content encodings specify a limit for the line
length, the encoding filters do <em>not</em> break text into lines (for length, the encoding filters do <em>not</em> break text into lines (for
added flexibility). added flexibility).
@ -111,19 +111,19 @@ Below is a filter that converts binary data to the Base64 transfer content
encoding and breaks it into lines of the correct size. encoding and breaks it into lines of the correct size.
</p> </p>
<pre class=example> <pre class="example">
base64 = ltn12.filter.chain( base64 = ltn12.filter.chain(
mime.encode("base64"), mime.encode("base64"),
mime.wrap("base64") mime.wrap("base64")
) )
</pre> </pre>
<p class=note> <p class="note">
Note: Text data <em>has</em> to be converted to canonic form Note: Text data <em>has</em> to be converted to canonic form
<em>before</em> being encoded. <em>before</em> being encoded.
</p> </p>
<pre class=example> <pre class="example">
base64 = ltn12.filter.chain( base64 = ltn12.filter.chain(
mime.normalize(), mime.normalize(),
mime.encode("base64"), mime.encode("base64"),
@ -133,24 +133,24 @@ base64 = ltn12.filter.chain(
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="normalize"> <p class="name" id="normalize">
mime.<b>normalize(</b>[marker]<b>)</b> mime.<b>normalize(</b>[marker]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Converts most common end-of-line markers to a specific given marker. Converts most common end-of-line markers to a specific given marker.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic <tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
end-of-line marker defined by the MIME standard. end-of-line marker defined by the MIME standard.
</p> </p>
<p class=return> <p class="return">
The function returns a filter that performs the conversion. The function returns a filter that performs the conversion.
</p> </p>
<p class=note> <p class="note">
Note: There is no perfect solution to this problem. Different end-of-line Note: There is no perfect solution to this problem. Different end-of-line
markers are an evil that will probably plague developers forever. markers are an evil that will probably plague developers forever.
This function, however, will work perfectly for text created with any of This function, however, will work perfectly for text created with any of
@ -162,33 +162,33 @@ guarantee that the number of empty lines will be correct.
<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="stuff"> <p class="name" id="stuff">
mime.<b>stuff()</b><br> mime.<b>stuff()</b><br>
</p> </p>
<p class=description> <p class="description">
Creates and returns a filter that performs stuffing of SMTP messages. Creates and returns a filter that performs stuffing of SMTP messages.
</p> </p>
<p class=note> <p class="note">
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to chain it with your uses this filter automatically. You don't need to chain it with your
source, or apply it to your message body. source, or apply it to your message body.
</p> </p>
<!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrap"> <p class="name" id="wrap">
mime.<b>wrap(</b>"text" [, length]<b>)</b><br> mime.<b>wrap(</b>"text" [, length]<b>)</b><br>
mime.<b>wrap(</b>"base64"<b>)</b><br> mime.<b>wrap(</b>"base64"<b>)</b><br>
mime.<b>wrap(</b>"quoted-printable"<b>)</b> mime.<b>wrap(</b>"quoted-printable"<b>)</b>
</p> </p>
<p class=description> <p class="description">
Returns a filter that breaks data into lines. Returns a filter that breaks data into lines.
</p> </p>
<p class=parameters> <p class="parameters">
The "<tt>text</tt>" line-wrap filter simply breaks text into lines by The "<tt>text</tt>" line-wrap filter simply breaks text into lines by
inserting CRLF end-of-line markers at appropriate positions. inserting CRLF end-of-line markers at appropriate positions.
<tt>Length</tt> defaults 76. <tt>Length</tt> defaults 76.
@ -199,11 +199,11 @@ not to break lines in the middle of an escaped character. In that case, the
line length is fixed at 76. line length is fixed at 76.
</p> </p>
<p class=note> <p class="note">
For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following: For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following:
</p> </p>
<pre class=example> <pre class="example">
qp = ltn12.filter.chain( qp = ltn12.filter.chain(
mime.normalize(), mime.normalize(),
mime.encode("quoted-printable"), mime.encode("quoted-printable"),
@ -211,26 +211,26 @@ qp = ltn12.filter.chain(
) )
</pre> </pre>
<p class=note> <p class="note">
Note: To break into lines with a different end-of-line convention, apply Note: To break into lines with a different end-of-line convention, apply
a normalization filter after the line break filter. a normalization filter after the line break filter.
</p> </p>
<!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=low>Low-level filters</h3> <h3 id="low">Low-level filters</h3>
<!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="b64"> <p class="name" id="b64">
A, B = mime.<b>b64(</b>C [, D]<b>)</b> A, B = mime.<b>b64(</b>C [, D]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to perform Base64 encoding. Low-level filter to perform Base64 encoding.
</p> </p>
<p class=description> <p class="description">
<tt>A</tt> is the encoded version of the largest prefix of <tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt> <tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
@ -239,56 +239,56 @@ If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>. the encoding of the remaining bytes of <tt>C</tt>.
</p> </p>
<p class=note> <p class="note">
Note: The simplest use of this function is to encode a string into it's Note: The simplest use of this function is to encode a string into it's
Base64 transfer content encoding. Notice the extra parenthesis around the Base64 transfer content encoding. Notice the extra parenthesis around the
call to <tt>mime.b64</tt>, to discard the second return value. call to <tt>mime.b64</tt>, to discard the second return value.
</p> </p>
<pre class=example> <pre class="example">
print((mime.b64("diego:password"))) print((mime.b64("diego:password")))
--&gt; ZGllZ286cGFzc3dvcmQ= --&gt; ZGllZ286cGFzc3dvcmQ=
</pre> </pre>
<!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dot"> <p class="name" id="dot">
A, n = mime.<b>dot(</b>m [, B]<b>)</b> A, n = mime.<b>dot(</b>m [, B]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to perform SMTP stuffing and enable transmission of Low-level filter to perform SMTP stuffing and enable transmission of
messages containing the sequence "CRLF.CRLF". messages containing the sequence "CRLF.CRLF".
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the <tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the
number of characters from the sequence CRLF seen in the end of <tt>B</tt>. number of characters from the sequence CRLF seen in the end of <tt>B</tt>.
'<tt>m</tt>' should tell the same, but for the previous chunk. '<tt>m</tt>' should tell the same, but for the previous chunk.
</p> </p>
<p class=note>Note: The message body is defined to begin with <p class="note">Note: The message body is defined to begin with
an implicit CRLF. Therefore, to stuff a message correctly, the an implicit CRLF. Therefore, to stuff a message correctly, the
first <tt>m</tt> should have the value 2. first <tt>m</tt> should have the value 2.
</p> </p>
<pre class=example> <pre class="example">
print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n"))) print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n")))
--&gt; ..\nStuffing the message.\n..\n.. --&gt; ..\nStuffing the message.\n..\n..
</pre> </pre>
<p class=note> <p class="note">
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function Note: The <a href="smtp.html#send"><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to uses this filter automatically. You don't need to
apply it again. apply it again.
</p> </p>
<!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="eol"> <p class="name" id="eol">
A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b> A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to perform end-of-line marker translation. Low-level filter to perform end-of-line marker translation.
For each chunk, the function needs to know if the last character of the For each chunk, the function needs to know if the last character of the
previous chunk could be part of an end-of-line marker or not. This is the previous chunk could be part of an end-of-line marker or not. This is the
@ -296,7 +296,7 @@ context the function receives besides the chunk. An updated version of
the context is returned after each new chunk. the context is returned after each new chunk.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the <tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the
ASCII value of the last character of the previous chunk, if it was a ASCII value of the last character of the previous chunk, if it was a
candidate for line break, or 0 otherwise. candidate for line break, or 0 otherwise.
@ -304,22 +304,22 @@ candidate for line break, or 0 otherwise.
chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF. chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF.
</p> </p>
<pre class=example> <pre class="example">
-- translates the end-of-line marker to UNIX -- translates the end-of-line marker to UNIX
unix = mime.eol(0, dos, "\n") unix = mime.eol(0, dos, "\n")
</pre> </pre>
<!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qp"> <p class="name" id="qp">
A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b> A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to perform Quoted-Printable encoding. Low-level filter to perform Quoted-Printable encoding.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is the encoded version of the largest prefix of <tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt> <tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
@ -330,28 +330,28 @@ Throughout encoding, occurrences of CRLF are replaced by the
<tt>marker</tt>, which itself defaults to CRLF. <tt>marker</tt>, which itself defaults to CRLF.
</p> </p>
<p class=note> <p class="note">
Note: The simplest use of this function is to encode a string into it's Note: The simplest use of this function is to encode a string into it's
Quoted-Printable transfer content encoding. Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value. Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value.
</p> </p>
<pre class=example> <pre class="example">
print((mime.qp("maçã"))) print((mime.qp("ma<EFBFBD><EFBFBD>")))
--&gt; ma=E7=E3= --&gt; ma=E7=E3=
</pre> </pre>
<!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qpwrp"> <p class="name" id="qpwrp">
A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b> A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to break Quoted-Printable text into lines. Low-level filter to break Quoted-Printable text into lines.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most <tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76). <tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first '<tt>n</tt>' should tell how many bytes are left for the first
@ -359,7 +359,7 @@ line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>. left in the last line of <tt>A</tt>.
</p> </p>
<p class=note> <p class="note">
Note: Besides breaking text into lines, this function makes sure the line Note: Besides breaking text into lines, this function makes sure the line
breaks don't fall in the middle of an escaped character combination. Also, breaks don't fall in the middle of an escaped character combination. Also,
this function only breaks lines that are bigger than <tt>length</tt> bytes. this function only breaks lines that are bigger than <tt>length</tt> bytes.
@ -367,15 +367,15 @@ this function only breaks lines that are bigger than <tt>length</tt> bytes.
<!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unb64"> <p class="name" id="unb64">
A, B = mime.<b>unb64(</b>C [, D]<b>)</b> A, B = mime.<b>unb64(</b>C [, D]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to perform Base64 decoding. Low-level filter to perform Base64 decoding.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is the decoded version of the largest prefix of <tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt> <tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
@ -384,29 +384,29 @@ If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is the empty string
and <tt>B</tt> returns whatever couldn't be decoded. and <tt>B</tt> returns whatever couldn't be decoded.
</p> </p>
<p class=note> <p class="note">
Note: The simplest use of this function is to decode a string from it's Note: The simplest use of this function is to decode a string from it's
Base64 transfer content encoding. Base64 transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value. Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p> </p>
<pre class=example> <pre class="example">
print((mime.unb64("ZGllZ286cGFzc3dvcmQ="))) print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
--&gt; diego:password --&gt; diego:password
</pre> </pre>
<!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unqp"> <p class="name" id="unqp">
A, B = mime.<b>unqp(</b>C [, D]<b>)</b> A, B = mime.<b>unqp(</b>C [, D]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to remove the Quoted-Printable transfer content encoding Low-level filter to remove the Quoted-Printable transfer content encoding
from data. from data.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is the decoded version of the largest prefix of <tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt> <tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
@ -415,29 +415,29 @@ If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with
the encoding of the remaining bytes of <tt>C</tt>. the encoding of the remaining bytes of <tt>C</tt>.
</p> </p>
<p class=note> <p class="note">
Note: The simplest use of this function is to decode a string from it's Note: The simplest use of this function is to decode a string from it's
Quoted-Printable transfer content encoding. Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value. Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p> </p>
<pre class=example> <pre class="example">
print((mime.qp("ma=E7=E3="))) print((mime.qp("ma=E7=E3=")))
--&gt; maçã --&gt; ma<EFBFBD><EFBFBD>
</pre> </pre>
<!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrp"> <p class="name" id="wrp">
A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b> A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Low-level filter to break text into lines with CRLF marker. Low-level filter to break text into lines with CRLF marker.
Text is assumed to be in the <a href=#normalize><tt>normalize</tt></a> form. Text is assumed to be in the <a href="#normalize"><tt>normalize</tt></a> form.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most <tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76). <tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first '<tt>n</tt>' should tell how many bytes are left for the first
@ -445,7 +445,7 @@ line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>. left in the last line of <tt>A</tt>.
</p> </p>
<p class=note> <p class="note">
Note: This function only breaks lines that are bigger than Note: This function only breaks lines that are bigger than
<tt>length</tt> bytes. The resulting line length does not include the CRLF <tt>length</tt> bytes. The resulting line length does not include the CRLF
marker. marker.
@ -454,10 +454,10 @@ marker.
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -14,17 +14,17 @@ Support, Manual">
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -238,10 +238,10 @@ Support, Manual">
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -14,17 +14,17 @@ Library, Support">
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -37,7 +37,7 @@ Library, Support">
<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=smtp>SMTP</h2> <h2 id="smtp">SMTP</h2>
<p> The <tt>smtp</tt> namespace provides functionality to send e-mail <p> The <tt>smtp</tt> namespace provides functionality to send e-mail
messages. The high-level API consists of two functions: one to messages. The high-level API consists of two functions: one to
@ -54,11 +54,11 @@ href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
which governs the Internet Message Format. which governs the Internet Message Format.
Multipart messages (those that contain attachments) are part Multipart messages (those that contain attachments) are part
of the MIME standard, but described mainly of the MIME standard, but described mainly
in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a> in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>.</p>
<p> In the description below, good understanding of <a <p> In the description below, good understanding of <a
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
sources and sinks</a> and the <a href=mime.html>MIME</a> module is sources and sinks</a> and the <a href="mime.html">MIME</a> module is
assumed. In fact, the SMTP module was the main reason for their assumed. In fact, the SMTP module was the main reason for their
creation. </p> creation. </p>
@ -66,7 +66,7 @@ creation. </p>
To obtain the <tt>smtp</tt> namespace, run: To obtain the <tt>smtp</tt> namespace, run:
</p> </p>
<pre class=example> <pre class="example">
-- loads the SMTP module and everything it requires -- loads the SMTP module and everything it requires
local smtp = require("socket.smtp") local smtp = require("socket.smtp")
</pre> </pre>
@ -92,11 +92,11 @@ headers = {<br>
<p> <p>
Field names are case insensitive (as specified by the standard) and all Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>). <a href="socket.html#headers.canonic"><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified. Field values are left unmodified.
</p> </p>
<p class=note> <p class="note">
Note: MIME headers are independent of order. Therefore, there is no problem Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table. in representing them in a Lua table.
</p> </p>
@ -107,25 +107,25 @@ the SMTP module:
</p> </p>
<ul> <ul>
<li> <tt>DOMAIN</tt>: domain used to greet the server; <li> <tt>DOMAIN</tt>: domain used to greet the server;</li>
<li> <tt>PORT</tt>: default port used for the connection; <li> <tt>PORT</tt>: default port used for the connection;</li>
<li> <tt>SERVER</tt>: default server used for the connection; <li> <tt>SERVER</tt>: default server used for the connection;</li>
<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations; <li> <tt>TIMEOUT</tt>: default timeout for all I/O operations;</li>
<li> <tt>ZONE</tt>: default time zone. <li> <tt>ZONE</tt>: default time zone.</li>
</ul> </ul>
<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=message> <p class="name" id="message">
smtp.<b>message(</b>mesgt<b>)</b> smtp.<b>message(</b>mesgt<b>)</b>
</p> </p>
<p class=description> <p class="description">
Returns a <em>simple</em> Returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep). <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
</p> </p>
<p class=parameters> <p class="parameters">
The only parameter of the function is a table describing the message. The only parameter of the function is a table describing the message.
<tt>Mesgt</tt> has the following form (notice the recursive structure): <tt>Mesgt</tt> has the following form (notice the recursive structure):
</p> </p>
@ -151,7 +151,7 @@ multipart-mesgt = {<br>
</table> </table>
</blockquote> </blockquote>
<p class=parameters> <p class="parameters">
For a simple message, all that is needed is a set of <tt>headers</tt> For a simple message, all that is needed is a set of <tt>headers</tt>
and the <tt>body</tt>. The message <tt>body</tt> can be given as a string and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
or as a <em>simple</em> or as a <em>simple</em>
@ -161,7 +161,7 @@ recursively defines each part as an independent message, plus an optional
<tt>preamble</tt> and <tt>epilogue</tt>. <tt>preamble</tt> and <tt>epilogue</tt>.
</p> </p>
<p class=return> <p class="return">
The function returns a <em>simple</em> The function returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that produces the source that produces the
@ -170,7 +170,7 @@ Hopefully, the following
example will make things clear. When in doubt, refer to the appropriate RFC example will make things clear. When in doubt, refer to the appropriate RFC
as listed in the introduction. </p> as listed in the introduction. </p>
<pre class=example> <pre class="example">
-- load the smtp support and its friends -- load the smtp support and its friends
local smtp = require("socket.smtp") local smtp = require("socket.smtp")
local mime = require("mime") local mime = require("mime")
@ -234,7 +234,7 @@ r, e = smtp.send{
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send> <p class="name" id="send">
smtp.<b>send{</b><br> smtp.<b>send{</b><br>
&nbsp;&nbsp;from = <i>string</i>,<br> &nbsp;&nbsp;from = <i>string</i>,<br>
&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br> &nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br>
@ -249,16 +249,16 @@ smtp.<b>send{</b><br>
<b>}</b> <b>}</b>
</p> </p>
<p class=description> <p class="description">
Sends a message to a recipient list. Since sending messages is not as Sends a message to a recipient list. Since sending messages is not as
simple as downloading an URL from a FTP or HTTP server, this function simple as downloading an URL from a FTP or HTTP server, this function
doesn't have a simple interface. However, see the doesn't have a simple interface. However, see the
<a href=#message><tt>message</tt></a> source factory for <a href="#message"><tt>message</tt></a> source factory for
a very powerful way to define the message contents. a very powerful way to define the message contents.
</p> </p>
<p class=parameters> <p class="parameters">
The sender is given by the e-mail address in the <tt>from</tt> field. The sender is given by the e-mail address in the <tt>from</tt> field.
<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail <tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
address, or a string address, or a string
@ -270,32 +270,32 @@ The contents of the message are given by a <em>simple</em>
<ul> <ul>
<li> <tt>user</tt>, <tt>password</tt>: User and password for <li> <tt>user</tt>, <tt>password</tt>: User and password for
authentication. The function will attempt LOGIN and PLAIN authentication authentication. The function will attempt LOGIN and PLAIN authentication
methods if supported by the server (both are unsafe); methods if supported by the server (both are unsafe);</li>
<li> <tt>server</tt>: Server to connect to. Defaults to "localhost"; <li> <tt>server</tt>: Server to connect to. Defaults to "localhost";</li>
<li> <tt>port</tt>: Port to connect to. Defaults to 25; <li> <tt>port</tt>: Port to connect to. Defaults to 25;</li>
<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the <li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
local machine host name; local machine host name;</li>
<li> <tt>step</tt>: <li> <tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the pump step function used to pass data from the
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function; source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;</li>
<li><tt>create</tt>: An optional function to be used instead of <li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created. <a href="tcp.html#socket.tcp"><tt>socket.tcp</tt></a> when the communications socket is created.</li>
</ul> </ul>
<p class=return> <p class="return">
If successful, the function returns 1. Otherwise, the function returns If successful, the function returns 1. Otherwise, the function returns
<b><tt>nil</tt></b> followed by an error message. <b><tt>nil</tt></b> followed by an error message.
</p> </p>
<p class=note> <p class="note">
Note: SMTP servers can be very picky with the format of e-mail Note: SMTP servers can be very picky with the format of e-mail
addresses. To be safe, use only addresses of the form addresses. To be safe, use only addresses of the form
"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and "<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and
<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail <tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
addresses can take whatever form you like. </p> addresses can take whatever form you like. </p>
<p class=note> <p class="note">
Big note: There is a good deal of misconception with the use of the Big note: There is a good deal of misconception with the use of the
destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>', destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
@ -303,7 +303,7 @@ and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
exact opposite of what you expect. exact opposite of what you expect.
</p> </p>
<p class=note> <p class="note">
Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
message. Each recipient of an SMTP mail message receives a copy of the message. Each recipient of an SMTP mail message receives a copy of the
message body along with the headers, and nothing more. The headers message body along with the headers, and nothing more. The headers
@ -313,7 +313,7 @@ message body along with the headers, and nothing more. The headers
part of the message and will not be sent to anyone. part of the message and will not be sent to anyone.
</p> </p>
<p class=note> <p class="note">
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a> <a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper fields" and "5. Security considerations", explaining the proper
@ -322,16 +322,17 @@ use of these headers. Here is a summary of what it says:
<ul> <ul>
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s) <li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
of the message; of the message;</li>
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of <li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
making a copy on a typewriter using carbon paper) contains the making a copy on a typewriter using carbon paper) contains the
addresses of others who are to receive the message, though the addresses of others who are to receive the message, though the
content of the message may not be directed at them; content of the message may not be directed at them;</li>
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon <li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message. Copy") contains addresses of recipients of the message whose addresses are not
to be revealed to other recipients of the message.</li>
</ul> </ul>
<p class=note> <p class="note">
The LuaSocket <tt>send</tt> function does not care or interpret the The LuaSocket <tt>send</tt> function does not care or interpret the
headers you send, but it gives you full control over what is sent and headers you send, but it gives you full control over what is sent and
to whom it is sent: to whom it is sent:
@ -339,27 +340,27 @@ to whom it is sent:
<ul> <ul>
<li> If someone is to receive the message, the e-mail address <em>has</em> <li> If someone is to receive the message, the e-mail address <em>has</em>
to be in the recipient list. This is the only parameter that controls who to be in the recipient list. This is the only parameter that controls who
gets a copy of the message; gets a copy of the message;</li>
<li> If there are multiple recipients, none of them will automatically <li> If there are multiple recipients, none of them will automatically
know that someone else got that message. That is, the default behavior is know that someone else got that message. That is, the default behavior is
similar to the <tt>Bcc</tt> field of popular e-mail clients; similar to the <tt>Bcc</tt> field of popular e-mail clients;</li>
<li> It is up to you to add the <tt>To</tt> header with the list of primary <li> It is up to you to add the <tt>To</tt> header with the list of primary
recipients so that other recipients can see it; recipients so that other recipients can see it;</li>
<li> It is also up to you to add the <tt>Cc</tt> header with the <li> It is also up to you to add the <tt>Cc</tt> header with the
list of additional recipients so that everyone else sees it; list of additional recipients so that everyone else sees it;</li>
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is <li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
empty. Otherwise, everyone receiving the message will see it and that is empty. Otherwise, everyone receiving the message will see it and that is
exactly what you <em>don't</em> want to happen! exactly what you <em>don't</em> want to happen!</li>
</ul> </ul>
<p class=note> <p class="note">
I hope this clarifies the issue. Otherwise, please refer to I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a> <a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
and and
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>. <a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
</p> </p>
<pre class=example> <pre class="example">
-- load the smtp support -- load the smtp support
local smtp = require("socket.smtp") local smtp = require("socket.smtp")
@ -395,10 +396,10 @@ r, e = smtp.send{
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -13,17 +13,17 @@
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="https://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -36,7 +36,7 @@
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=socket>The socket namespace</h2> <h2 id="socket">The socket namespace</h2>
<p> <p>
The <tt>socket</tt> namespace contains the core functionality of LuaSocket. The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
@ -46,14 +46,14 @@ The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
To obtain the <tt>socket</tt> namespace, run: To obtain the <tt>socket</tt> namespace, run:
</p> </p>
<pre class=example> <pre class="example">
-- loads the socket module -- loads the socket module
local socket = require("socket") local socket = require("socket")
</pre> </pre>
<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="headers.canonic"> <p class="name" id="headers.canonic">
socket.headers.<b>canonic</b></p> socket.headers.<b>canonic</b></p>
<p> The <tt>socket.headers.canonic</tt> table <p> The <tt>socket.headers.canonic</tt> table
@ -69,7 +69,7 @@ You can obtain the <tt>headers</tt> namespace if case run-time
modifications are required by running: modifications are required by running:
</p> </p>
<pre class=example> <pre class="example">
-- loads the headers module -- loads the headers module
local headers = require("headers") local headers = require("headers")
</pre> </pre>
@ -77,30 +77,30 @@ local headers = require("headers")
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind> <p class="name" id="bind">
socket.<b>bind(</b>address, port [, backlog]<b>)</b> socket.<b>bind(</b>address, port [, backlog]<b>)</b>
</p> </p>
<p class=description> <p class="description">
This function is a shortcut that creates and returns a TCP server object This function is a shortcut that creates and returns a TCP server object
bound to a local <tt>address</tt> and <tt>port</tt>, ready to bound to a local <tt>address</tt> and <tt>port</tt>, ready to
accept client connections. Optionally, accept client connections. Optionally,
user can also specify the <tt>backlog</tt> argument to the user can also specify the <tt>backlog</tt> argument to the
<a href=tcp.html#listen><tt>listen</tt></a> method (defaults to 32). <a href="tcp.html#listen"><tt>listen</tt></a> method (defaults to 32).
</p> </p>
<p class=note> <p class="note">
Note: The server object returned will have the option "<tt>reuseaddr</tt>" Note: The server object returned will have the option "<tt>reuseaddr</tt>"
set to <tt><b>true</b></tt>. set to <tt><b>true</b></tt>.
</p> </p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect> <p class="name" id="connect">
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b> socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p> </p>
<p class=description> <p class="description">
This function is a shortcut that creates and returns a TCP client object This function is a shortcut that creates and returns a TCP client object
connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally, connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
the user can also specify the local address and port to bind the user can also specify the local address and port to bind
@ -114,40 +114,40 @@ of connect are defined as simple helper functions that restrict the
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug> <p class="name" id="debug">
socket.<b>_DEBUG</b> socket.<b>_DEBUG</b>
</p> </p>
<p class=description> <p class="description">
This constant is set to <tt><b>true</b></tt> if the library was compiled This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support. with debug support.
</p> </p>
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug> <p class="name" id="datagramsize">
socket.<b>_DATAGRAMSIZE</b> socket.<b>_DATAGRAMSIZE</b>
</p> </p>
<p class=description> <p class="description">
Default datagram size used by calls to Default datagram size used by calls to
<a href="udp.html#receive"<tt>receive</tt></a> and <a href="udp.html#receive"><tt>receive</tt></a> and
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>. <a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
(Unless changed in compile time, the value is 8192.) (Unless changed in compile time, the value is 8192.)
</p> </p>
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime> <p class="name" id="gettime">
socket.<b>gettime()</b> socket.<b>gettime()</b>
</p> </p>
<p class=description> <p class="description">
Returns the UNIX time in seconds. You should subtract the values returned by this function Returns the UNIX time in seconds. You should subtract the values returned by this function
to get meaningful values. to get meaningful values.
</p> </p>
<pre class=example> <pre class="example">
t = socket.gettime() t = socket.gettime()
-- do stuff -- do stuff
print(socket.gettime() - t .. " seconds elapsed") print(socket.gettime() - t .. " seconds elapsed")
@ -155,32 +155,32 @@ print(socket.gettime() - t .. " seconds elapsed")
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry> <p class="name" id="newtry">
socket.<b>newtry(</b>finalizer<b>)</b> socket.<b>newtry(</b>finalizer<b>)</b>
</p> </p>
<p class=description> <p class="description">
Creates and returns a <em>clean</em> Creates and returns a <em>clean</em>
<a href="#try"><tt>try</tt></a> <a href="#try"><tt>try</tt></a>
function that allows for cleanup before the exception function that allows for cleanup before the exception
is raised. is raised.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Finalizer</tt> is a function that will be called before <tt>Finalizer</tt> is a function that will be called before
<tt>try</tt> throws the exception. <tt>try</tt> throws the exception.
</p> </p>
<p class=return> <p class="return">
The function returns your customized <tt>try</tt> function. The function returns your customized <tt>try</tt> function.
</p> </p>
<p class=note> <p class="note">
Note: This idea saved a <em>lot</em> of work with the Note: This idea saved a <em>lot</em> of work with the
implementation of protocols in LuaSocket: implementation of protocols in LuaSocket:
</p> </p>
<pre class=example> <pre class="example">
foo = socket.protect(function() foo = socket.protect(function()
-- connect somewhere -- connect somewhere
local c = socket.try(socket.connect("somewhere", 42)) local c = socket.try(socket.connect("somewhere", 42))
@ -198,40 +198,40 @@ end)
<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=protect> <p class="name" id="protect">
socket.<b>protect(</b>func<b>)</b> socket.<b>protect(</b>func<b>)</b>
</p> </p>
<p class=description> <p class="description">
Converts a function that throws exceptions into a safe function. This Converts a function that throws exceptions into a safe function. This
function only catches exceptions thrown by the <a href=#try><tt>try</tt></a> function only catches exceptions thrown by the <a href="#try"><tt>try</tt></a>
and <a href=#newtry><tt>newtry</tt></a> functions. It does not catch normal and <a href="#newtry"><tt>newtry</tt></a> functions. It does not catch normal
Lua errors. Lua errors.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Func</tt> is a function that calls <tt>Func</tt> is a function that calls
<a href=#try><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>) <a href="#try"><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>)
to throw exceptions. to throw exceptions.
</p> </p>
<p class=return> <p class="return">
Returns an equivalent function that instead of throwing exceptions in case of Returns an equivalent function that instead of throwing exceptions in case of
a failed <a href=#try><tt>try</tt></a> call, returns <tt><b>nil</b></tt> a failed <a href="#try"><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
followed by an error message. followed by an error message.
</p> </p>
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=select> <p class="name" id="select">
socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b> socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Waits for a number of sockets to change status. Waits for a number of sockets to change status.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Recvt</tt> is an array with the sockets to test for characters <tt>Recvt</tt> is an array with the sockets to test for characters
available for reading. Sockets in the <tt>sendt</tt> array are watched to available for reading. Sockets in the <tt>sendt</tt> array are watched to
see if it is OK to immediately write on them. <tt>Timeout</tt> is the see if it is OK to immediately write on them. <tt>Timeout</tt> is the
@ -242,7 +242,7 @@ be empty tables or <tt><b>nil</b></tt>. Non-socket values (or values with
non-numeric indices) in the arrays will be silently ignored. non-numeric indices) in the arrays will be silently ignored.
</p> </p>
<p class=return> The function returns a list with the sockets ready for <p class="return"> The function returns a list with the sockets ready for
reading, a list with the sockets ready for writing and an error message. reading, a list with the sockets ready for writing and an error message.
The error message is "<tt>timeout</tt>" if a timeout The error message is "<tt>timeout</tt>" if a timeout
condition was met, "<tt>select failed</tt>" if the call condition was met, "<tt>select failed</tt>" if the call
@ -253,213 +253,215 @@ themselves, to simplify the test if a specific socket has
changed status. changed status.
</p> </p>
<p class=note> <p class="note">
<b>Note:</b> <tt>select</tt> can monitor a limited number <b>Note:</b> <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This of sockets, as defined by the constant <a href="#setsize">
<tt>socket._SETSIZE</tt></a>. This
number may be as high as 1024 or as low as 64 by default, number may be as high as 1024 or as low as 64 by default,
depending on the system. It is usually possible to change this depending on the system. It is usually possible to change this
at compile time. Invoking <tt>select</tt> with a larger at compile time. Invoking <tt>select</tt> with a larger
number of sockets will raise an error. number of sockets will raise an error.
</p> </p>
<p class=note> <p class="note">
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail <b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
on non-blocking TCP sockets. The function may return a socket as on non-blocking TCP sockets. The function may return a socket as
writable even though the socket is <em>not</em> ready for sending. writable even though the socket is <em>not</em> ready for sending.
</p> </p>
<p class=note> <p class="note">
<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee <b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee
<a href=tcp.html#accept><tt>accept</tt></a> will return immediately. <a href="tcp.html#accept"><tt>accept</tt></a> will return immediately.
Use the <a href=tcp.html#settimeout><tt>settimeout</tt></a> Use the <a href="tcp.html#settimeout"><tt>settimeout</tt></a>
method or <tt>accept</tt> might block forever. method or <tt>accept</tt> might block forever.
</p> </p>
<p class=note> <p class="note">
<b>Yet another note</b>: If you close a socket and pass <b>Yet another note</b>: If you close a socket and pass
it to <tt>select</tt>, it will be ignored. it to <tt>select</tt>, it will be ignored.
</p> </p>
<p class=note> <p class="note">
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop. <b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
</p> </p>
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setsize> <p class="name" id="setsize">
socket.<b>_SETSIZE</b> socket.<b>_SETSIZE</b>
</p> </p>
<p class=description> <p class="description">
The maximum number of sockets that the <a The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle. href="#select"><tt>select</tt></a> function can handle.
</p> </p>
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink> <p class="name" id="sink">
socket.<b>sink(</b>mode, socket<b>)</b> socket.<b>sink(</b>mode, socket<b>)</b>
</p> </p>
<p class=description> <p class="description">
Creates an Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink from a stream socket object. sink from a stream socket object.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Mode</tt> defines the behavior of the sink. The following <tt>Mode</tt> defines the behavior of the sink. The following
options are available: options are available:
</p> </p>
<ul> <ul>
<li> <tt>"http-chunked"</tt>: sends data through socket after applying the <li> <tt>"http-chunked"</tt>: sends data through socket after applying the
<em>chunked transfer coding</em>, closing the socket when done; <em>chunked transfer coding</em>, closing the socket when done;</li>
<li> <tt>"close-when-done"</tt>: sends all received data through the <li> <tt>"close-when-done"</tt>: sends all received data through the
socket, closing the socket when done; socket, closing the socket when done;</li>
<li> <tt>"keep-open"</tt>: sends all received data through the <li> <tt>"keep-open"</tt>: sends all received data through the
socket, leaving it open when done. socket, leaving it open when done.</li>
</ul> </ul>
<p> <p>
<tt>Socket</tt> is the stream socket object used to send the data. <tt>Socket</tt> is the stream socket object used to send the data.
</p> </p>
<p class=return> <p class="return">
The function returns a sink with the appropriate behavior. The function returns a sink with the appropriate behavior.
</p> </p>
<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=skip> <p class="name" id="skip">
socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b> socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Drops a number of arguments and returns the remaining. Drops a number of arguments and returns the remaining.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to <tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to
<tt>ret<sub>N</sub></tt> are the arguments. <tt>ret<sub>N</sub></tt> are the arguments.
</p> </p>
<p class=return> <p class="return">
The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>. The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
</p> </p>
<p class=note> <p class="note">
Note: This function is useful to avoid creation of dummy variables: Note: This function is useful to avoid creation of dummy variables:
</p> </p>
<pre class=example> <pre class="example">
-- get the status code and separator from SMTP server reply -- get the status code and separator from SMTP server reply
local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
</pre> </pre>
<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sleep> <p class="name" id="sleep">
socket.<b>sleep(</b>time<b>)</b> socket.<b>sleep(</b>time<b>)</b>
</p> </p>
<p class=description> <p class="description">
Freezes the program execution during a given amount of time. Freezes the program execution during a given amount of time.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Time</tt> is the number of seconds to sleep for. If <tt>Time</tt> is the number of seconds to sleep for. If
<tt>time</tt> is negative, the function returns immediately. <tt>time</tt> is negative, the function returns immediately.
</p> </p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=source> <p class="name" id="source">
socket.<b>source(</b>mode, socket [, length]<b>)</b> socket.<b>source(</b>mode, socket [, length]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Creates an Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> <a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source from a stream socket object. source from a stream socket object.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Mode</tt> defines the behavior of the source. The following <tt>Mode</tt> defines the behavior of the source. The following
options are available: options are available:
</p> </p>
<ul> <ul>
<li> <tt>"http-chunked"</tt>: receives data from socket and removes the <li> <tt>"http-chunked"</tt>: receives data from socket and removes the
<em>chunked transfer coding</em> before returning the data; <em>chunked transfer coding</em> before returning the data;</li>
<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the <li> <tt>"by-length"</tt>: receives a fixed number of bytes from the
socket. This mode requires the extra argument <tt>length</tt>; socket. This mode requires the extra argument <tt>length</tt>;</li>
<li> <tt>"until-closed"</tt>: receives data from a socket until the other <li> <tt>"until-closed"</tt>: receives data from a socket until the other
side closes the connection. side closes the connection.</li>
</ul> </ul>
<p> <p>
<tt>Socket</tt> is the stream socket object used to receive the data. <tt>Socket</tt> is the stream socket object used to receive the data.
</p> </p>
<p class=return> <p class="return">
The function returns a source with the appropriate behavior. The function returns a source with the appropriate behavior.
</p> </p>
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socketinvalid> <p class="name" id="socketinvalid">
socket.<b>_SOCKETINVALID</b> socket.<b>_SOCKETINVALID</b>
</p> </p>
<p class=description> <p class="description">
The OS value for an invalid socket. The OS value for an invalid socket. This can be used with <a href="tcp.html#getfd">
<tt>tcp:getfd</tt></a> and <a href="tcp.html#setfd"><tt>tcp:setfd</tt></a> methods.
</p> </p>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try> <p class="name" id="try">
socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b> socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught <tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
by a <a href=#protect><tt>protect</tt></a>ed function only. by a <a href="#protect"><tt>protect</tt></a>ed function only.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary <tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary
arguments, but are usually the return values of a function call arguments, but are usually the return values of a function call
nested with <tt>try</tt>. nested with <tt>try</tt>.
</p> </p>
<p class=return> <p class="return">
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>. <tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
in a table with metatable used by <a href=#protect><tt>protect</tt></a> to in a table with metatable used by <a href="#protect"><tt>protect</tt></a> to
distinguish exceptions from runtime errors. distinguish exceptions from runtime errors.
</p> </p>
<pre class=example> <pre class="example">
-- connects or throws an exception with the appropriate error message -- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect("localhost", 80)) c = socket.try(socket.connect("localhost", 80))
</pre> </pre>
<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=version> <p class="name" id="version">
socket.<b>_VERSION</b> socket.<b>_VERSION</b>
</p> </p>
<p class=description> <p class="description">
This constant has a string describing the current LuaSocket version. This constant has a string describing the current LuaSocket version.
</p> </p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -13,17 +13,17 @@
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -40,42 +40,43 @@
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="accept"> <p class="name" id="accept">
server:<b>accept()</b> server:<b>accept()</b>
</p> </p>
<p class=description> <p class="description">
Waits for a remote connection on the server Waits for a remote connection on the server
object and returns a client object representing that connection. object and returns a client object representing that connection.
</p> </p>
<p class=return> <p class="return">
If a connection is successfully initiated, a client object is returned. If a connection is successfully initiated, a client object is returned.
If a timeout condition is met, the method returns <b><tt>nil</tt></b> If a timeout condition is met, the method returns <b><tt>nil</tt></b>
followed by the error string '<tt>timeout</tt>'. Other errors are followed by the error string '<tt>timeout</tt>'. Other errors are
reported by <b><tt>nil</tt></b> followed by a message describing the error. reported by <b><tt>nil</tt></b> followed by a message describing the error.
</p> </p>
<p class=note> <p class="note">
Note: calling <a href=socket.html#select><tt>socket.select</tt></a> Note: calling <a href="socket.html#select"><tt>socket.select</tt></a>
with a server object in with a server object in
the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a <em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt> href="#settimeout"><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up. might block until <em>another</em> client shows up.
</p> </p>
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="bind"> <p class="name" id="bind">
master:<b>bind(</b>address, port<b>)</b> master:<b>bind(</b>address, port<b>)</b>
</p> </p>
<p class=description> <p class="description">
Binds a master object to <tt>address</tt> and <tt>port</tt> on the Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host. local host.
</p>
<p class=parameters> <p class="parameters">
<tt>Address</tt> can be an IP address or a host name. <tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [0..64K). <tt>Port</tt> must be an integer number in the range [0..64K).
If <tt>address</tt> If <tt>address</tt>
@ -86,25 +87,25 @@ If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port. chooses an ephemeral port.
</p> </p>
<p class=return> <p class="return">
In case of success, the method returns 1. In case of error, the In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message. method returns <b><tt>nil</tt></b> followed by an error message.
</p> </p>
<p class=note> <p class="note">
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> Note: The function <a href="socket.html#bind"><tt>socket.bind</tt></a>
is available and is a shortcut for the creation of server sockets. is available and is a shortcut for the creation of server sockets.
</p> </p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="close"> <p class="name" id="close">
master:<b>close()</b><br> master:<b>close()</b><br>
client:<b>close()</b><br> client:<b>close()</b><br>
server:<b>close()</b> server:<b>close()</b>
</p> </p>
<p class=description> <p class="description">
Closes a TCP object. The internal socket used by the object is closed Closes a TCP object. The internal socket used by the object is closed
and the local address to which the object was and the local address to which the object was
bound is made available to other applications. No further operations bound is made available to other applications. No further operations
@ -112,7 +113,7 @@ bound is made available to other applications. No further operations
a closed socket. a closed socket.
</p> </p>
<p class=note> <p class="note">
Note: It is important to close all used sockets once they are not Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor, needed, since, in many systems, each socket uses a file descriptor,
which are limited system resources. Garbage-collected objects are which are limited system resources. Garbage-collected objects are
@ -121,53 +122,53 @@ automatically closed before destruction, though.
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="connect"> <p class="name" id="connect">
master:<b>connect(</b>address, port<b>)</b> master:<b>connect(</b>address, port<b>)</b>
</p> </p>
<p class=description> <p class="description">
Attempts to connect a master object to a remote host, transforming it into a Attempts to connect a master object to a remote host, transforming it into a
client object. client object.
Client objects support methods Client objects support methods
<a href=#send><tt>send</tt></a>, <a href="#send"><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, <a href="#receive"><tt>receive</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>, <a href="#getsockname"><tt>getsockname</tt></a>,
<a href=#getpeername><tt>getpeername</tt></a>, <a href="#getpeername"><tt>getpeername</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>, <a href="#settimeout"><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a>. and <a href="#close"><tt>close</tt></a>.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Address</tt> can be an IP address or a host name. <tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [1..64K). <tt>Port</tt> must be an integer number in the range [1..64K).
</p> </p>
<p class=return> <p class="return">
In case of error, the method returns <b><tt>nil</tt></b> followed by a string In case of error, the method returns <b><tt>nil</tt></b> followed by a string
describing the error. In case of success, the method returns 1. describing the error. In case of success, the method returns 1.
</p> </p>
<p class=note> <p class="note">
Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> Note: The function <a href="socket.html#connect"><tt>socket.connect</tt></a>
is available and is a shortcut for the creation of client sockets. is available and is a shortcut for the creation of client sockets.
</p> </p>
<p class=note> <p class="note">
Note: Starting with LuaSocket 2.0, Note: Starting with LuaSocket 2.0,
the <a href=#settimeout><tt>settimeout</tt></a> the <a href="#settimeout"><tt>settimeout</tt></a>
method affects the behavior of <tt>connect</tt>, causing it to return method affects the behavior of <tt>connect</tt>, causing it to return
with an error in case of a timeout. If that happens, you can still call <a with an error in case of a timeout. If that happens, you can still call <a
href=socket.html#select><tt>socket.select</tt></a> with the socket in the href="socket.html#select"><tt>socket.select</tt></a> with the socket in the
<tt>sendt</tt> table. The socket will be writable when the connection is <tt>sendt</tt> table. The socket will be writable when the connection is
established. established.
</p> </p>
<p class=note> <p class="note">
Note: Starting with LuaSocket 3.0, the host name resolution Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by depends on whether the socket was created by
<a href=#socket.tcp><tt>socket.tcp</tt></a>, <a href="#socket.tcp"><tt>socket.tcp</tt></a>,
<a href=#socket.tcp4><tt>socket.tcp4</tt></a> or <a href="#socket.tcp4"><tt>socket.tcp4</tt></a> or
<a href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from <a href="#socket.tcp6"><tt>socket.tcp6</tt></a>. Addresses from
the appropriate family (or both) are tried in the order the appropriate family (or both) are tried in the order
returned by the resolver until the returned by the resolver until the
first success or until the last failure. If the timeout was first success or until the last failure. If the timeout was
@ -176,42 +177,44 @@ set to zero, only the first address is tried.
<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dirty"> <p class="name" id="dirty">
master:<b>dirty()</b><br> master:<b>dirty()</b><br>
client:<b>dirty()</b><br> client:<b>dirty()</b><br>
server:<b>dirty()</b> server:<b>dirty()</b>
</p> </p>
<p class=description> <p class="description">
Check the read buffer status. Check the read buffer status.
</p> </p>
<p class=return> <p class="return">
Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise. Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
</p> </p>
<p class=note> <p class="note">
Note: <b>This is an internal method, use at your own risk.</b> Note: <b>This is an internal method, use at your own risk.</b>
</p> </p>
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getfd"> <p class="name" id="getfd">
master:<b>getfd()</b><br> master:<b>getfd()</b><br>
client:<b>getfd()</b><br> client:<b>getfd()</b><br>
server:<b>getfd()</b> server:<b>getfd()</b>
</p> </p>
<p class=description> <p class="description">
Returns the underling socket descriptor or handle associated to the object. Returns the underling socket descriptor or handle associated to the object.
</p> </p>
<p class=return> <p class="return">
The descriptor or handle. In case the object has been closed, the return will be -1. The descriptor or handle. In case the object has been closed, the return value
will be -1. For an invalid socket it will be <a href="socket.html#socketinvalid">
<tt>_SOCKETINVALID</tt></a>.
</p> </p>
<p class=note> <p class="note">
Note: <b>This is an internal method. Unlikely to be Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b> portable. Use at your own risk. </b>
</p> </p>
@ -219,28 +222,27 @@ portable. Use at your own risk. </b>
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getoption"> <p class="name" id="getoption">
client:<b>getoption(</b>option)</b><br> client:<b>getoption(option)</b><br>
server:<b>getoption(</b>option)</b> server:<b>getoption(option)</b>
</p> </p>
<p class=description> <p class="description">
Gets options for the TCP object. Gets options for the TCP object.
See <a href=#setoption><tt>setoption</tt></a> for description of the See <a href="#setoption"><tt>setoption</tt></a> for description of the
option names and values. option names and values.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Option</tt> is a string with the option name. <tt>Option</tt> is a string with the option name.</p>
<ul> <ul>
<li> '<tt>keepalive</tt>'</li>
<li> '<tt>keepalive</tt>' <li> '<tt>linger</tt>'</li>
<li> '<tt>linger</tt>' <li> '<tt>reuseaddr</tt>'</li>
<li> '<tt>reuseaddr</tt>' <li> '<tt>tcp-nodelay</tt>'</li>
<li> '<tt>tcp-nodelay</tt>'
</ul> </ul>
<p class=return> <p class="return">
The method returns the option <tt>value</tt> in case of success, or The method returns the option <tt>value</tt> in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise. <b><tt>nil</tt></b> followed by an error message otherwise.
</p> </p>
@ -248,38 +250,38 @@ The method returns the option <tt>value</tt> in case of success, or
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getpeername"> <p class="name" id="getpeername">
client:<b>getpeername()</b> client:<b>getpeername()</b>
</p> </p>
<p class=description> <p class="description">
Returns information about the remote side of a connected client object. Returns information about the remote side of a connected client object.
</p> </p>
<p class=return> <p class="return">
Returns a string with the IP address of the peer, the Returns a string with the IP address of the peer, the
port number that peer is using for the connection, port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>. In case of error, the method returns <b><tt>nil</tt></b>.
</p> </p>
<p class=note> <p class="note">
Note: It makes no sense to call this method on server objects. Note: It makes no sense to call this method on server objects.
</p> </p>
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getsockname"> <p class="name" id="getsockname">
master:<b>getsockname()</b><br> master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br> client:<b>getsockname()</b><br>
server:<b>getsockname()</b> server:<b>getsockname()</b>
</p> </p>
<p class=description> <p class="description">
Returns the local address information associated to the object. Returns the local address information associated to the object.
</p> </p>
<p class=return> <p class="return">
The method returns a string with local IP address, a number with The method returns a string with local IP address, a number with
the local port, the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@ -288,31 +290,31 @@ In case of error, the method returns <b><tt>nil</tt></b>.
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getstats"> <p class="name" id="getstats">
master:<b>getstats()</b><br> master:<b>getstats()</b><br>
client:<b>getstats()</b><br> client:<b>getstats()</b><br>
server:<b>getstats()</b><br> server:<b>getstats()</b><br>
</p> </p>
<p class=description> <p class="description">
Returns accounting information on the socket, useful for throttling Returns accounting information on the socket, useful for throttling
of bandwidth. of bandwidth.
</p> </p>
<p class=return> <p class="return">
The method returns the number of bytes received, the number of bytes sent, The method returns the number of bytes received, the number of bytes sent,
and the age of the socket object in seconds. and the age of the socket object in seconds.
</p> </p>
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout"> <p class="name" id="gettimeout">
master:<b>gettimeout()</b><br> master:<b>gettimeout()</b><br>
client:<b>gettimeout()</b><br> client:<b>gettimeout()</b><br>
server:<b>gettimeout()</b> server:<b>gettimeout()</b>
</p> </p>
<p class=description> <p class="description">
Returns the current block timeout followed by the curent Returns the current block timeout followed by the curent
total timeout. total timeout.
</p> </p>
@ -320,65 +322,65 @@ total timeout.
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="listen"> <p class="name" id="listen">
master:<b>listen(</b>backlog<b>)</b> master:<b>listen(</b>backlog<b>)</b>
</p> </p>
<p class=description> <p class="description">
Specifies the socket is willing to receive connections, transforming the Specifies the socket is willing to receive connections, transforming the
object into a server object. Server objects support the object into a server object. Server objects support the
<a href=#accept><tt>accept</tt></a>, <a href="#accept"><tt>accept</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>, <a href="#getsockname"><tt>getsockname</tt></a>,
<a href=#setoption><tt>setoption</tt></a>, <a href="#setoption"><tt>setoption</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>, <a href="#settimeout"><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a> methods. and <a href="#close"><tt>close</tt></a> methods.
</p> </p>
<p class=parameters> <p class="parameters">
The parameter <tt>backlog</tt> specifies the number of client The parameter <tt>backlog</tt> specifies the number of client
connections that can connections that can
be queued waiting for service. If the queue is full and another client be queued waiting for service. If the queue is full and another client
attempts connection, the connection is refused. attempts connection, the connection is refused.
</p> </p>
<p class=return> <p class="return">
In case of success, the method returns 1. In case of error, the In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message. method returns <b><tt>nil</tt></b> followed by an error message.
</p> </p>
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="receive"> <p class="name" id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b> client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Reads data from a client object, according to the specified <em>read Reads data from a client object, according to the specified <em>read
pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Pattern</tt> can be any of the following: <tt>Pattern</tt> can be any of the following:
</p> </p>
<ul> <ul>
<li> '<tt>*a</tt>': reads from the socket until the connection is <li> '<tt>*a</tt>': reads from the socket until the connection is
closed. No end-of-line translation is performed; closed. No end-of-line translation is performed;</li>
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is <li> '<tt>*l</tt>': reads a line of text from the socket. The line is
terminated by a LF character (ASCII&nbsp;10), optionally preceded by a terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
CR character (ASCII&nbsp;13). The CR and LF characters are not included in CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. In fact, <em>all</em> CR characters are the returned line. In fact, <em>all</em> CR characters are
ignored by the pattern. This is the default pattern; ignored by the pattern. This is the default pattern;</li>
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> <li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket. of bytes from the socket.</li>
</ul> </ul>
<p class=parameters> <p class="parameters">
<tt>Prefix</tt> is an optional string to be concatenated to the beginning <tt>Prefix</tt> is an optional string to be concatenated to the beginning
of any received data before return. of any received data before return.
</p> </p>
<p class=return> <p class="return">
If successful, the method returns the received pattern. In case of error, If successful, the method returns the received pattern. In case of error,
the method returns <tt><b>nil</b></tt> followed by an error the method returns <tt><b>nil</b></tt> followed by an error
message, followed by a (possibly empty) string containing message, followed by a (possibly empty) string containing
@ -388,7 +390,7 @@ closed before the transmission was completed or the string
'<tt>timeout</tt>' in case there was a timeout during the operation. '<tt>timeout</tt>' in case there was a timeout during the operation.
</p> </p>
<p class=note> <p class="note">
<b>Important note</b>: This function was changed <em>severely</em>. It used <b>Important note</b>: This function was changed <em>severely</em>. It used
to support multiple patterns (but I have never seen this feature used) and to support multiple patterns (but I have never seen this feature used) and
now it doesn't anymore. Partial results used to be returned in the same now it doesn't anymore. Partial results used to be returned in the same
@ -399,22 +401,22 @@ too.
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="send"> <p class="name" id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b> client:<b>send(</b>data [, i [, j]]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Sends <tt>data</tt> through client object. Sends <tt>data</tt> through client object.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Data</tt> is the string to be sent. The optional arguments <tt>Data</tt> is the string to be sent. The optional arguments
<tt>i</tt> and <tt>j</tt> work exactly like the standard <tt>i</tt> and <tt>j</tt> work exactly like the standard
<tt>string.sub</tt> Lua function to allow the selection of a <tt>string.sub</tt> Lua function to allow the selection of a
substring to be sent. substring to be sent.
</p> </p>
<p class=return> <p class="return">
If successful, the method returns the index of the last byte If successful, the method returns the index of the last byte
within <tt>[i, j]</tt> that has been sent. Notice that, if within <tt>[i, j]</tt> that has been sent. Notice that, if
<tt>i</tt> is 1 or absent, this is effectively the total <tt>i</tt> is 1 or absent, this is effectively the total
@ -428,7 +430,7 @@ was completed or the string '<tt>timeout</tt>' in case
there was a timeout during the operation. there was a timeout during the operation.
</p> </p>
<p class=note> <p class="note">
Note: Output is <em>not</em> buffered. For small strings, Note: Output is <em>not</em> buffered. For small strings,
it is always better to concatenate them in Lua it is always better to concatenate them in Lua
(with the '<tt>..</tt>' operator) and send the result in one call (with the '<tt>..</tt>' operator) and send the result in one call
@ -437,27 +439,27 @@ instead of calling the method several times.
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setoption"> <p class="name" id="setoption">
client:<b>setoption(</b>option [, value]<b>)</b><br> client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b> server:<b>setoption(</b>option [, value]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Sets options for the TCP object. Options are only needed by low-level or Sets options for the TCP object. Options are only needed by low-level or
time-critical applications. You should only modify an option if you time-critical applications. You should only modify an option if you
are sure you need it. are sure you need it.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Option</tt> is a string with the option name, and <tt>value</tt> <tt>Option</tt> is a string with the option name, and <tt>value</tt>
depends on the option being set: depends on the option being set:</p>
<ul> <ul>
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables <li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
the periodic transmission of messages on a connected socket. Should the the periodic transmission of messages on a connected socket. Should the
connected party fail to respond to these messages, the connection is connected party fail to respond to these messages, the connection is
considered broken and processes using the socket are notified; considered broken and processes using the socket are notified;</li>
<li> '<tt>linger</tt>': Controls the action taken when unsent data are <li> '<tt>linger</tt>': Controls the action taken when unsent data are
queued on a socket and a close is performed. The value is a table with a queued on a socket and a close is performed. The value is a table with a
@ -468,79 +470,85 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will '<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
process the close in a manner that allows the process to continue as process the close in a manner that allows the process to continue as
quickly as possible. I do not advise you to set this to anything other than quickly as possible. I do not advise you to set this to anything other than
zero; zero;</li>
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules <li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
used in validating addresses supplied in a call to used in validating addresses supplied in a call to
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses; <a href="#bind"><tt>bind</tt></a> should allow reuse of local addresses;</li>
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> <li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
disables the Nagle's algorithm for the connection; disables the Nagle's algorithm for the connection;</li>
<li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!! <li> '<tt>tcp-keepidle</tt>': value in seconds for <tt>TCP_KEEPIDLE</tt> Linux only!!</li>
<li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!! <li> '<tt>tcp-keepcnt</tt>': value for <tt>TCP_KEEPCNT</tt> Linux only!!</li>
<li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!! <li> '<tt>tcp-keepintvl</tt>': value for <tt>TCP_KEEPINTVL</tt> Linux only!!</li>
<li> '<tt>tcp-defer-accept</tt>': value for <tt>TCP_DEFER_ACCEPT</tt> Linux only!!</li>
<li> '<tt>tcp-fastopen</tt>': value for <tt>TCP_FASTOPEN</tt> Linux only!!</li>
<li> '<tt>tcp-fastopen-connect</tt>': value for <tt>TCP_FASTOPEN_CONNECT</tt> Linux only!!</li>
<li> '<tt>ipv6-v6only</tt>': <li> '<tt>ipv6-v6only</tt>':
Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
sending and receiving only IPv6 packets. sending and receiving only IPv6 packets.</li>
</ul> </ul>
<p class=return> <p class="return">
The method returns 1 in case of success, or <b><tt>nil</tt></b> The method returns 1 in case of success, or <b><tt>nil</tt></b>
followed by an error message otherwise. followed by an error message otherwise.
</p> </p>
<p class=note> <p class="note">
Note: The descriptions above come from the man pages. Note: The descriptions above come from the man pages.
</p> </p>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setstats"> <p class="name" id="setstats">
master:<b>setstats(</b>received, sent, age<b>)</b><br> master:<b>setstats(</b>received, sent, age<b>)</b><br>
client:<b>setstats(</b>received, sent, age<b>)</b><br> client:<b>setstats(</b>received, sent, age<b>)</b><br>
server:<b>setstats(</b>received, sent, age<b>)</b><br> server:<b>setstats(</b>received, sent, age<b>)</b><br>
</p> </p>
<p class=description> <p class="description">
Resets accounting information on the socket, useful for throttling Resets accounting information on the socket, useful for throttling
of bandwidth. of bandwidth.
</p> </p>
<p class=parameters> <p class="parameters">
<tt>Received</tt> is a number with the new number of bytes received. <tt>Received</tt> is a number with the new number of bytes received.
<tt>Sent</tt> is a number with the new number of bytes sent. <tt>Sent</tt> is a number with the new number of bytes sent.
<tt>Age</tt> is the new age in seconds. <tt>Age</tt> is the new age in seconds.
</p> </p>
<p class=return> <p class="return">
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p> </p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="settimeout"> <p class="name" id="settimeout">
master:<b>settimeout(</b>value [, mode]<b>)</b><br> master:<b>settimeout(</b>value [, mode]<b>)</b><br>
client:<b>settimeout(</b>value [, mode]<b>)</b><br> client:<b>settimeout(</b>value [, mode]<b>)</b><br>
server:<b>settimeout(</b>value [, mode]<b>)</b> server:<b>settimeout(</b>value [, mode]<b>)</b>
</p> </p>
<p class=description> <p class="description">
Changes the timeout values for the object. By default, Changes the timeout values for the object. By default,
all I/O operations are blocking. That is, any call to the methods all I/O operations are blocking. That is, any call to the methods
<a href=#send><tt>send</tt></a>, <a href="#send"><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, and <a href="#receive"><tt>receive</tt></a>, and
<a href=#accept><tt>accept</tt></a> <a href="#accept"><tt>accept</tt></a>
will block indefinitely, until the operation completes. The will block indefinitely, until the operation completes. The
<tt>settimeout</tt> method defines a limit on the amount of time the <tt>settimeout</tt> method defines a limit on the amount of time the
I/O methods can block. When a timeout is set and the specified amount of I/O methods can block. When a timeout is set and the specified amount of
time has elapsed, the affected methods give up and fail with an error code. time has elapsed, the affected methods give up and fail with an error code.
</p> </p>
<p class=parameters> <p class="parameters">
The amount of time to wait is specified as the The amount of time to wait is specified as the
<tt>value</tt> parameter, in seconds. There are two timeout modes and <tt>value</tt> parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning: both can be used together for fine tuning:
@ -557,12 +565,12 @@ the amount of time LuaSocket can block a Lua script before returning from
a call.</li> a call.</li>
</ul> </ul>
<p class=parameters> <p class="parameters">
The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block
indefinitely. Negative timeout values have the same effect. indefinitely. Negative timeout values have the same effect.
</p> </p>
<p class=note> <p class="note">
Note: although timeout values have millisecond precision in LuaSocket, Note: although timeout values have millisecond precision in LuaSocket,
large blocks can cause I/O functions not to respect timeout values due large blocks can cause I/O functions not to respect timeout values due
to the time the library takes to transfer blocks to and from the OS to the time the library takes to transfer blocks to and from the OS
@ -571,7 +579,7 @@ and perform automatic name resolution might be blocked by the resolver for
longer than the specified timeout value. longer than the specified timeout value.
</p> </p>
<p class=note> <p class="note">
Note: The old <tt>timeout</tt> method is deprecated. The name has been Note: The old <tt>timeout</tt> method is deprecated. The name has been
changed for sake of uniformity, since all other method names already changed for sake of uniformity, since all other method names already
contained verbs making their imperative nature obvious. contained verbs making their imperative nature obvious.
@ -579,123 +587,126 @@ contained verbs making their imperative nature obvious.
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="shutdown"> <p class="name" id="shutdown">
client:<b>shutdown(</b>mode<b>)</b><br> client:<b>shutdown(</b>mode<b>)</b><br>
</p> </p>
<p class=description> <p class="description">
Shuts down part of a full-duplex connection. Shuts down part of a full-duplex connection.
</p> </p>
<p class=parameters> <p class="parameters">
Mode tells which way of the connection should be shut down and can Mode tells which way of the connection should be shut down and can
take the value: take the value:
<ul> <ul>
<li>"<tt>both</tt>": disallow further sends and receives on the object. <li>"<tt>both</tt>": disallow further sends and receives on the object.
This is the default mode; This is the default mode;</li>
<li>"<tt>send</tt>": disallow further sends on the object; <li>"<tt>send</tt>": disallow further sends on the object;</li>
<li>"<tt>receive</tt>": disallow further receives on the object. <li>"<tt>receive</tt>": disallow further receives on the object.</li>
</ul> </ul>
</p>
<p class=return> <p class="return">
This function returns 1. This function returns 1.
</p> </p>
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setfd"> <p class="name" id="setfd">
master:<b>setfd(</b>fd<b>)</b><br> master:<b>setfd(</b>fd<b>)</b><br>
client:<b>setfd(</b>fd<b>)</b><br> client:<b>setfd(</b>fd<b>)</b><br>
server:<b>setfd(</b>fd<b>)</b> server:<b>setfd(</b>fd<b>)</b>
</p> </p>
<p class=description> <p class="description">
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made. Sets the underling socket descriptor or handle associated to the object. The current one
is simply replaced, not closed, and no other change to the object state is made.
To set it as invalid use <a href="socket.html#socketinvalid"><tt>_SOCKETINVALID</tt></a>.
</p> </p>
<p class=return> <p class="return">
No return value. No return value.
</p> </p>
<p class=note> <p class="note">
Note: <b>This is an internal method. Unlikely to be Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b> portable. Use at your own risk. </b>
</p> </p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp"> <p class="name" id="socket.tcp">
socket.<b>tcp()</b> socket.<b>tcp()</b>
</p> </p>
<p class=description> <p class="description">
Creates and returns an TCP master object. A master object can Creates and returns an TCP master object. A master object can
be transformed into a server object with the method be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a <a href="#listen"><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with href="#bind"><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other the method <a href="#connect"><tt>connect</tt></a>. The only other
method supported by a master object is the method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p> <a href="#close"><tt>close</tt></a> method.</p>
<p class=return> <p class="return">
In case of success, a new master object is returned. In case of error, In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message. <b><tt>nil</tt></b> is returned, followed by an error message.
</p> </p>
<p class=note> <p class="note">
Note: The choice between IPv4 and IPv6 happens during a call to Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#bind><tt>bind</tt></a> or <a <a href="#bind"><tt>bind</tt></a> or <a
href=#bind><tt>connect</tt></a>, depending on the address href="#bind"><tt>connect</tt></a>, depending on the address
family obtained from the resolver. family obtained from the resolver.
</p> </p>
<p class=note> <p class="note">
Note: Before the choice between IPv4 and IPv6 happens, Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail. href="#setoption"><tt>setoption</tt></a> will fail.
</p> </p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp4"> <p class="name" id="socket.tcp4">
socket.<b>tcp4()</b> socket.<b>tcp4()</b>
</p> </p>
<p class=description> <p class="description">
Creates and returns an IPv4 TCP master object. A master object can Creates and returns an IPv4 TCP master object. A master object can
be transformed into a server object with the method be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a <a href="#listen"><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with href="#bind"><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other the method <a href="#connect"><tt>connect</tt></a>. The only other
method supported by a master object is the method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p> <a href="#close"><tt>close</tt></a> method.</p>
<p class=return> <p class="return">
In case of success, a new master object is returned. In case of error, In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message. <b><tt>nil</tt></b> is returned, followed by an error message.
</p> </p>
<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp6"> <p class="name" id="socket.tcp6">
socket.<b>tcp6()</b> socket.<b>tcp6()</b>
</p> </p>
<p class=description> <p class="description">
Creates and returns an IPv6 TCP master object. A master object can Creates and returns an IPv6 TCP master object. A master object can
be transformed into a server object with the method be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a <a href="#listen"><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with href="#bind"><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other the method <a href="#connect"><tt>connect</tt></a>. The only other
method supported by a master object is the method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p> <a href="#close"><tt>close</tt></a> method.</p>
<p class=return> <p class="return">
In case of success, a new master object is returned. In case of error, In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message. <b><tt>nil</tt></b> is returned, followed by an error message.
</p> </p>
<p class=note> <p class="note">
Note: The TCP object returned will have the option Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>. "<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p> </p>
@ -704,10 +715,10 @@ Note: The TCP object returned will have the option
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot; <a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -13,17 +13,17 @@
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header> <div class="header">
<hr> <hr>
<center> <center>
<table summary="LuaSocket logo"> <table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org"> <tr><td align="center"><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png"> <img width="128" height="128" border="0" alt="LuaSocket" src="luasocket.png">
</a></td></tr> </a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language <tr><td align="center" valign="top">Network support for the Lua language
</td></tr> </td></tr>
</table> </table>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;
@ -71,26 +71,26 @@ unconnected:<b>getoption()</b>
<p class="description"> <p class="description">
Gets an option value from the UDP object. Gets an option value from the UDP object.
See <a href=#setoption><tt>setoption</tt></a> for See <a href="#setoption"><tt>setoption</tt></a> for
description of the option names and values. description of the option names and values.
</p> </p>
<p class="parameters"><tt>Option</tt> is a string with the option name. <p class="parameters"><tt>Option</tt> is a string with the option name.
<ul> <ul>
<li> '<tt>dontroute</tt>' <li> '<tt>dontroute</tt>'</li>
<li> '<tt>broadcast</tt>' <li> '<tt>broadcast</tt>'</li>
<li> '<tt>reuseaddr</tt>' <li> '<tt>reuseaddr</tt>'</li>
<li> '<tt>reuseport</tt>' <li> '<tt>reuseport</tt>'</li>
<li> '<tt>ip-multicast-loop</tt>' <li> '<tt>ip-multicast-loop</tt>'</li>
<li> '<tt>ipv6-v6only</tt>' <li> '<tt>ipv6-v6only</tt>'</li>
<li> '<tt>ip-multicast-if</tt>' <li> '<tt>ip-multicast-if</tt>'</li>
<li> '<tt>ip-multicast-ttl</tt>' <li> '<tt>ip-multicast-ttl</tt>'</li>
<li> '<tt>ip-add-membership</tt>' <li> '<tt>ip-add-membership</tt>'</li>
<li> '<tt>ip-drop-membership</tt>' <li> '<tt>ip-drop-membership</tt>'</li>
</ul> </ul>
</p> </p>
<p class=return> <p class="return">
The method returns the option <tt>value</tt> in case of The method returns the option <tt>value</tt> in case of
success, or success, or
<b><tt>nil</tt></b> followed by an error message otherwise. <b><tt>nil</tt></b> followed by an error message otherwise.
@ -108,7 +108,7 @@ associated with a connected UDP object.
</p> </p>
<p class=return> <p class="return">
Returns a string with the IP address of the peer, the Returns a string with the IP address of the peer, the
port number that peer is using for the connection, port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@ -131,7 +131,7 @@ Returns the local address information associated to the object.
</p> </p>
<p class=return> <p class="return">
The method returns a string with local IP address, a number with The method returns a string with local IP address, a number with
the local port, the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
@ -148,12 +148,12 @@ wild-card address).
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout"> <p class="name" id="gettimeout">
connected:<b>settimeout(</b>value<b>)</b><br> connected:<b>settimeout(</b>value<b>)</b><br>
unconnected:<b>settimeout(</b>value<b>)</b> unconnected:<b>settimeout(</b>value<b>)</b>
</p> </p>
<p class=description> <p class="description">
Returns the current timeout value. Returns the current timeout value.
</p> </p>
@ -180,8 +180,8 @@ the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the <tt>size</tt> bytes available in the current datagram, the
available bytes are returned. available bytes are returned.
If <tt>size</tt> is omitted, the If <tt>size</tt> is omitted, the
compile-time constant <a compile-time constant <a href="socket.html#datagramsize">
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used <tt>socket._DATAGRAMSIZE</tt></a> is used
(it defaults to 8192 bytes). Larger sizes will cause a (it defaults to 8192 bytes). Larger sizes will cause a
temporary buffer to be allocated for the operation. temporary buffer to be allocated for the operation.
</p> </p>
@ -286,45 +286,45 @@ name, and <tt>value</tt> depends on the option being set:
<ul> <ul>
<li> '<tt>dontroute</tt>': Indicates that outgoing <li> '<tt>dontroute</tt>': Indicates that outgoing
messages should bypass the standard routing facilities. messages should bypass the standard routing facilities.
Receives a boolean value; Receives a boolean value;</li>
<li> '<tt>broadcast</tt>': Requests permission to send <li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket. broadcast datagrams on the socket.
Receives a boolean value; Receives a boolean value;</li>
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in <li> '<tt>reuseaddr</tt>': Indicates that the rules used in
validating addresses supplied in a <tt>bind()</tt> call validating addresses supplied in a <tt>bind()</tt> call
should allow reuse of local addresses. should allow reuse of local addresses.
Receives a boolean value; Receives a boolean value;</li>
<li> '<tt>reuseport</tt>': Allows completely duplicate <li> '<tt>reuseport</tt>': Allows completely duplicate
bindings by multiple processes if they all set bindings by multiple processes if they all set
'<tt>reuseport</tt>' before binding the port. '<tt>reuseport</tt>' before binding the port.
Receives a boolean value; Receives a boolean value;</li>
<li> '<tt>ip-multicast-loop</tt>': <li> '<tt>ip-multicast-loop</tt>':
Specifies whether or not a copy of an outgoing multicast Specifies whether or not a copy of an outgoing multicast
datagram is delivered to the sending host as long as it is a datagram is delivered to the sending host as long as it is a
member of the multicast group. member of the multicast group.
Receives a boolean value; Receives a boolean value;</li>
<li> '<tt>ipv6-v6only</tt>': <li> '<tt>ipv6-v6only</tt>':
Specifies whether to restrict <tt>inet6</tt> sockets to Specifies whether to restrict <tt>inet6</tt> sockets to
sending and receiving only IPv6 packets. sending and receiving only IPv6 packets.
Receive a boolean value; Receive a boolean value;</li>
<li> '<tt>ip-multicast-if</tt>': <li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams Sets the interface over which outgoing multicast datagrams
are sent. are sent.
Receives an IP address; Receives an IP address;</li>
<li> '<tt>ip-multicast-ttl</tt>': <li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing Sets the Time To Live in the IP header for outgoing
multicast datagrams. multicast datagrams.
Receives a number; Receives a number;</li>
<li> '<tt>ip-add-membership</tt>': <li> '<tt>ip-add-membership</tt>':
Joins the multicast group specified. Joins the multicast group specified.
Receives a table with fields Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an <tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address; IP address;</li>
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast <li> '<tt>ip-drop-membership</tt>': Leaves the multicast
group specified. group specified.
Receives a table with fields Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an <tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address. IP address.</li>
</ul> </ul>
<p class="return"> <p class="return">
@ -332,7 +332,7 @@ The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise. <b><tt>nil</tt></b> followed by an error message otherwise.
</p> </p>
<p class=note> <p class="note">
Note: The descriptions above come from the man pages. Note: The descriptions above come from the man pages.
</p> </p>
@ -381,11 +381,11 @@ is recommended when the same peer is used for several transmissions
and can result in up to 30% performance gains. and can result in up to 30% performance gains.
</p> </p>
<p class=note> <p class="note">
Note: Starting with LuaSocket 3.0, the host name resolution Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by <a depends on whether the socket was created by <a
href=#socket.udp><tt>socket.udp</tt></a> or <a href="#socket.udp"><tt>socket.udp</tt></a> or <a
href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from href="#socket.udp6"><tt>socket.udp6</tt></a>. Addresses from
the appropriate family are tried in succession until the the appropriate family are tried in succession until the
first success or until the last failure. first success or until the last failure.
</p> </p>
@ -492,23 +492,23 @@ returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message. an error message.
</p> </p>
<p class=note> <p class="note">
Note: The choice between IPv4 and IPv6 happens during a call to Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#sendto><tt>sendto</tt></a>, <a <a href="#sendto"><tt>sendto</tt></a>, <a
href=#setpeername><tt>setpeername</tt></a>, or <a href="#setpeername"><tt>setpeername</tt></a>, or <a
href=#setsockname><tt>sockname</tt></a>, depending on the address href="#setsockname"><tt>sockname</tt></a>, depending on the address
family obtained from the resolver. family obtained from the resolver.
</p> </p>
<p class=note> <p class="note">
Note: Before the choice between IPv4 and IPv6 happens, Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail. href="#setoption"><tt>setoption</tt></a> will fail.
</p> </p>
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp"> <p class="name" id="socket.udp4">
socket.<b>udp4()</b> socket.<b>udp4()</b>
</p> </p>
@ -564,7 +564,7 @@ returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message. an error message.
</p> </p>
<p class=note> <p class="note">
Note: The TCP object returned will have the option Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>. "<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p> </p>
@ -573,10 +573,10 @@ Note: The TCP object returned will have the option
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer> <div class="footer">
<hr> <hr>
<center> <center>
<p class=bar> <p class="bar">
<a href="index.html">home</a> &middot; <a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot; <a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot; <a href="installation.html">installation</a> &middot;

View File

@ -1,89 +0,0 @@
This directory contains code that is more useful than the
samples. This code *is* supported.
tftp.lua -- Trivial FTP client
This module implements file retrieval by the TFTP protocol.
Its main use was to test the UDP code, but since someone
found it usefull, I turned it into a module that is almost
official (no uploads, yet).
dict.lua -- Dict client
The dict.lua module started with a cool simple client
for the DICT protocol, written by Luiz Henrique Figueiredo.
This new version has been converted into a library, similar
to the HTTP and FTP libraries, that can be used from within
any luasocket application. Take a look on the source code
and you will be able to figure out how to use it.
lp.lua -- LPD client library
The lp.lua module implements the client part of the Line
Printer Daemon protocol, used to print files on Unix
machines. It is courtesy of David Burgess! See the source
code and the lpr.lua in the examples directory.
b64.lua
qp.lua
eol.lua
These are tiny programs that perform Base64,
Quoted-Printable and end-of-line marker conversions.
get.lua -- file retriever
This little program is a client that uses the FTP and
HTTP code to implement a command line file graber. Just
run
lua get.lua <remote-file> [<local-file>]
to download a remote file (either ftp:// or http://) to
the specified local file. The program also prints the
download throughput, elapsed time, bytes already downloaded
etc during download.
check-memory.lua -- checks memory consumption
This is just to see how much memory each module uses.
dispatch.lua -- coroutine based dispatcher
This is a first try at a coroutine based non-blocking
dispatcher for LuaSocket. Take a look at 'check-links.lua'
and at 'forward.lua' to see how to use it.
check-links.lua -- HTML link checker program
This little program scans a HTML file and checks for broken
links. It is similar to check-links.pl by Jamie Zawinski,
but uses all facilities of the LuaSocket library and the Lua
language. It has not been thoroughly tested, but it should
work. Just run
lua check-links.lua [-n] {<url>} > output
and open the result to see a list of broken links. Make sure
you check the '-n' switch. It runs in non-blocking mode,
using coroutines, and is MUCH faster!
forward.lua -- coroutine based forward server
This is a forward server that can accept several connections
and transfers simultaneously using non-blocking I/O and the
coroutine-based dispatcher. You can run, for example
lua forward.lua 8080:proxy.com:3128
to redirect all local conections to port 8080 to the host
'proxy.com' at port 3128.
unix.c and unix.h
This is an implementation of Unix local domain sockets and
demonstrates how to extend LuaSocket with a new type of
transport. It has been tested on Linux and on Mac OS X.
Good luck,
Diego.

View File

@ -1,4 +0,0 @@
local CRLF = "\013\010"
local input = source.chain(source.file(io.stdin), normalize(CRLF))
local output = sink.file(io.stdout)
pump.all(input, output)

View File

@ -1,17 +0,0 @@
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then
if err then return nil, err
else return 1 end
end
end
end

View File

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

View File

@ -1,34 +0,0 @@
local smtp = require"socket.smtp"
local mime = require"mime"
local ltn12 = require"ltn12"
CRLF = "\013\010"
local message = smtp.message{
headers = {
from = "Sicrano <sicrano@example.com>",
to = "Fulano <fulano@example.com>",
subject = "A message with an attachment"},
body = {
preamble = "Hope you can see the attachment" .. CRLF,
[1] = {
body = "Here is our logo" .. CRLF},
[2] = {
headers = {
["content-type"] = 'image/png; name="luasocket.png"',
["content-disposition"] =
'attachment; filename="luasocket.png"',
["content-description"] = 'LuaSocket logo',
["content-transfer-encoding"] = "BASE64"},
body = ltn12.source.chain(
ltn12.source.file(io.open("luasocket.png", "rb")),
ltn12.filter.chain(
mime.encode("base64"),
mime.wrap()))}}}
assert(smtp.send{
rcpt = "<diego@cs.princeton.edu>",
from = "<diego@cs.princeton.edu>",
server = "localhost",
port = 2525,
source = message})

View File

@ -1,11 +0,0 @@
function filter.cycle(lowlevel, context, extra)
return function(chunk)
local ret
ret, context = lowlevel(context, chunk, extra)
return ret
end
end
function normalize(marker)
return filter.cycle(eol, 0, marker)
end

View File

@ -1,15 +0,0 @@
local function chainpair(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return (ret or "") .. (f2() or "") end
end
end
function filter.chain(...)
local f = select(1, ...)
for i = 2, select('#', ...) do
f = chainpair(f, select(i, ...))
end
return f
end

View File

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

View File

@ -1,15 +0,0 @@
function source.empty(err)
return function()
return nil, err
end
end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(20)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end

View File

@ -1,14 +0,0 @@
function source.chain(src, f)
return function()
if not src then
return nil
end
local chunk, err = src()
if not chunk then
src = nil
return f(nil)
else
return f(chunk)
end
end
end

View File

@ -1,16 +0,0 @@
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
local function null()
return 1
end
function sink.null()
return null
end

View File

@ -1,5 +0,0 @@
local input = source.file(io.stdin)
local output, t = sink.table()
output = sink.chain(normalize(CRLF), output)
pump.all(input, output)
io.write(table.concat(t))

View File

@ -1,3 +0,0 @@
for chunk in source.file(io.stdin) do
io.write(chunk)
end

View File

@ -1,54 +0,0 @@
#include "lua.h"
#include "lauxlib.h"
#define CR '\xD'
#define LF '\xA'
#define CRLF "\xD\xA"
#define candidate(c) (c == CR || c == LF)
static int pushchar(int c, int last, const char *marker,
luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last)
luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
return 0;
}
}
static int eol(lua_State *L) {
int context = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input < last)
context = pushchar(*input++, context, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, context);
return 2;
}
static luaL_reg func[] = {
{ "eol", eol },
{ NULL, NULL }
};
int luaopen_gem(lua_State *L) {
luaL_openlib(L, "gem", func, 0);
return 0;
}

View File

@ -1,206 +0,0 @@
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,14 +0,0 @@
ltn012.pdf: ltn012.ps
./myps2pdf ltn012.ps
ltn012.ps: ltn012.dvi
dvips -G0 -t letter -o ltn012.ps ltn012.dvi
ltn012.dvi: ltn012.tex
latex ltn012
clean:
rm -f *~ *.log *.aux *.bbl *.blg ltn012.pdf ltn012.ps ltn012.dvi ltn012.lof ltn012.toc ltn012.lot
pdf: ltn012.pdf
open ltn012.pdf

View File

@ -1,113 +0,0 @@
#!/bin/sh -
do_opt=1
best=0
rot=0
a4=0
eps=0
usage="Usage: $0 [-no_opt] [-best] [-rot] [-a4] [-eps] in.ps [out.pdf]"
case "x$1" in
"x-no_opt") do_opt=0 ; shift ;;
esac
case "x$1" in
"x-best") best=1 ; shift ;;
esac
case "x$1" in
"x-rot") rot=1 ; shift ;;
esac
case "x$1" in
"x-a4") a4=1 ; shift ;;
esac
case "x$1" in
"x-eps") eps=1 ; shift ;;
esac
case $# in
2) ifilename=$1 ; ofilename=$2 ;;
1) ifilename=$1
if `echo $1 | grep -i '\.e*ps$' > /dev/null`
then
ofilename=`echo $1 | sed 's/\..*$/.pdf/'`
else
echo "$usage" 1>&2
exit 1
fi ;;
*) echo "$usage" 1>&2 ; exit 1 ;;
esac
if [ $best == 1 ]
then
options="-dPDFSETTINGS=/prepress \
-r1200 \
-dMonoImageResolution=1200 \
-dGrayImageResolution=1200 \
-dColorImageResolution=1200 \
-dDownsampleMonoImages=false \
-dDownsampleGrayImages=false \
-dDownsampleColorImages=false \
-dAutoFilterMonoImages=false \
-dAutoFilterGrayImages=false \
-dAutoFilterColorImages=false \
-dMonoImageFilter=/FlateEncode \
-dGrayImageFilter=/FlateEncode \
-dColorImageFilter=/FlateEncode"
else
options="-dPDFSETTINGS=/prepress \
-r600 \
-dDownsampleMonoImages=true \
-dDownsampleGrayImages=true \
-dDownsampleColorImages=true \
-dMonoImageDownsampleThreshold=2.0 \
-dGrayImageDownsampleThreshold=1.5 \
-dColorImageDownsampleThreshold=1.5 \
-dMonoImageResolution=600 \
-dGrayImageResolution=600 \
-dColorImageResolution=600 \
-dAutoFilterMonoImages=false \
-dMonoImageFilter=/FlateEncode \
-dAutoFilterGrayImages=true \
-dAutoFilterColorImages=true"
fi
if [ $rot == 1 ]
then
options="$options -dAutoRotatePages=/PageByPage"
fi
if [ $eps == 1 ]
then
options="$options -dEPSCrop"
fi
set -x
if [ $a4 == 1 ]
then
# Resize from A4 to letter size
psresize -Pa4 -pletter "$ifilename" myps2pdf.temp.ps
ifilename=myps2pdf.temp.ps
fi
gs -q -dSAFER -dNOPAUSE -dBATCH \
-sDEVICE=pdfwrite -sPAPERSIZE=letter -sOutputFile=myps2pdf.temp.pdf \
-dCompatibilityLevel=1.3 \
$options \
-dMaxSubsetPct=100 \
-dSubsetFonts=true \
-dEmbedAllFonts=true \
-dColorConversionStrategy=/LeaveColorUnchanged \
-dDoThumbnails=true \
-dPreserveEPSInfo=true \
-c .setpdfwrite -f "$ifilename"
if [ $do_opt == 1 ]
then
pdfopt myps2pdf.temp.pdf $ofilename
else
mv myps2pdf.temp.pdf $ofilename
fi
rm -f myps2pdf.temp.pdf myps2pdf.temp.ps

View File

@ -1,25 +0,0 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- sink.file
require"ltn12"
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex1.lua")

View File

@ -1,5 +0,0 @@
this is a test file
it should have been saved as lf eol
but t1.lua will convert it to crlf eol
otherwise it is broken!

View File

@ -1,36 +0,0 @@
source = {}
sink = {}
pump = {}
filter = {}
-- filter.chain
dofile("ex3.lua")
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- encode
require"mime"
encode = mime.encode
-- wrap
wrap = mime.wrap
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- sink.file
require"ltn12"
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
CRLF = "\013\010"
dofile("ex4.lua")

View File

@ -1,4 +0,0 @@
esse é um texto com acentos
quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de texto
fora que as quebras de linhas têm que ser normalizadas
vamos ver o que dá isso aqui

View File

@ -1,5 +0,0 @@
esse =E9 um texto com acentos
quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de t=
exto
fora que as quebras de linhas t=EAm que ser normalizadas
vamos ver o que d=E1 isso aqui

View File

@ -1,25 +0,0 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.file
dofile("ex5.lua")
-- sink.table
dofile("ex7.lua")
-- sink.chain
require"ltn12"
sink.chain = ltn12.sink.chain
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex8.lua")

View File

@ -1,10 +0,0 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.file
dofile("ex5.lua")
-- run test
dofile("ex9.lua")

View File

@ -1,30 +0,0 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- encode
require"mime"
encode = mime.encode
-- sink.chain
require"ltn12"
sink.chain = ltn12.sink.chain
-- wrap
wrap = mime.wrap
-- sink.file
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex11.lua")

View File

@ -1,46 +0,0 @@
function readfile(n)
local f = io.open(n, "rb")
local s = f:read("*a")
f:close()
return s
end
lf = readfile("t1lf.txt")
os.remove("t1crlf.txt")
os.execute("lua t1.lua < t1lf.txt > t1crlf.txt")
crlf = readfile("t1crlf.txt")
assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
gt = readfile("t2gt.qp")
os.remove("t2.qp")
os.execute("lua t2.lua < t2.txt > t2.qp")
t2 = readfile("t2.qp")
assert(gt == t2, "broken")
os.remove("t1crlf.txt")
os.execute("lua t3.lua < t1lf.txt > t1crlf.txt")
crlf = readfile("t1crlf.txt")
assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
t = readfile("test.lua")
os.execute("lua t4.lua < test.lua > t")
t2 = readfile("t")
assert(t == t2, "broken")
os.remove("output.b64")
gt = readfile("gt.b64")
os.execute("lua t5.lua")
t5 = readfile("output.b64")
assert(gt == t5, "failed")
print("1 2 5 6 10 passed")
print("2 3 4 5 6 10 passed")
print("2 5 6 7 8 10 passed")
print("5 9 passed")
print("5 6 10 11 passed")
os.remove("t")
os.remove("t2.qp")
os.remove("t1crlf.txt")
os.remove("t11.b64")
os.remove("output.b64")

390
ltn012.md Normal file
View File

@ -0,0 +1,390 @@
# Filters, sources and sinks: design, motivation and examples
### or Functional programming for the rest of us
by DiegoNehab
## Abstract
Certain 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.
## Introduction
Applications 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.
"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.
A "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.
Filters 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.
Finally, 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.
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.
### A concrete example
Some 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.
Assume we are given text in an unknown end-of-line convention (including possibly mixed conventions) out of the commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) conventions. We would like to be able to write code like the following:
```lua
input = source.chain(source.file(io.stdin), normalize("\r\n"))
output = sink.file(io.stdout)
pump(input, output)
```
This 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.
To 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.
Although 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.
We 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.
### The Lua part of the implementation
Below is the implementation of the factory of high-level end-of-line normalization filters:
```lua
function filter.cycle(low, ctx, extra)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
return ret
end
end
function normalize(marker)
return cycle(eol, 0, marker)
end
```
The `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.
Moving 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.
Here 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.
### The C part of the implementation
The 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.
```c
#define candidate(c) (c == CR || c == LF)
static int process(int c, int last, const char *marker, luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last) luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
return 0;
}
}
```
The 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.
```c
static int eol(lua_State *L) {
int ctx = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &amp;buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input &lt; last)
ctx = process(*input++, ctx, marker, &amp;buffer);
luaL_pushresult(&amp;buffer);
lua_pushnumber(L, ctx);
return 2;
}
```
Notice that if the input chunk is `nil`, the operation is considered to be finished. In that case, the loop will not execute a single time and the context is reset to the initial state. This allows the filter to be reused indefinitely. It is a good idea to write filters like this, when possible.
Besides 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.
## Chaining
Filters 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.
```lua
local function chain2(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return ret .. f2() end
end
end
function filter.chain(...)
local arg = {...}
local f = arg[1]
for i = 2, #arg do
f = chain2(f, arg[i])
end
return f
end
local chain = filter.chain(normalize("\r\n"), encode("quoted-printable"))
while 1 do
local chunk = io.read(2048)
io.write(chain(chunk))
if not chunk then break end
end
```
The 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.
## Sources, sinks, and pumps
As 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.
### Sources
We 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.
```lua
function source.empty(err)
return function()
return nil, err
end
end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(2048)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
```
A 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:
```lua
local process = normalize("\r\n")
for chunk in source.file(io.stdin) do
io.write(process(chunk))
end
io.write(process(nil))
```
Notice 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.
### Maintaining state between calls
It 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.
One 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:
```lua
function source.file(handle, io_err)
if handle then
return function()
if not handle then return nil end
local chunk = handle:read(2048)
if not chunk then
handle:close()
handle = nil
end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
```
Another 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.
This 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.
```lua
function source.simplify(src)
return function()
local chunk, err_or_new = src()
src = err_or_new or src
if not chunk then return nil, err_or_new
else return chunk end
end
end
```
The 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.
Going 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:
```lua
function source.file(handle, io_err)
if handle then
return source.simplify(function()
local chunk = handle:read(2048)
if not chunk then
handle:close()
return "", source.empty()
end
return chunk
end)
else return source.empty(io_err or "unable to open file") end
end
```
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
```lua
function source.cat(...)
local arg = {...}
local co = coroutine.create(function()
local i = 1
while i <= #arg do
local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk)
elseif err then return nil, err
else i = i + 1 end
end
end)
return function()
return shift(coroutine.resume(co))
end
end
```
The 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.
### Chaining Sources
What 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:
```lua
function source.chain(src, f)
return source.simplify(function()
local chunk, err = src()
if not chunk then return f(nil), source.empty(err)
else return f(chunk) end
end)
end
```
Our 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.
### Sinks
Just 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.
```lua
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
local function null()
return 1
end
function sink.null()
return null
end
```
Sinks 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.
As 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.
```lua
local load = source.chain(source.file(io.stdin), normalize("\r\n"))
local store, t = sink.table()
while 1 do
local chunk = load()
store(chunk)
if not chunk then break end
end
print(table.concat(t))
```
Again, 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:
```lua
function sink.chain(f, snk)
return function(chunk, err)
local r, e = snk(f(chunk))
if not r then return nil, e end
if not chunk then return snk(nil, err) end
return 1
end
end
```
### Pumps
There 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.
```lua
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
return chunk and ret and not src_err and not snk_err, src_err or snk_err
end
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then return not err, err end
end
end
```
The `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:
```lua
local load = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64")
)
local store = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")),
)
pump.all(load, store)
```
The way we split the filters here is not intuitive, on purpose. Alternatively, we could have chained the Base64 encode filter and the line-wrap filter together, and then chain the resulting filter with either the file source or the file sink. It doesn't really matter.
## One last important change
Turns 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.
More 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.
Most 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!
```lua
local function chain2(f1, f2)
local co = coroutine.create(function(chunk)
while true do
local filtered1 = f1(chunk)
local filtered2 = f2(filtered1)
local done2 = filtered1 and ""
while true do
if filtered2 == "" or filtered2 == nil then break end
coroutine.yield(filtered2)
filtered2 = f2(done2)
end
if filtered1 == "" then chunk = coroutine.yield(filtered1)
elseif filtered1 == nil then return nil
else chunk = chunk and "" end
end
end)
return function(chunk)
local _, res = coroutine.resume(co, chunk)
return res
end
end
```
Chaining 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.
## Final considerations
These 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.
One 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.
In 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.

View File

@ -1,393 +0,0 @@
===Filters, sources and sinks: design, motivation and examples===
==or Functional programming for the rest of us==
by DiegoNehab
{{{
}}}
===Abstract===
Certain 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.
===Introduction===
Applications 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.
''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.
A ''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.
Filters 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.
Finally, 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.
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.
== A concrete example ==
Some 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.
Assume we are given text in an unknown end-of-line convention (including possibly mixed conventions) out of the commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) conventions. We would like to be able to write code like the following:
{{{
input = source.chain(source.file(io.stdin), normalize("\r\n"))
output = sink.file(io.stdout)
pump(input, output)
}}}
This 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.
To 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.
Although 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.
We 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.
==The Lua part of the implementation==
Below is the implementation of the factory of high-level end-of-line normalization filters:
{{{
function filter.cycle(low, ctx, extra)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
return ret
end
end
function normalize(marker)
return cycle(eol, 0, marker)
end
}}}
The {{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.
Moving 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.
Here 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.
==The C part of the implementation==
The 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.
{{{
#define candidate(c) (c == CR || c == LF)
static int process(int c, int last, const char *marker, luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last) luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
return 0;
}
}
}}}
The 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.
{{{
static int eol(lua_State *L) {
int ctx = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &amp;buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input &lt; last)
ctx = process(*input++, ctx, marker, &amp;buffer);
luaL_pushresult(&amp;buffer);
lua_pushnumber(L, ctx);
return 2;
}
}}}
Notice that if the input chunk is {{nil}}, the operation is considered to be finished. In that case, the loop will not execute a single time and the context is reset to the initial state. This allows the filter to be reused indefinitely. It is a good idea to write filters like this, when possible.
Besides 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.
===Chaining===
Filters 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.
{{{
local function chain2(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return ret .. f2() end
end
end
function filter.chain(...)
local arg = {...}
local f = arg[1]
for i = 2, #arg do
f = chain2(f, arg[i])
end
return f
end
local chain = filter.chain(normalize("\r\n"), encode("quoted-printable"))
while 1 do
local chunk = io.read(2048)
io.write(chain(chunk))
if not chunk then break end
end
}}}
The 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.
===Sources, sinks, and pumps===
As 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.
==Sources==
We 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.
{{{
function source.empty(err)
return function()
return nil, err
end
end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(2048)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
}}}
A 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:
{{{
local process = normalize("\r\n")
for chunk in source.file(io.stdin) do
io.write(process(chunk))
end
io.write(process(nil))
}}}
Notice 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.
==Maintaining state between calls==
It 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.
One 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:
{{{
function source.file(handle, io_err)
if handle then
return function()
if not handle then return nil end
local chunk = handle:read(2048)
if not chunk then
handle:close()
handle = nil
end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
}}}
Another 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.
This 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.
{{{
function source.simplify(src)
return function()
local chunk, err_or_new = src()
src = err_or_new or src
if not chunk then return nil, err_or_new
else return chunk end
end
end
}}}
The 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.
Going 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:
{{{
function source.file(handle, io_err)
if handle then
return source.simplify(function()
local chunk = handle:read(2048)
if not chunk then
handle:close()
return "", source.empty()
end
return chunk
end)
else return source.empty(io_err or "unable to open file") end
end
}}}
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
{{{
function source.cat(...)
local arg = {...}
local co = coroutine.create(function()
local i = 1
while i <= #arg do
local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk)
elseif err then return nil, err
else i = i + 1 end
end
end)
return function()
return shift(coroutine.resume(co))
end
end
}}}
The 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.
==Chaining Sources==
What 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:
{{{
function source.chain(src, f)
return source.simplify(function()
local chunk, err = src()
if not chunk then return f(nil), source.empty(err)
else return f(chunk) end
end)
end
}}}
Our 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.
==Sinks==
Just 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.
{{{
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
local function null()
return 1
end
function sink.null()
return null
end
}}}
Sinks 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.
As 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.
{{{
local load = source.chain(source.file(io.stdin), normalize("\r\n"))
local store, t = sink.table()
while 1 do
local chunk = load()
store(chunk)
if not chunk then break end
end
print(table.concat(t))
}}}
Again, 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:
{{{
function sink.chain(f, snk)
return function(chunk, err)
local r, e = snk(f(chunk))
if not r then return nil, e end
if not chunk then return snk(nil, err) end
return 1
end
end
}}}
==Pumps==
There 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.
{{{
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
return chunk and ret and not src_err and not snk_err, src_err or snk_err
end
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then return not err, err end
end
end
}}}
The {{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:
{{{
local load = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64")
)
local store = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")),
)
pump.all(load, store)
}}}
The way we split the filters here is not intuitive, on purpose. Alternatively, we could have chained the Base64 encode filter and the line-wrap filter together, and then chain the resulting filter with either the file source or the file sink. It doesn't really matter.
===One last important change===
Turns 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.
More 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.
Most 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!
{{{
local function chain2(f1, f2)
local co = coroutine.create(function(chunk)
while true do
local filtered1 = f1(chunk)
local filtered2 = f2(filtered1)
local done2 = filtered1 and ""
while true do
if filtered2 == "" or filtered2 == nil then break end
coroutine.yield(filtered2)
filtered2 = f2(done2)
end
if filtered1 == "" then chunk = coroutine.yield(filtered1)
elseif filtered1 == nil then return nil
else chunk = chunk and "" end
end
end)
return function(chunk)
local _, res = coroutine.resume(co, chunk)
return res
end
end
}}}
Chaining 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.
===Final considerations===
These 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.
One 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.
In 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.

191
ltn013.md Normal file
View File

@ -0,0 +1,191 @@
# Using finalized exceptions
### or How to get rid of all those if statements
by DiegoNehab
## Abstract
This 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).
## Introduction
Most 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.
If 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.
Even 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?)
```lua
function task(arg1, arg2, ...)
local ret1, err = task1(arg1)
if not ret1 then
cleanup1()
return nil, error
end
local ret2, err = task2(arg2)
if not ret then
cleanup2()
return nil, error
end
...
end
```
The 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:
```lua
function task(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
```
If 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.
First, 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.
```lua
function xtask(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
function task(arg1, arg2, ...)
local ok, ret_or_err = pcall(xtask, arg1, arg2, ...)
if ok then return ret_or_err
else return nil, ret_or_err end
end
```
Our 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.
These are the main ideas for our exception scheme, but there are still a few glitches to fix:
* Directly using `pcall` ruined the simplicity of the code;
* What happened to the cleanup function calls? What if we have to, say, close a file?
* `Assert` messes with the error message before raising the error (it adds line number information).
Fortunately, all these problems are very easy to solve and that's what we do in the following sections.
## Introducing the `protect` factory
We used the `pcall` function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using `pcall` (and thus duplicating code) every time we prefer a factory that does the same job:
```lua
local function pack(ok, ...)
return ok, {...}
end
function protect(f)
return function(...)
local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret)
else return nil, ret[1] end
end
end
```
The `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:
```lua
task = protect(function(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end)
```
The 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.
```c
static int safecall(lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
lua_pushnil(L);
lua_insert(L, 1);
return 2;
} else return lua_gettop(L);
}
static int protect(lua_State *L) {
lua_pushcclosure(L, safecall, 1);
return 1;
}
```
## The `newtry` factory
Let'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.
```lua
get = protect(function(host, path)
local c
-- create a try function with a finalizer to close the socket
local try = newtry(function()
if c then c:close() end
end)
-- connect and send request
c = try(connect(host, 80))
try(c:send("GET " .. path .. " HTTP/1.0\r\n\r\n"))
-- get headers
local h = {}
while 1 do
l = try(c:receive())
if l == "" then break end
table.insert(h, l)
end
-- get body
local b = try(c:receive("*a"))
c:close()
return b, h
end)
```
The `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.
Even 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:
* We don't need to declare dummy variables to hold error messages in case any ever shows up;
* We avoid using a variable to hold something that could either be a return value or an error message;
* We didn't have to use several "if" statements to check for errors;
* If an error happens, we know our finalizer is going to be invoked automatically;
* Exceptions get propagated, so we don't repeat these "if" statements until the error reaches the user.
Try 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:
```lua
function newtry(f)
return function(...)
if not arg[1] then
if f then f() end
error(arg[2], 0)
else
return ...
end
end
end
```
Again, the implementation suffers from the creation of tables at each function call, so we prefer the C version:
```lua
static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, 0);
lua_settop(L, 2);
lua_error(L);
return 0;
} else return lua_gettop(L);
}
static int do_nothing(lua_State *L) {
(void) L;
return 0;
}
static int newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1))
lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
```
## Final considerations
The `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).

View File

@ -1,194 +0,0 @@
===Using finalized exceptions===
==or How to get rid of all those if statements==
by DiegoNehab
{{{
}}}
===Abstract===
This 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).
===Introduction===
Most 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.
If 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.
Even 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?)
{{{
function task(arg1, arg2, ...)
local ret1, err = task1(arg1)
if not ret1 then
cleanup1()
return nil, error
end
local ret2, err = task2(arg2)
if not ret then
cleanup2()
return nil, error
end
...
end
}}}
The 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:
{{{
function task(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
}}}
If 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.
First, 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.
{{{
function xtask(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
function task(arg1, arg2, ...)
local ok, ret_or_err = pcall(xtask, arg1, arg2, ...)
if ok then return ret_or_err
else return nil, ret_or_err end
end
}}}
Our 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.
These are the main ideas for our exception scheme, but there are still a few glitches to fix:
* Directly using {{pcall}} ruined the simplicity of the code;
* What happened to the cleanup function calls? What if we have to, say, close a file?
* {{Assert}} messes with the error message before raising the error (it adds line number information).
Fortunately, all these problems are very easy to solve and that's what we do in the following sections.
== Introducing the {{protect}} factory ==
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
{{{
local function pack(ok, ...)
return ok, {...}
end
function protect(f)
return function(...)
local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret)
else return nil, ret[1] end
end
end
}}}
The {{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:
{{{
task = protect(function(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end)
}}}
The 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.
{{{
static int safecall(lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
lua_pushnil(L);
lua_insert(L, 1);
return 2;
} else return lua_gettop(L);
}
static int protect(lua_State *L) {
lua_pushcclosure(L, safecall, 1);
return 1;
}
}}}
===The {{newtry}} factory===
Let'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.
{{{
get = protect(function(host, path)
local c
-- create a try function with a finalizer to close the socket
local try = newtry(function()
if c then c:close() end
end)
-- connect and send request
c = try(connect(host, 80))
try(c:send("GET " .. path .. " HTTP/1.0\r\n\r\n"))
-- get headers
local h = {}
while 1 do
l = try(c:receive())
if l == "" then break end
table.insert(h, l)
end
-- get body
local b = try(c:receive("*a"))
c:close()
return b, h
end)
}}}
The {{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.
Even 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:
* We don't need to declare dummy variables to hold error messages in case any ever shows up;
* We avoid using a variable to hold something that could either be a return value or an error message;
* We didn't have to use several ''if'' statements to check for errors;
* If an error happens, we know our finalizer is going to be invoked automatically;
* Exceptions get propagated, so we don't repeat these ''if'' statements until the error reaches the user.
Try 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:
{{{
function newtry(f)
return function(...)
if not arg[1] then
if f then f() end
error(arg[2], 0)
else
return ...
end
end
end
}}}
Again, the implementation suffers from the creation of tables at each function call, so we prefer the C version:
{{{
static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, 0);
lua_settop(L, 2);
lua_error(L);
return 0;
} else return lua_gettop(L);
}
static int do_nothing(lua_State *L) {
(void) L;
return 0;
}
static int newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1))
lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
}}}
===Final considerations===
The {{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}}.

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

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

View File

@ -33,6 +33,9 @@ install-both:
$(MAKE) clean $(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.3 @cd src; $(MAKE) $(PLAT) LUAV=5.3
@cd src; $(MAKE) install LUAV=5.3 @cd src; $(MAKE) install LUAV=5.3
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.4
@cd src; $(MAKE) install LUAV=5.4
install-both-unix: install-both-unix:
$(MAKE) clean $(MAKE) clean
@ -44,6 +47,9 @@ install-both-unix:
$(MAKE) clean $(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.3 @cd src; $(MAKE) $(PLAT) LUAV=5.3
@cd src; $(MAKE) install-unix LUAV=5.3 @cd src; $(MAKE) install-unix LUAV=5.3
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.4
@cd src; $(MAKE) install-unix LUAV=5.4
.PHONY: test .PHONY: test

View File

@ -1,7 +1,7 @@
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
# Distribution makefile # Distribution makefile
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
DIST = luasocket-3.0-rc1 DIST = luasocket-3.0.0
TEST = \ TEST = \
test/README \ test/README \
@ -22,20 +22,17 @@ SAMPLES = \
samples/lpr.lua \ samples/lpr.lua \
samples/talker.lua \ samples/talker.lua \
samples/tinyirc.lua samples/tinyirc.lua
samples/b64.lua \
ETC = \ samples/check-links.lua \
etc/README \ samples/check-memory.lua \
etc/b64.lua \ samples/dict.lua \
etc/check-links.lua \ samples/dispatch.lua \
etc/check-memory.lua \ samples/eol.lua \
etc/dict.lua \ samples/forward.lua \
etc/dispatch.lua \ samples/get.lua \
etc/eol.lua \ samples/lp.lua \
etc/forward.lua \ samples/qp.lua \
etc/get.lua \ samples/tftp.lua
etc/lp.lua \
etc/qp.lua \
etc/tftp.lua
SRC = \ SRC = \
src/makefile \ src/makefile \
@ -92,39 +89,36 @@ MAKE = \
socket.vcxproj \ socket.vcxproj \
mime.vcxproj mime.vcxproj
DOC = \ DOCS = \
doc/dns.html \ docs/dns.html \
doc/ftp.html \ docs/ftp.html \
doc/index.html \ docs/index.html \
doc/http.html \ docs/http.html \
doc/installation.html \ docs/installation.html \
doc/introduction.html \ docs/introduction.html \
doc/ltn12.html \ docs/ltn12.html \
doc/luasocket.png \ docs/luasocket.png \
doc/mime.html \ docs/mime.html \
doc/reference.css \ docs/reference.css \
doc/reference.html \ docs/reference.html \
doc/smtp.html \ docs/smtp.html \
doc/socket.html \ docs/socket.html \
doc/tcp.html \ docs/tcp.html \
doc/udp.html \ docs/udp.html \
doc/url.html docs/url.html
dist: dist:
mkdir -p $(DIST) mkdir -p $(DIST)
cp -vf NEW $(DIST) cp -vf CHANGELOG.md $(DIST)
cp -vf LICENSE $(DIST) cp -vf LICENSE $(DIST)
cp -vf README $(DIST) cp -vf README.md $(DIST)
cp -vf $(MAKE) $(DIST) cp -vf $(MAKE) $(DIST)
mkdir -p $(DIST)/etc
cp -vf $(ETC) $(DIST)/etc
mkdir -p $(DIST)/src mkdir -p $(DIST)/src
cp -vf $(SRC) $(DIST)/src cp -vf $(SRC) $(DIST)/src
mkdir -p $(DIST)/doc mkdir -p $(DIST)/docs
cp -vf $(DOC) $(DIST)/doc cp -vf $(DOCS) $(DIST)/docs
mkdir -p $(DIST)/samples mkdir -p $(DIST)/samples
cp -vf $(SAMPLES) $(DIST)/samples cp -vf $(SAMPLES) $(DIST)/samples

View File

@ -20,6 +20,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\mime.c" /> <ClCompile Include="src\mime.c" />
<ClCompile Include="src\compat.c" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid> <ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>

View File

@ -1,18 +1,18 @@
package = "LuaSocket" package = "LuaSocket"
version = "scm-2" version = "3.0.0-1"
source = { source = {
url = "git://github.com/diegonehab/luasocket.git" url = "git+https://github.com/lunarmodules/luasocket.git",
, branch="master" tag = "v3.0.0"
} }
description = { description = {
summary = "Network support for the Lua language", summary = "Network support for the Lua language",
detailed = [[ detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core LuaSocket is a Lua extension library composed of two parts: a set of C
that provides support for the TCP and UDP transport layers, and a set of Lua modules that provide support for the TCP and UDP transport layers, and a
modules that add support for functionality commonly needed by applications set of Lua modules that provide functions commonly needed by applications
that deal with the Internet. that deal with the Internet.
]], ]],
homepage = "http://luaforge.net/projects/luasocket/", homepage = "https://github.com/lunarmodules/luasocket",
license = "MIT" license = "MIT"
} }
dependencies = { dependencies = {
@ -127,7 +127,7 @@ build = {
mingw32 = make_plat("mingw32") mingw32 = make_plat("mingw32")
}, },
copy_directories = { copy_directories = {
"doc" "docs"
, "samples" , "samples"
, "etc" , "etc"
, "test" } , "test" }

View File

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

View File

@ -1,18 +1,18 @@
package = "LuaSocket" package = "LuaSocket"
version = "3.0rc2-1" version = "3.1.0-1"
source = { source = {
url = "git://github.com/diegonehab/luasocket.git", url = "git+https://github.com/lunarmodules/luasocket.git",
tag = "v3.0-rc2", tag = "v3.1.0"
} }
description = { description = {
summary = "Network support for the Lua language", summary = "Network support for the Lua language",
detailed = [[ detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core LuaSocket is a Lua extension library composed of two parts: a set of C
that provides support for the TCP and UDP transport layers, and a set of Lua modules that provide support for the TCP and UDP transport layers, and a
modules that add support for functionality commonly needed by applications set of Lua modules that provide functions commonly needed by applications
that deal with the Internet. that deal with the Internet.
]], ]],
homepage = "http://luaforge.net/projects/luasocket/", homepage = "https://github.com/lunarmodules/luasocket",
license = "MIT" license = "MIT"
} }
dependencies = { dependencies = {
@ -34,7 +34,7 @@ local function make_plat(plat)
}, },
mingw32 = { mingw32 = {
"LUASOCKET_DEBUG", "LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON", -- "LUASOCKET_INET_PTON",
"WINVER=0x0501" "WINVER=0x0501"
} }
} }
@ -113,6 +113,7 @@ local function make_plat(plat)
then then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c" modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" } modules["socket.core"].libraries = { "ws2_32" }
modules["socket.core"].libdirs = {}
end end
return { modules = modules } return { modules = modules }
end end
@ -127,7 +128,7 @@ build = {
mingw32 = make_plat("mingw32") mingw32 = make_plat("mingw32")
}, },
copy_directories = { copy_directories = {
"doc" "docs"
, "samples" , "samples"
, "etc" , "etc"
, "test" } , "test" }

View File

@ -1,6 +1,90 @@
This directory contains some sample programs using This directory contains some sample programs using
LuaSocket. This code is not supported. LuaSocket. This code is not supported.
tftp.lua -- Trivial FTP client
This module implements file retrieval by the TFTP protocol.
Its main use was to test the UDP code, but since someone
found it usefull, I turned it into a module that is almost
official (no uploads, yet).
dict.lua -- Dict client
The dict.lua module started with a cool simple client
for the DICT protocol, written by Luiz Henrique Figueiredo.
This new version has been converted into a library, similar
to the HTTP and FTP libraries, that can be used from within
any luasocket application. Take a look on the source code
and you will be able to figure out how to use it.
lp.lua -- LPD client library
The lp.lua module implements the client part of the Line
Printer Daemon protocol, used to print files on Unix
machines. It is courtesy of David Burgess! See the source
code and the lpr.lua in the examples directory.
b64.lua
qp.lua
eol.lua
These are tiny programs that perform Base64,
Quoted-Printable and end-of-line marker conversions.
get.lua -- file retriever
This little program is a client that uses the FTP and
HTTP code to implement a command line file graber. Just
run
lua get.lua <remote-file> [<local-file>]
to download a remote file (either ftp:// or http://) to
the specified local file. The program also prints the
download throughput, elapsed time, bytes already downloaded
etc during download.
check-memory.lua -- checks memory consumption
This is just to see how much memory each module uses.
dispatch.lua -- coroutine based dispatcher
This is a first try at a coroutine based non-blocking
dispatcher for LuaSocket. Take a look at 'check-links.lua'
and at 'forward.lua' to see how to use it.
check-links.lua -- HTML link checker program
This little program scans a HTML file and checks for broken
links. It is similar to check-links.pl by Jamie Zawinski,
but uses all facilities of the LuaSocket library and the Lua
language. It has not been thoroughly tested, but it should
work. Just run
lua check-links.lua [-n] {<url>} > output
and open the result to see a list of broken links. Make sure
you check the '-n' switch. It runs in non-blocking mode,
using coroutines, and is MUCH faster!
forward.lua -- coroutine based forward server
This is a forward server that can accept several connections
and transfers simultaneously using non-blocking I/O and the
coroutine-based dispatcher. You can run, for example
lua forward.lua 8080:proxy.com:3128
to redirect all local conections to port 8080 to the host
'proxy.com' at port 3128.
unix.c and unix.h
This is an implementation of Unix local domain sockets and
demonstrates how to extend LuaSocket with a new type of
transport. It has been tested on Linux and on Mac OS X.
listener.lua -- socket to stdout listener.lua -- socket to stdout
talker.lua -- stdin to socket talker.lua -- stdin to socket
@ -17,7 +101,7 @@ be printed by listen.lua.
This is a cool program written by David Burgess to print This is a cool program written by David Burgess to print
files using the Line Printer Daemon protocol, widely used in files using the Line Printer Daemon protocol, widely used in
Unix machines. It uses the lp.lua implementation, in the Unix machines. It uses the lp.lua implementation, in the
etc directory. Just run 'lua lpr.lua <filename> samples directory. Just run 'lua lpr.lua <filename>
queue=<printername>' and the file will print! queue=<printername>' and the file will print!
cddb.lua -- CDDB client cddb.lua -- CDDB client

View File

@ -14,7 +14,7 @@ end
local function parse_set_cookie(c, quoted, cookie_table) local function parse_set_cookie(c, quoted, cookie_table)
c = c .. ";$last=last;" c = c .. ";$last=last;"
local _, __, n, v, i = string.find(c, "(" .. token_class .. local _, _, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=%s*(.-)%s*;%s*()") "+)%s*=%s*(.-)%s*;%s*()")
local cookie = { local cookie = {
name = n, name = n,
@ -22,7 +22,7 @@ local function parse_set_cookie(c, quoted, cookie_table)
attributes = {} attributes = {}
} }
while 1 do while 1 do
_, __, n, v, i = string.find(c, "(" .. token_class .. _, _, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=?%s*(.-)%s*;%s*()", i) "+)%s*=?%s*(.-)%s*;%s*()", i)
if not n or n == "$last" then break end if not n or n == "$last" then break end
cookie.attributes[#cookie.attributes+1] = { cookie.attributes[#cookie.attributes+1] = {
@ -46,8 +46,8 @@ local function split_set_cookie(s, cookie_table)
-- split into individual cookies -- split into individual cookies
i = 1 i = 1
while 1 do while 1 do
local _, __, cookie, next_token local _, _, cookie, next_token
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" .. _, _, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
token_class .. "+)%s*=", i) token_class .. "+)%s*=", i)
if not next_token then break end if not next_token then break end
parse_set_cookie(cookie, quoted, cookie_table) parse_set_cookie(cookie, quoted, cookie_table)

View File

@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="src\auxiliar.c" /> <ClCompile Include="src\auxiliar.c" />
<ClCompile Include="src\buffer.c" /> <ClCompile Include="src\buffer.c" />
<ClCompile Include="src\compat.c" />
<ClCompile Include="src\except.c" /> <ClCompile Include="src\except.c" />
<ClCompile Include="src\inet.c" /> <ClCompile Include="src\inet.c" />
<ClCompile Include="src\io.c" /> <ClCompile Include="src\io.c" />

View File

@ -103,11 +103,14 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
* object:receive() interface * object:receive() interface
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int buffer_meth_receive(lua_State *L, p_buffer buf) { int buffer_meth_receive(lua_State *L, p_buffer buf) {
int err = IO_DONE, top = lua_gettop(L); int err = IO_DONE, top;
luaL_Buffer b; luaL_Buffer b;
size_t size; size_t size;
const char *part = luaL_optlstring(L, 3, "", &size); const char *part = luaL_optlstring(L, 3, "", &size);
timeout_markstart(buf->tm); timeout_markstart(buf->tm);
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
top = lua_gettop(L);
/* initialize buffer with optional extra prefix /* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */ * (useful for concatenating previous partial results) */
luaL_buffinit(L, &b); luaL_buffinit(L, &b);

View File

@ -56,7 +56,7 @@ end
function metat.__index:login(user, password) function metat.__index:login(user, password)
self.try(self.tp:command("user", user or _M.USER)) self.try(self.tp:command("user", user or _M.USER))
local code, reply = self.try(self.tp:check{"2..", 331}) local code, _ = self.try(self.tp:check{"2..", 331})
if code == 331 then if code == 331 then
self.try(self.tp:command("pass", password or _M.PASSWORD)) self.try(self.tp:command("pass", password or _M.PASSWORD))
self.try(self.tp:check("2..")) self.try(self.tp:check("2.."))
@ -66,7 +66,7 @@ end
function metat.__index:pasv() function metat.__index:pasv()
self.try(self.tp:command("pasv")) self.try(self.tp:command("pasv"))
local code, reply = self.try(self.tp:check("2..")) local _, reply = self.try(self.tp:check("2.."))
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
self.try(a and b and c and d and p1 and p2, reply) self.try(a and b and c and d and p1 and p2, reply)
@ -83,9 +83,9 @@ end
function metat.__index:epsv() function metat.__index:epsv()
self.try(self.tp:command("epsv")) self.try(self.tp:command("epsv"))
local code, reply = self.try(self.tp:check("229")) local _, reply = self.try(self.tp:check("229"))
local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)" local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
local d, prt, address, port = string.match(reply, pattern) local _, _, _, port = string.match(reply, pattern)
self.try(port, "invalid epsv response") self.try(port, "invalid epsv response")
self.pasvt = { self.pasvt = {
address = self.tp:getpeername(), address = self.tp:getpeername(),
@ -102,7 +102,7 @@ end
function metat.__index:port(address, port) function metat.__index:port(address, port)
self.pasvt = nil self.pasvt = nil
if not address then if not address then
address, port = self.try(self.tp:getsockname()) address = self.try(self.tp:getsockname())
self.server = self.try(socket.bind(address, 0)) self.server = self.try(socket.bind(address, 0))
address, port = self.try(self.server:getsockname()) address, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(_M.TIMEOUT)) self.try(self.server:settimeout(_M.TIMEOUT))
@ -118,7 +118,7 @@ end
function metat.__index:eprt(family, address, port) function metat.__index:eprt(family, address, port)
self.pasvt = nil self.pasvt = nil
if not address then if not address then
address, port = self.try(self.tp:getsockname()) address = self.try(self.tp:getsockname())
self.server = self.try(socket.bind(address, 0)) self.server = self.try(socket.bind(address, 0))
address, port = self.try(self.server:getsockname()) address, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(_M.TIMEOUT)) self.try(self.server:settimeout(_M.TIMEOUT))
@ -142,7 +142,7 @@ function metat.__index:send(sendt)
local command = sendt.command or "stor" local command = sendt.command or "stor"
-- send the transfer command and check the reply -- send the transfer command and check the reply
self.try(self.tp:command(command, argument)) self.try(self.tp:command(command, argument))
local code, reply = self.try(self.tp:check{"2..", "1.."}) local code, _ = self.try(self.tp:check{"2..", "1.."})
-- if there is not a pasvt table, then there is a server -- if there is not a pasvt table, then there is a server
-- and we already sent a PORT command -- and we already sent a PORT command
if not self.pasvt then self:portconnect() end if not self.pasvt then self:portconnect() end

View File

@ -41,9 +41,6 @@ local SCHEMES = {
https.tcp, 'LuaSocket: Function tcp() not available from LuaSec') https.tcp, 'LuaSocket: Function tcp() not available from LuaSec')
return tcp(t) end }} return tcp(t) end }}
-- default scheme and port for document retrieval
local SCHEME = 'http'
local PORT = SCHEMES[SCHEME].port
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed -- Reads MIME headers from a connection, unfolding where needed
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@ -92,7 +89,7 @@ socket.sourcet["http-chunked"] = function(sock, headers)
-- was it the last chunk? -- was it the last chunk?
if size > 0 then if size > 0 then
-- if not, get chunk and skip terminating CRLF -- if not, get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size) local chunk, err, _ = sock:receive(size)
if chunk then sock:receive() end if chunk then sock:receive() end
return chunk, err return chunk, err
else else
@ -286,6 +283,13 @@ local function adjustrequest(reqt)
nreqt.uri = reqt.uri or adjusturi(nreqt) nreqt.uri = reqt.uri or adjusturi(nreqt)
-- adjust headers in request -- adjust headers in request
nreqt.headers = adjustheaders(nreqt) nreqt.headers = adjustheaders(nreqt)
if nreqt.source
and not nreqt.headers["content-length"]
and not nreqt.headers["transfer-encoding"]
then
nreqt.headers["transfer-encoding"] = "chunked"
end
-- ajust host and port if there is a proxy -- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt) nreqt.host, nreqt.port = adjustproxy(nreqt)
return nreqt return nreqt
@ -296,6 +300,8 @@ local function shouldredirect(reqt, code, headers)
if not location then return false end if not location then return false end
location = string.gsub(location, "%s", "") location = string.gsub(location, "%s", "")
if location == "" then return false end if location == "" then return false end
-- the RFC says the redirect URL may be relative
location = url.absolute(reqt.url, location)
local scheme = url.parse(location).scheme local scheme = url.parse(location).scheme
if scheme and (not SCHEMES[scheme]) then return false end if scheme and (not SCHEMES[scheme]) then return false end
-- avoid https downgrades -- avoid https downgrades
@ -319,8 +325,7 @@ end
local trequest, tredirect local trequest, tredirect
--[[local]] function tredirect(reqt, location) --[[local]] function tredirect(reqt, location)
-- the RFC says the redirect URL has to be absolute, but some -- the RFC says the redirect URL may be relative
-- servers do not respect that
local newurl = url.absolute(reqt.url, location) local newurl = url.absolute(reqt.url, location)
-- if switching schemes, reset port and create function -- if switching schemes, reset port and create function
if url.parse(newurl).scheme ~= reqt.scheme then if url.parse(newurl).scheme ~= reqt.scheme then
@ -366,7 +371,7 @@ end
local headers local headers
-- ignore any 100-continue messages -- ignore any 100-continue messages
while code == 100 do while code == 100 do
headers = h:receiveheaders() h:receiveheaders()
code, status = h:receivestatusline() code, status = h:receivestatusline()
end end
headers = h:receiveheaders() headers = h:receiveheaders()

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

@ -253,7 +253,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if (err) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, gai_strerror(err)); lua_pushstring(L, LUA_GAI_STRERROR(err));
return 2; return 2;
} }
lua_pushstring(L, name); lua_pushstring(L, name);
@ -286,11 +286,11 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, gai_strerror(err)); lua_pushstring(L, LUA_GAI_STRERROR(err));
return 2; return 2;
} }
lua_pushstring(L, name); lua_pushstring(L, name);
lua_pushstring(L, port); lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
switch (family) { switch (family) {
case AF_INET: lua_pushliteral(L, "inet"); break; case AF_INET: lua_pushliteral(L, "inet"); break;
case AF_INET6: lua_pushliteral(L, "inet6"); break; case AF_INET6: lua_pushliteral(L, "inet6"); break;

View File

@ -11,9 +11,11 @@ local string = require("string")
local table = require("table") local table = require("table")
local unpack = unpack or table.unpack local unpack = unpack or table.unpack
local base = _G local base = _G
local select = select
local _M = {} local _M = {}
if module then -- heuristic for exporting a global package table if module then -- heuristic for exporting a global package table
ltn12 = _M ltn12 = _M -- luacheck: ignore
end end
local filter,source,sink,pump = {},{},{},{} local filter,source,sink,pump = {},{},{},{}
@ -22,9 +24,6 @@ _M.source = source
_M.sink = sink _M.sink = sink
_M.pump = pump _M.pump = pump
local unpack = unpack or table.unpack
local select = base.select
-- 2048 seems to be better in windows... -- 2048 seems to be better in windows...
_M.BLOCKSIZE = 2048 _M.BLOCKSIZE = 2048
_M._VERSION = "LTN12 1.0.3" _M._VERSION = "LTN12 1.0.3"
@ -46,7 +45,7 @@ end
-- (thanks to Wim Couwenberg) -- (thanks to Wim Couwenberg)
function filter.chain(...) function filter.chain(...)
local arg = {...} local arg = {...}
local n = base.select('#',...) local n = select('#',...)
local top, index = 1, 1 local top, index = 1, 1
local retry = "" local retry = ""
return function(chunk) return function(chunk)

View File

@ -10,7 +10,7 @@
/*-------------------------------------------------------------------------* \ /*-------------------------------------------------------------------------* \
* Current socket library version * Current socket library version
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 3.0-rc1" #define LUASOCKET_VERSION "LuaSocket 3.0.0"
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" #define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\

View File

@ -16,7 +16,7 @@
# platform to build for # platform to build for
PLAT?=linux PLAT?=linux
# LUAV: 5.1 5.2 # LUAV: 5.1 5.2 5.3 5.4
# lua version to build against # lua version to build against
LUAV?=5.1 LUAV?=5.1
@ -272,7 +272,7 @@ SOCKET_win64=wsocket.obj
# #
SO=$(SO_$(PLAT)) SO=$(SO_$(PLAT))
O=$(O_$(PLAT)) O=$(O_$(PLAT))
SOCKET_V=3.0-rc1 SOCKET_V=3.0.0
MIME_V=1.0.3 MIME_V=1.0.3
SOCKET_SO=socket-$(SOCKET_V).$(SO) SOCKET_SO=socket-$(SOCKET_V).$(SO)
MIME_SO=mime-$(MIME_V).$(SO) MIME_SO=mime-$(MIME_V).$(SO)

View File

@ -1,7 +1,7 @@
local _M = {} local _M = {}
if module then if module then
mbox = _M mbox = _M -- luacheck: ignore
end end
function _M.split_message(message_s) function _M.split_message(message_s)
@ -29,7 +29,7 @@ end
function _M.parse_header(header_s) function _M.parse_header(header_s)
header_s = string.gsub(header_s, "\n[ ]+", " ") header_s = string.gsub(header_s, "\n[ ]+", " ")
header_s = string.gsub(header_s, "\n+", "") header_s = string.gsub(header_s, "\n+", "")
local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") local _, _, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
return name, value return name, value
end end
@ -49,9 +49,9 @@ function _M.parse_headers(headers_s)
end end
function _M.parse_from(from) function _M.parse_from(from)
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") local _, _, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
if not address then if not address then
_, __, address = string.find(from, "%s*(.+)%s*") _, _, address = string.find(from, "%s*(.+)%s*")
end end
name = name or "" name = name or ""
address = address or "" address = address or ""
@ -63,7 +63,8 @@ end
function _M.split_mbox(mbox_s) function _M.split_mbox(mbox_s)
local mbox = {} local mbox = {}
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
local nj, i, j = 1, 1, 1 local nj, i
local j = 1
while 1 do while 1 do
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
if not i then break end if not i then break end

View File

@ -27,12 +27,12 @@ static int mime_global_eol(lua_State *L);
static int mime_global_dot(lua_State *L); static int mime_global_dot(lua_State *L);
static size_t dot(int c, size_t state, luaL_Buffer *buffer); static size_t dot(int c, size_t state, luaL_Buffer *buffer);
//static void b64setup(UC *base); /*static void b64setup(UC *base);*/
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
//static void qpsetup(UC *class, UC *unbase); /*static void qpsetup(UC *class, UC *unbase);*/
static void qpquote(UC c, luaL_Buffer *buffer); static void qpquote(UC c, luaL_Buffer *buffer);
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t qpencode(UC c, UC *input, size_t size, static size_t qpencode(UC c, UC *input, size_t size,
@ -176,8 +176,8 @@ LUASOCKET_API int luaopen_mime_core(lua_State *L)
lua_pushstring(L, MIME_VERSION); lua_pushstring(L, MIME_VERSION);
lua_rawset(L, -3); lua_rawset(L, -3);
/* initialize lookup tables */ /* initialize lookup tables */
// qpsetup(qpclass, qpunbase); /*qpsetup(qpclass, qpunbase);*/
// b64setup(b64unbase); /*b64setup(b64unbase);*/
return 1; return 1;
} }

View File

@ -10,7 +10,6 @@
local base = _G local base = _G
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
local mime = require("mime.core") local mime = require("mime.core")
local string = require("string")
local _M = mime local _M = mime
-- encode, decode and wrap algorithm tables -- encode, decode and wrap algorithm tables
@ -52,13 +51,6 @@ decodet['quoted-printable'] = function()
return ltn12.filter.cycle(_M.unqp, "") return ltn12.filter.cycle(_M.unqp, "")
end end
local function format(chunk)
if chunk then
if chunk == "" then return "''"
else return string.len(chunk) end
else return "nil" end
end
-- define the line-wrap filters -- define the line-wrap filters
wrapt['text'] = function(length) wrapt['text'] = function(length)
length = length or 76 length = length or 76

View File

@ -54,7 +54,34 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
return opt->func(L, ps); return opt->func(L, ps);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
/* binds socket to network interface */
int opt_set_bindtodevice(lua_State *L, p_socket ps)
{
#ifndef SO_BINDTODEVICE
return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
#else
const char *dev = luaL_checkstring(L, 3);
return opt_set(L, ps, SOL_SOCKET, SO_BINDTODEVICE, (char*)dev, strlen(dev)+1);
#endif
}
int opt_get_bindtodevice(lua_State *L, p_socket ps)
{
#ifndef SO_BINDTODEVICE
return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
#else
char dev[IFNAMSIZ];
int len = sizeof(dev);
int err = opt_get(L, ps, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len);
if (err)
return err;
lua_pushstring(L, dev);
return 1;
#endif
}
/*------------------------------------------------------*/
/* enables reuse of local address */ /* enables reuse of local address */
int opt_set_reuseaddr(lua_State *L, p_socket ps) int opt_set_reuseaddr(lua_State *L, p_socket ps)
{ {
@ -66,7 +93,7 @@ int opt_get_reuseaddr(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
/* enables reuse of local port */ /* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps) int opt_set_reuseport(lua_State *L, p_socket ps)
{ {
@ -78,7 +105,7 @@ int opt_get_reuseport(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
/* disables the Nagle algorithm */ /* disables the Nagle algorithm */
int opt_set_tcp_nodelay(lua_State *L, p_socket ps) int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{ {
@ -90,7 +117,7 @@ int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
#ifdef TCP_KEEPIDLE #ifdef TCP_KEEPIDLE
int opt_get_tcp_keepidle(lua_State *L, p_socket ps) int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
@ -105,7 +132,7 @@ int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
#endif #endif
// ------------------------------------------------------- /*------------------------------------------------------*/
#ifdef TCP_KEEPCNT #ifdef TCP_KEEPCNT
int opt_get_tcp_keepcnt(lua_State *L, p_socket ps) int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
@ -120,7 +147,7 @@ int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
#endif #endif
// ------------------------------------------------------- /*------------------------------------------------------*/
#ifdef TCP_KEEPINTVL #ifdef TCP_KEEPINTVL
int opt_get_tcp_keepintvl(lua_State *L, p_socket ps) int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
@ -135,7 +162,7 @@ int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
#endif #endif
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_keepalive(lua_State *L, p_socket ps) int opt_set_keepalive(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
@ -146,7 +173,7 @@ int opt_get_keepalive(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_dontroute(lua_State *L, p_socket ps) int opt_set_dontroute(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
@ -157,7 +184,7 @@ int opt_get_dontroute(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_broadcast(lua_State *L, p_socket ps) int opt_set_broadcast(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
@ -168,7 +195,7 @@ int opt_get_broadcast(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_recv_buf_size(lua_State *L, p_socket ps) int opt_set_recv_buf_size(lua_State *L, p_socket ps)
{ {
return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF); return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
@ -179,7 +206,7 @@ int opt_get_recv_buf_size(lua_State *L, p_socket ps)
return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF); return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_get_send_buf_size(lua_State *L, p_socket ps) int opt_get_send_buf_size(lua_State *L, p_socket ps)
{ {
return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF); return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
@ -190,7 +217,32 @@ int opt_set_send_buf_size(lua_State *L, p_socket ps)
return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF); return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
#ifdef TCP_FASTOPEN
int opt_set_tcp_fastopen(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN);
}
#endif
#ifdef TCP_FASTOPEN_CONNECT
int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT);
}
#endif
/*------------------------------------------------------*/
#ifdef TCP_DEFER_ACCEPT
int opt_set_tcp_defer_accept(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT);
}
#endif
/*------------------------------------------------------*/
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
{ {
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
@ -201,7 +253,7 @@ int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
{ {
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
@ -212,7 +264,7 @@ int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
@ -223,7 +275,7 @@ int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
{ {
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
@ -234,7 +286,7 @@ int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_linger(lua_State *L, p_socket ps) int opt_set_linger(lua_State *L, p_socket ps)
{ {
struct linger li; /* obj, name, table */ struct linger li; /* obj, name, table */
@ -267,13 +319,13 @@ int opt_get_linger(lua_State *L, p_socket ps)
return 1; return 1;
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{ {
return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip_multicast_if(lua_State *L, p_socket ps) int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
{ {
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
@ -298,7 +350,7 @@ int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
return 1; return 1;
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip_add_membership(lua_State *L, p_socket ps) int opt_set_ip_add_membership(lua_State *L, p_socket ps)
{ {
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
@ -309,7 +361,7 @@ int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_set_ip6_add_membership(lua_State *L, p_socket ps) int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
{ {
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
@ -319,7 +371,8 @@ int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
{ {
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
} }
// -------------------------------------------------------
/*------------------------------------------------------*/
int opt_get_ip6_v6only(lua_State *L, p_socket ps) int opt_get_ip6_v6only(lua_State *L, p_socket ps)
{ {
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
@ -330,7 +383,7 @@ int opt_set_ip6_v6only(lua_State *L, p_socket ps)
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
} }
// ------------------------------------------------------- /*------------------------------------------------------*/
int opt_get_error(lua_State *L, p_socket ps) int opt_get_error(lua_State *L, p_socket ps)
{ {
int val = 0; int val = 0;

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