|
| LuaSocket |
| IPv4 Socket support for the Lua language |
LuaSocket is a Lua extension library that provides support for TCP and UDP socket layer within the Lua language. The library also provides support for SMTP (sending e-mails), HTTP (www) and FTP (uploading and downloading files).
It can be used by any Lua application desiring access to network communication on the Internet, once it has been properly linked with and initialized by the interpreter running the application. The code has been tested and runs well both on Windows and on Unix Platforms.
The library is available under the same terms as the Lua language, that is, it can be used at no cost for both academic and commercial purposes.
Copyright (C) 2000 TeCGraf, PUC-Rio. All rights reserved.
Author: Diego Nehab
Below is a little introduction on how to get the library up and running with your applications and a little introduction on network programming with LuaSocket.
To have the library functions made available to a Lua script, the interpreter running the script must be linked to the luasocket library, and to whatever libraries the OS in use requires for socket programming. The functions are registered in the Lua state given as the parameter to the function lua_socketlibopen, the only C function exported by the library. The scripts can then use all registered functions.
Bringing network support into the Lua language brings out the choice between having an API similar to the C socket API or creating a new transport layer abstraction. Having an API similar to the C API would make things easier for those used to socket programming. On the other hand, the simplicity of the Lua language would be lost. We ended up with something in between.
One of the major differences the API is the timeout control provided by the library. All I/O operations are blocking by default. In other words, the send, receive and accept functions will block the caller application until the operation is completed (if ever). The application can, however, specify upper limits on the time it can be blocked by LuaSocket ("return" timeout), or it can specify a time limit on the time LuaSocket can be blocked by the OS ("blocked" timeout) or a combination of the two. Remember that each LuaSocket call performs several OS calls, so that the two timeout values are not equivalent.
Another major difference is the receive pattern capability. Applications can read data from a TCP client socket line by line, chunk by chunk or until the connection is closed. All I/O reads are buffered and the performance difference between different receive patterns is negligible.
Finally, most functions accept both IP addresses and host names. In case a host name is given, the library queries the resolver and tries all returned IP addresses until one succeeds or all fail. IP addresses are directly encoded and are therefore more efficient. The toip and tohostname functions are provided to convert between host names and IP addresses.
Socket objects are represented as tables in the Lua language. Different socket types accept different operations. These operations are available both as stand-alone global functions and as table methods of the socket objects. For example, the function call send(socket,"test") is equivalent to the function call socket:send("test"), where socket is a client socket object.
TCP programming
TCP is a reliable stream protocol. In other words, applications send and
receive data as an error free stream of bytes. Data is split in one end
and reassembled transparently on the other end. There are no boundaries
in the data transfers. The library distinguishes two types of TCP
sockets: client sockets and server sockets.
Client sockets are used to exchange data between two applications over
the Internet. Client sockets are created by the connect
function or returned by the accept server socket method.
Applications can call the methods send and receive to
send and receive data. The other methods available for client socket
objects are timeout and close.
Server sockets are created by the bind function and are
associated with a address and port on a the local. Applications use the
accept method to wait for a client connection on a server
socket. Once a connection is established, a client socket object is
returned representing this connection. The other methods available for
server socket objects are getsockname, getpeername,
timeout and close.
UDP programming
UDP is a non-reliable datagram protocol. In other words, applications
send and receive data as independent blocks, which are not guaranteed to
reach the other end. Even when they reach the other side, they are not
guaranteed to be error free. Data transfers are atomic, sending or
receiving one datagram at a time. Reading only part of a datagram
discards the rest, so that the next read operation will act on a
different datagram. The gain lies in simplicity and performance.
An UDP socket object is created by the udpcreate function. UDP
sockets do not need to be connected before use. The method
sendto can be used immediately after creation to send a
datagram to any UDP (ip, port) pair. Host names are not allowed for
performance reasons. Methods receive and receivefrom
can be used to retrieve datagrams, the latter returning the ip and port
of the sender as extra return values.
When communication is performed with a single peer, an application can
call the setpeername method to specify a partner. The method
send can be used to send data directly to the peer, and methods
receive and receivefrom only return datagrams
originating from that peer. There is about 30% performance gain due to
this practice.
To associate an UDP socket with a local address, an application calls
the setsockname function. The other methods available for UDP
sockets are getpeername, getsockname, timeout
and close.
LuaSocket version 1.2 is now available for download! It is compatible
with Lua 4.0 and has been tested on Windows 98,
Windows 2000, Linux, AIX, and SunOS.
There have been some improvements since version 1.1, mainly
motivated by feedback from the Lua community:
There server method listen has been removed from the library.
The backlog server socket value, when the default value of 1 is
not satisfactory, MUST be assigned at bind time.
The library can be downloaded in source code here:
luasocket-1.2.tar.gz
All the functions of the API are described below. Several examples are
given in the distribution, including the automated tests and the full
implementation of the protocols FTP, SMTP and HTTP.
Note that although some function names are overloaded, documentation is
provided separately for TCP and UDP sockets.
accept(socket)
Creates and returns a TCP client socket object, representing a client
attempting connection on the server socket. The function blocks
until a remote connection attempt is detected or until the timeout
condition is met.
bind(address, port [, backlog])
Creates a new TCP server socket and binds it to (address,
port) on the local host. Address can be an IP address
or a host name. If address is '*', the system binds to
all local interfaces (INADDR_ANY). If port is 0, the
system automatically chooses an ephemeral port. The optional parameter
backlog (default value 1) specifies the number of client
connections that can be queued waiting for service. If the queue is full
and another client attempts connection, the connection is refused. In
case of success, the function returns a server socket, on which the
operations accept, close, getsockname and
listen are permitted. In case of error, the function returns
nil followed by a string describing the error.
close(socket)
Closes the socket socket. No further operations are allowed on
a closed socket. The local address to which it is bound is made
available to other applications.
Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor,
which are a limited system resource.
connect(address, port)
Creates a new TCP client socket and tries to connect to
(address, port). Address can be an IP address
or a host name. In case of success, the function returns a client socket
on which the operations send, receive and
close are permitted. In case of error, the function returns
nil followed by a string describing the error.
getpeername(socket)
Returns the IP address and port of the peer connected to the TCP client
socket or nil in case of error. Note that it makes no
sense to call getpeername on a server socket object.
poll(socket, operation)
Determines if socket is ready for operation, which can be:
Important Note: a know bug in WinSock prevents poll from
working properly on non-blocking TCP sockets. The function may return 1
on operation '*s' when the socket is not ready for
sending.
Note: simply calling poll with operation '*r' on a
server socket before a call to accept does not guarantee accept
will return. Use the timeout server socket method instead,
which DOES guarantee that.
getsockname(socket)
Returns the local IP address and port of the TCP socket
or nil in case of error.
receive(socket [, pattern1, pattern2, ... patternN])
Receives pattern1, pattern2, ...
patternN from the client socket. A pattern
can be one of the following:
send(socket, string1 [, string2, ... stringN])
Sends the strings string1,
string2, ... stringN through the
client socket socket. The function returns an error code, which
is nil in case of success, the string 'closed' in case
the connection was closed before the transmission was complete or the
string 'timeout' in case there was a timeout during the
operation. After the error code, the function returns the number of
bytes accepted by the transport layer.
timeout(socket, value [, mode])
Changes the timeout values for the socket socket. By default,
all I/O operations are blocking. That is, any call to the functions
send and receive will block indefinitely, until the
operation completes. The timeout function defines a limit on
the amount of time the functions can block, specified as the
value parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning:
Note: although timeout values have millisecond precision, 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 kernel and to and from the
Lua interpreter.
close(socket)
Closes the socket socket. No further operations are allowed on
a closed socket. The local address to which it is bound is made
available to other applications.
Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor,
which are a limited system resource.
getpeername(socket)
Returns the IP address and port of the peer of the UDP socket.
The function will fail unless a peer has been set with a call to
setpeername.
getsockname(socket)
Returns the local IP address and port of the TCP socket
or nil in case of error.
Note: UDP sockets are not bound to any address until
setsockname or the first sendto method is called (in
which case it is bound to an ephemeral port and the wildcard address).
The local address will not change thereafter.
poll(socket, operation)
Determines if socket is ready for operation, which can be:
receive(socket [, number])
Receives a datagram from the UDP socket socket with up to
number bytes. If there are more than number bytes
available in the datagram, the remaining are discarded. If there are
less then number bytes available in the current datagram, the
available bytes are returned. If number is omitted, the maximum
datagram size is used. In case of timeout, the function returns
nil followed by the string 'timeout'. In case the
transmission failed, the function returns nil followed by the
string 'refused'.
receivefrom(socket [, number])
Works exactly as the receive function, except it returns the
sender ip and port as extra return values and
therefore is slightly less efficient.
send(socket, string)
Sends string to the UDP peer of socket socket. The
method setpeername MUST have been called on socket. If
successful, the function returns nil. In case of timeout, the
function returns the string 'timeout'. In case the transmission
failed, the function returns the string 'refused'.
sendto(socket, string, ip, port)
Sends string to (ip, port). In case of
timeout, the function returns the string 'timeout'. Ip
MUST be an IP address, for performance reasons. In case the transmission
failed, the function returns the string 'refused'.
setpeername(socket, address, port)
Sets the socket UDP peer to (address, port).
Address can be an IP address or a host name. After a call to
setpeername, the send and receive MUST be
used instead of sendto and receivefrom. Outgoing
datagrams will be sent to the specified peer, and datagrams received
from other peers will be discarded by the OS. Since the address of the
peer does not have to be passed to and from the OS, this practice is
recommended when the same peer is used for several transmissions and can
lead to up to 30% performance gains.
setsockname(socket, address, port)
Binds the UDP socket to a local address (address,
port). Address can be an IP address or a host name. If
address is '*' the system binds to all local
interfaces (INADDR_ANY). If port is 0, the system
chooses an ephemeral port. If successful, the function returns
nil. In case of error, the function returns an error message.
timeout(socket, value)
Changes the timeout value for the socket socket. By default,
all operations are blocking. The timeout function defines a
limit on the amount of time the functions can block, specified as the
value parameter, in seconds. The nil timeout
value allows operations to block indefinitely. Negative timeout
values have the same effect.
Note: there is no send buffer on an UDP socket. Therefore, a send
operation on an UDP socket should never block, regardless of the timeout
value. Receive operations, however, can block the application.
udpsocket()
Creates and returns an UDP socket object, on which the methods
close, getpeername, getsockname,
receive, receivefrom, send, sendto,
setpeername, setsockname and timeout can be
used. In case of error, the function returns nil and an error
message.
The following functions can be used to convert between host names and IP
addresses. All information returned by the resolver is returned by these
functions, as a table in the form:
tohostname(address)
Returns a string with the canonic host name of given address,
followed by a table with all information returned by the resolver.
Address can be an IP address or host name. In casee of error,
the function returns nil followed by an error message.
toip(address)
Returns a string with the first IP address found for address,
followed by a table with all information returned by the resolver.
Address can be an IP address or host name. In case of error,
the function returns nil followed by an error message.
Besides IPv4 transport layer support, the LuaSocket toolkit offers
straightforward support for the HTTP, SMTP and FTP protocols. The
support is implemented in the Lua language and is distributed in source
code as three separate modules.
The module smtp.lua provides functionality to send e-mail
messages to a SMTP mail server. The implementation conforms to
RFC 821.
MIME Headers are represented as a table in the form:
smtp_mail(from, rcpt, headers, body,
server)
Sends a message to recipient list rcpt, a lua table. The sender
is given by the e-mail address from. The message is composed by
the optional MIME Headers headers and text body. The
message is sent using the server server. If successful, the
function returns nil, otherwise an error message is returned.
Examples:
The mail function, for compatibility, implements the same interface
as that of CGILua 3.2,
except the mailserver parameter is mandatory.
The function returns nil if the message was sent successfully.
In case of error, an error message is returned.
The module http.lua provides functionality to download an URL
from an HTTP server. The implementation conforms to the HTTP/1.1
standard,
RFC 2068.
URLs MUST conform to
RFC 1738,
that is, an URL is a string in the form:
The module exports three functions:
http_request(method, url [, headers, body])
Performs the generic HTTP request using method on url
sending the request headers and message body along
with the request. If successful, the function returns the body of the
reply, a table with mime headers and the HTTP status returned by the
server. In case of error, the function returns whatever it managed to
retrieve (nil values representing failure) and and an error
message describing the error. If <user> and
<password> are provided in the URL, the function uses the
Basic Authentication Scheme (see note) to retrieve
the document.
http_get(url [, headers])
Calls http_request with method 'GET'.
Examples:
The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both
explained in detail in
RFC 2068.
The Basic Authentication Scheme sends <user> and
<password> unencrypted to the server and is therefore
considered unsafe. Unfortunately, by the time of this implementation,
the wide majority of servers and browsers support the Basic Scheme only.
Therefore, this is the method used by the toolkit whenever
authentication is required.
Example:
Calls http_request with method 'POST' sending
body along with the request.
The module ftp.lua provides functions to download and upload
files from and to FTP servers. The implementation conforms to
RFC 959.
URLs MUST conform to
RFC 1738,
that is, an URL is a string in the form:
ftp_get(url [, type])
Downloads the URL url using transfer type type and
returns it as a string.
The parameter type can receive values 'a' (ascii, the
default) or 'b' (binary) and determines the transfer type. If
<path> ends with a '/', a directory listing of
<path> is returned. If successful, the function returns
the file contents as a string. In case of error, the function returns
nil and an error message describing the error.
If no <user> is provided, the function tries to log in as
'anonymous'.
Examples:
Stores a file at url with contents given by the string
data and using transfer type type.
The parameter type can receive values 'a' (ascii, the
default) or 'b' (binary) and determines the transfer type. If
successful, the function returns nil. In case of error, the
function returns a string describing the error.
If no <user> is provided, the function tries to log in as
anonymous.
Examples:
Current Version
What's New
Incompatibilities with Previous Versions
Download
luasocket-1.2.zip Function Reference
TCP sockets
The function returns 1 if socket is ready, and nil otherwise.
The poll function returns imediately.
The function returns one string for each pattern, followed by a single
error code that can be nil in case of success, the string
'closed' in case the connection was closed before the
transmission was complete or the string 'timeout' in case there
was a timeout during the operation. The difference in performance
between all patterns is negligible.
The nil timeout value allows operations to block
indefinitely. Negative timeout values have the same effect. UDP sockets
The function returns 1 if socket is ready, and nil otherwise.
The poll function returns imediately. DNS Services
Note that the alias list can be empty.
resolved = {
["name"] = "canonic-name",
["alias"] = alias-list,
["ip"] = ip-address-list
}
Protocol Reference
SMTP
The module exports two functions:
headers = {
["field-1-name"] = "field-1-value",
["field-2-name"] = "field-2-value",
["field-3-name"] = "field-3-value",
... ...
["field-n-name"] = "field-n-value"
}
mail {
headers = {
to = "fulano@tecgraf.puc-rio.br, beltrano@tecgraf.puc-rio.br",
subject = "LuaSocket test message"
}
from = "luasocket@tecgraf.puc-rio.br"
rcpt = {
"fulano@tecgraf.puc-rio.br",
"beltrano@tecgraf.puc-rio.br",
"sicrano@tecgraf.puc-rio.br"
}
body = "This is a test message. Please ignore."
server = "local"
-- connects to server "local" and sends a message to users
-- "fulano@tecgraf.puc-rio.br" and "beltrano@tecgraf.puc-rio.br"
-- "sicrano@tecgraf.puc-rio.br" receives a 'blind carbon copy' of the message.
e = smtp_mail(from, rcpt, headers, body, server)
to=tolist,
from=from,
subject=subject,
message=message,
cc=cclist,
bcc=bcclist,
mailserver=server
}
to: A comma-separated list of the e-mails of
the recipients of the message. from: The email of the sender. subject: Optional message subject. message: Optional message body. cc: An optional comma-separated list of the
e-mails of "carbon-copy" recipients. bcc: An optional comma-separated list of the
e-mails of the "blind carbon-copy" recipients. mailserver: Address of SMTP server to be used. HTTP
MIME Headers are represented as a table in the form:[http://][<user>[:<password>]@]<>[:<port>][/<path>]
Field names are case insensitive (as specified by the standard) and all
API functions work with lowercase field names. Field values are left
unmodified.
headers = {
["field-1-name"] = "field-1-value",
["field-2-name"] = "field-2-value",
["field-3-name"] = "field-3-value",
... ...
["field-n-name"] = "field-n-value"
}
Note: Some URLs are protected by their servers from
anonymous download. For those URLs, the server must receive some sort of
authentication along with the request or it will deny download and
return status "401 Authentication Required".
-- connect to server "www.tecgraf.puc-rio.br" and retrieves this manual
-- file from "~diego/luasocket/manual.html"
f, m, s, e = http_get("http://www.tecgraf.puc-rio.br/~diego/luasocket/manual.html")
-- connect to server "www.tecgraf.puc-rio.br" and tries to retrieve
-- "~diego/auth/index.html". Fails because authentication is needed.
f, m, s, e = http_get("http://www.tecgraf.puc-rio.br/~diego/auth/index.html")
-- s returns with value "401 Authentication Required"
http_post(url, body [, headers])
-- connect to server "www.tecgraf.puc-rio.br" and tries to retrieve
-- "~diego/auth/index.html", using the provided name and password to
-- authenticate the request
f, m, s, e = http_get("http://diego:nehab@www.tecgraf.puc-rio.br/~diego/auth/index.html")
-- alternatively, one could fill the appropriate header and authenticate
-- the request directly. both calls are equivalent
h = {authentication = "Basic " .. base64("diego:nehab")}
f, m, s, e = http_get("http://www.tecgraf.puc-rio.br/~diego/auth/index.html", h)
FTP
The module exports two functions: [ftp://][<user>[:<password>]@]<>[:<port>][/<path>]
ftp_put(url, data [, type])
-- log as user "anonymous" on server "ftp.tecgraf.puc-rio.br"
-- go to directory "pub/lua" and get file "lua.tar.gz" as binary.
f, e = ftp_get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz", "b")
-- log as user "anonymous" on server "ftp.tecgraf.puc-rio.br"
-- go to director "pub" and retrieve directory listing of directory "lua"
f, e = ftp_get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/")
-- log as user "diego", password "nehab", on server "derain.tecgraf.puc-rio.br"
-- go to directory "tec/luasocket/html" and retrieve file "manual.html"
-- (actually, fails because of wrong password :-)
f, e = ftp_get("ftp://diego:nehab@derain.tecgraf.puc-rio.br/tec/luasocket/html/manual.html")
-- log as user "anonymous" on server "ftp.free.org" and store file
-- "hello" with contents "hello world!" on current directory
e = ftp_put("ftp://ftp.free.org/hello", "hello world!")
| and |
|
|
Last modified by Diego Nehab on Thu Jan 25 16:11:36 EDT 2001 | ||