Final push for release...

This commit is contained in:
Diego Nehab 2005-08-12 05:56:32 +00:00
parent 37f7af4b9f
commit 0c3cdd5ef2
31 changed files with 332 additions and 255 deletions

11
FIX
View File

@ -1,3 +1,14 @@
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.

36
TODO
View File

@ -1,22 +1,13 @@
new instalation scheme???
test empty socket.select no windows.
bug by mathew percival?
arranjar um jeito de fazer multipart/alternative
what the hell does __unload do?
clean timeout argument to open functions in SMTP, HTTP and FTP
add create field to FTP and SMTP
talk about new create field in HTTP, FTP and SMTP
talk about the non-blocking connect in the manual
test it on Windows!!!
think about a dispatcher.
- it creates a server and receives a function that will do the work on
received connections
- this function is invoked with the client socket
- it calls special send and receive functions that yield on timeout
think about how to extend http, ftp, smtp to use special send and receive
functions for non-blocking so they can be used in the context of the
dispatcher!
adjust manual for new sock:send returns.
leave code for losers that don't have nanosleep
ftp.send/recv return bytes transfered?
@ -41,7 +32,16 @@ testar os options!
- proteger ou atomizar o conjunto (timedout, receive), (timedout, send)
- inet_ntoa também é uma merda.
eliminate globals from namespaces created by module().
* BUG NO SET DO TINYIRC!!! SINISTRO.
* _VERSION, _DEBUG, etc.
* talk about new create field in HTTP, FTP and SMTP
* talk about the non-blocking connect in the manual
* think about how to extend http, ftp, smtp to use special send and receive
* functions for non-blocking so they can be used in the context of the
* dispatcher!
* adjust manual for new sock:send returns.
* think about a dispatcher.
* - it creates a server and receives a function that will do the work on
* received connections
* - this function is invoked with the client socket
* - it calls special send and receive functions that yield on timeout

2
config
View File

@ -21,7 +21,7 @@ LUALIB=
#------
# Compat-5.1 directory
#
COMPAT=compat-5.1r3
COMPAT=compat-5.1r4
#------
# Top of your Lua installation

View File

@ -106,6 +106,7 @@ ftp.<b>get{</b><br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
@ -138,7 +139,9 @@ authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function.
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>accept</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
@ -188,6 +191,7 @@ ftp.<b>put{</b><br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
@ -220,7 +224,9 @@ authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function.
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>accept</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>

View File

@ -131,7 +131,8 @@ http.<b>request{</b><br>
&nbsp;&nbsp;[source = <i>LTN12 source</i>],<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[proxy = <i>string</i>,]<br>
&nbsp;&nbsp;[redirect = <i>boolean</i>]<br>
&nbsp;&nbsp;[redirect = <i>boolean</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
@ -178,7 +179,9 @@ pump step function used to move data.
Defaults to the LTN12 <tt>pump.step</tt> function.
<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;
<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
function from automatically following 301 or 302 server redirect messages.
function from automatically following 301 or 302 server redirect messages;
<li><tt>accept</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>

View File

@ -168,6 +168,7 @@ support.
<li> Improved: <tt>tcp:send(data, i, j)</tt> to return <tt>(i+sent-1)</tt>. This is great for non-blocking I/O, but might break some code;
<li> Improved: HTTP, SMTP, and FTP functions to accept a new field
<tt>create</tt> that overrides the function used to create socket objects;
<li> Fixed: <tt>smtp.send</tt> was hanging on errors returned by LTN12 sources;
<li> Fixed: <tt>url.absolute()</tt> to work when <tt>base_url</tt> is in
parsed form;
<li> Fixed: <tt>http.request()</tt> not to redirect when the location
@ -194,7 +195,8 @@ with descriptor 0 to be ignored (Renato Maia);
<li> Fixed: "Bug" that caused <tt>gethostbyname</tt> to crash under VMS
(Renato Maia);
<li> Fixed: <tt>tcp:send("")</tt> to return 0 bytes sent (Alexander Marinov);
<li> Improved: <tt>socket.DEBUG</tt> and <tt>socket.VERSION</tt> became <tt>socket._DEBUGs</tt> and <tt>socket._VERSION</tt> for uniformity with other libraries.
<li> Improved: <tt>socket.DEBUG</tt> and <tt>socket.VERSION</tt> became <tt>socket._DEBUGs</tt> and <tt>socket._VERSION</tt> for uniformity with other libraries;
<li> Improved: <tt>socket.select</tt> now works on empty sets on Windows.
</ul>
<!-- incompatible +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->

View File

@ -71,11 +71,11 @@ Here is the standard LuaSocket distribution directory structure:</p>
<pre class=example>
&lt;ROOT&gt;/compat-5.1.lua
&lt;ROOT&gt;/socket.lua
&lt;ROOT&gt;/lsocket.dll
&lt;ROOT&gt;/mime.lua
&lt;ROOT&gt;/lmime.dll
&lt;ROOT&gt;/ltn12.lua
&lt;ROOT&gt;/mime/init.lua
&lt;ROOT&gt;/mime/core.dll
&lt;ROOT&gt;/socket/init.lua
&lt;ROOT&gt;/socket/core.dll
&lt;ROOT&gt;/socket/http.lua
&lt;ROOT&gt;/socket/tp.lua
&lt;ROOT&gt;/socket/ftp.lua
@ -83,10 +83,8 @@ Here is the standard LuaSocket distribution directory structure:</p>
&lt;ROOT&gt;/socket/url.lua
</pre>
<p> Naturally, on Unix systems, <tt>lsocket.dll</tt> and <tt>lmime.dll</tt>
would be replaced by <tt>lsocket.so</tt> and <tt>lmime.so</tt>. In Mac OS
X, they would be replaced by <tt>lsocket.dylib</tt> and
<tt>lmime.dylib</tt>. </p>
<p> Naturally, on Unix systems, <tt>core.dll</tt>
would be replaced by <tt>core.so</tt>.
<p> In order for the interpreter to find all LuaSocket components, three
environment variables need to be set. The first environment variable tells

View File

@ -142,7 +142,7 @@ Support, Manual">
<blockquote>
<a href="socket.html">Socket</a>
<blockquote>
<a href="socket.html#_debug">_DEBUG</a>,
<a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
<a href="socket.html#newtry">newtry</a>,
@ -155,7 +155,7 @@ Support, Manual">
<a href="tcp.html#tcp">tcp</a>,
<a href="socket.html#try">try</a>,
<a href="udp.html#udp">udp</a>,
<a href="socket.html#_version">_VERSION</a>.
<a href="socket.html#version">_VERSION</a>.
</blockquote>
</blockquote>

View File

@ -127,6 +127,7 @@ smtp.<b>send{</b><br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[domain = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
@ -138,6 +139,7 @@ doesn't have a simple interface. However, see the
a very powerful way to define the message contents.
</p>
<p class=parameters>
The sender is given by the e-mail address in the <tt>from</tt> field.
<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
@ -158,7 +160,9 @@ local machine host name;
<li> <tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function.
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>accept</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
@ -167,7 +171,7 @@ If successful, the function returns 1. Otherwise, the function returns
</p>
<p class=note>
Note: SMTP servers are 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
"<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

View File

@ -80,12 +80,12 @@ socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b>
This function is a shortcut that creates and returns a TCP client object
connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally,
the user can also specify the local address and port to bind
(<tt>locaddr</tt> and </tt>locport</tt>).
(<tt>locaddr</tt> and <tt>locport</tt>).
</p>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=_debug>
<p class=name id=debug>
socket.<b>_DEBUG</b>
</p>
@ -372,7 +372,7 @@ c = socket.try(socket.connect("localhost", 80))
<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=_version>
<p class=name id=version>
socket.<b>_VERSION</b>
</p>

View File

@ -79,7 +79,7 @@ reported by <b><tt>nil</tt></b> followed by a message describing the error.
<p class=note>
Note: calling <a href=socket.html#select><tt>socket.select</tt></a>
with a server object in
the <tt>receive</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
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up.
@ -111,7 +111,7 @@ method returns <b><tt>nil</tt></b> followed by an error message.
<p class=note>
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
is available and is a shortcut for the creation server sockets.
is available and is a shortcut for the creation of server sockets.
</p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -173,8 +173,11 @@ is available and is a shortcut for the creation of client sockets.
<p class=note>
Note: Starting with LuaSocket 2.0,
the <a href=#settimeout><tt>settimeout</tt></a>
method affects the behavior of connect, causing it to return in case of
a timeout.
method affects the behavior of <tt>connect</tt>, causing it to return
with an error in case of a timeout. If that happens, you can still call <a
href=socket.html#select><tt>socket.select</tt></a> with the socket in the
<tt>sendt</tt> table. The socket will be writable when the connection is
stablished.
</p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -328,11 +331,11 @@ substring to be sent.
</p>
<p class=return>
If successful, the method returns the number of bytes accepted by
the transport layer. In case of error, the method returns
If successful, the method returns the number of bytes sent.
In case of error, the method returns
<b><tt>nil</tt></b>, followed by an error message, followed by the
partial number of bytes accepted by the transport layer.
The error message can be '<tt>closed</tt>' in case
index of the first character within <tt>[i, j]</tt> that has not been sent yet
(you might want to try again from then on). The error message can be '<tt>closed</tt>' in case
the connection was closed before the transmission was completed or the
string '<tt>timeout</tt>' in case there was a timeout during the
operation.
@ -433,7 +436,7 @@ of bandwidth.
<p class=parameters>
<tt>Received</tt> is a number with the new number of bytes received.
<tt>Sent</tt> is a number with the new number of bytes sent.
<tt>Age</tt> is the new age in seconds</tt>
<tt>Age</tt> is the new age in seconds.
</p>
<p class=return>

View File

@ -84,17 +84,22 @@ function newcreate(thread)
first = (first or 1) - 1
local result, error
while true do
-- tell dispatcher we want to keep sending before we
-- yield control
sending:insert(tcp)
-- return control to dispatcher
-- if upon return the dispatcher tells us we timed out,
-- return an error to whoever called us
if coroutine.yield() == "timeout" then
return nil, "timeout"
end
-- mark time we started waiting
context[tcp].last = socket.gettime()
-- try sending
result, error, first = tcp:send(data, first+1, last)
if error == "timeout" then
-- tell dispatcher we want to keep sending
sending:insert(tcp)
-- mark time we started waiting
context[tcp].last = socket.gettime()
-- return control to dispatcher
if coroutine.yield() == "timeout" then
return nil, "timeout"
end
else return result, error, first end
-- if we are done, or there was an unexpected error,
-- break away from loop
if error ~= "timeout" then return result, error, first end
end
end,
-- receive in non-blocking mode and yield on timeout
@ -102,28 +107,35 @@ function newcreate(thread)
local error, partial = "timeout", ""
local value
while true do
-- tell dispatcher we want to keep receiving before we
-- yield control
receiving:insert(tcp)
-- return control to dispatcher
-- if upon return the dispatcher tells us we timed out,
-- return an error to whoever called us
if coroutine.yield() == "timeout" then
return nil, "timeout"
end
-- mark time we started waiting
context[tcp].last = socket.gettime()
-- try receiving
value, error, partial = tcp:receive(pattern, partial)
if error == "timeout" then
-- tell dispatcher we want to keep receiving
receiving:insert(tcp)
-- mark time we started waiting
context[tcp].last = socket.gettime()
-- return control to dispatcher
if coroutine.yield() == "timeout" then
return nil, "timeout"
end
else return value, error, partial end
-- if we are done, or there was an unexpected error,
-- break away from loop
if error ~= "timeout" then return value, error, partial end
end
end,
-- connect in non-blocking mode and yield on timeout
connect = function(self, host, port)
local result, error = tcp:connect(host, port)
-- mark time we started waiting
context[tcp].last = socket.gettime()
if error == "timeout" then
-- tell dispatcher we will be able to write uppon connection
sending:insert(tcp)
-- mark time we started waiting
context[tcp].last = socket.gettime()
-- return control to dispatcher
-- if upon return the dispatcher tells us we have a
-- timeout, just abort
if coroutine.yield() == "timeout" then
return nil, "timeout"
end
@ -148,10 +160,10 @@ function newcreate(thread)
end
-- get the status of a URL, non-blocking
function getstatus(from, link)
function getstatus(link)
local parsed = url.parse(link, {scheme = "file"})
if parsed.scheme == "http" then
local thread = coroutine.create(function(thread, from, link)
local thread = coroutine.create(function(thread, link)
local r, c, h, s = http.request{
method = "HEAD",
url = link,
@ -162,7 +174,7 @@ function getstatus(from, link)
nthreads = nthreads - 1
end)
nthreads = nthreads + 1
assert(coroutine.resume(thread, thread, from, link))
assert(coroutine.resume(thread, thread, link))
end
end
@ -190,6 +202,8 @@ function dispatch()
local now = socket.gettime()
for who, data in pairs(context) do
if data.last and now - data.last > TIMEOUT then
sending:remove(who)
receiving:remove(who)
assert(coroutine.resume(context[who].thread, "timeout"))
end
end
@ -206,14 +220,15 @@ function readfile(path)
else return nil, error end
end
function retrieve(u)
function load(u)
local parsed = url.parse(u, { scheme = "file" })
local body, headers, code, error
local base = u
if parsed.scheme == "http" then
body, code, headers = http.request(u)
if code == 200 then
base = base or headers.location
-- if there was a redirect, update base to reflect it
base = headers.location or base
end
if not body then
error = code
@ -241,12 +256,13 @@ function getlinks(body, base)
return links
end
function checklinks(from)
local base, body, error = retrieve(from)
function checklinks(address)
local base, body, error = load(address)
if not body then print(error) return end
print("Checking ", base)
local links = getlinks(body, base)
for _, link in ipairs(links) do
getstatus(from, link)
getstatus(link)
end
end
@ -255,8 +271,7 @@ if table.getn(arg) < 1 then
print("Usage:\n luasocket check-links.lua {<url>}")
exit()
end
for _, a in ipairs(arg) do
print("Checking ", a)
checklinks(url.absolute("file:", a))
for _, address in ipairs(arg) do
checklinks(url.absolute("file:", address))
end
dispatch()

View File

@ -37,7 +37,7 @@ function retrieve(u)
if parsed.scheme == "http" then
body, code, headers = http.request(u)
if code == 200 then
base = base or headers.location
base = headers.location or base
end
if not body then
error = code

View File

@ -16,6 +16,7 @@ local url = require("socket.url")
local tp = require("socket.tp")
module("socket.dict")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Globals
@ -151,4 +152,3 @@ get = socket.protect(function(gett)
else return tget(gett) end
end)
--getmetatable(_M).__index = nil

View File

@ -15,6 +15,7 @@ local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.lp")
getmetatable(_M).__index = nil
-- default port
PORT = 515
@ -318,4 +319,3 @@ query = socket.protect(function(p)
return data
end)
--getmetatable(_M).__index = nil

View File

@ -16,6 +16,7 @@ local socket = require("socket")
local ltn12 = require("ltn12")
local url = require("socket.url")
module("socket.tftp")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Program constants
@ -153,4 +154,3 @@ get = socket.protect(function(gett)
else return tget(gett) end
end)
--getmetatable(_M).__index = nil

52
makefile Normal file
View File

@ -0,0 +1,52 @@
#------
# Load configuration
#
include config
#------
# Hopefully no need to change anything below this line
#
INSTALL_SOCKET=$(INSTALL_TOP)/socket
INSTALL_MIME=$(INSTALL_TOP)/mime
all clean:
cd src; $(MAKE) $@
#------
# Files to install
#
TO_SOCKET:= \
socket.lua \
http.lua \
url.lua \
tp.lua \
ftp.lua \
smtp.lua
TO_TOP:= \
ltn12.lua
TO_MIME:= \
$(MIME_SO) \
mime.lua
#------
# Install LuaSocket according to recommendation
#
install: all
cd src; mkdir -p $(INSTALL_TOP)
cd src; $(INSTALL_DATA) $(COMPAT)/compat-5.1.lua $(INSTALL_TOP)
cd src; $(INSTALL_DATA) ltn12.lua $(INSTALL_TOP)
cd src; mkdir -p $(INSTALL_SOCKET)
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET)
cd src; $(INSTALL_DATA) $(TO_SOCKET) $(INSTALL_SOCKET)
cd src; cd $(INSTALL_SOCKET); $(INSTALL_LINK) -s $(SOCKET_SO) core.$(EXT)
cd src; cd $(INSTALL_SOCKET); $(INSTALL_LINK) -s socket.lua init.lua
cd src; mkdir -p $(INSTALL_MIME)
cd src; $(INSTALL_DATA) $(TO_MIME) $(INSTALL_MIME)
cd src; cd $(INSTALL_MIME); $(INSTALL_LINK) -s $(MIME_SO) core.$(EXT)
cd src; cd $(INSTALL_MIME); $(INSTALL_LINK) -s mime.lua init.lua
#------
# End of makefile
#

View File

@ -17,6 +17,7 @@ local url = require("socket.url")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
module("socket.ftp")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Program constants
@ -35,8 +36,8 @@ PASSWORD = "anonymous@anonymous.org"
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(server, port)
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT))
function open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT))
local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end)
@ -199,7 +200,7 @@ end
local function tput(putt)
putt = override(putt)
socket.try(putt.host, "missing hostname")
local f = open(putt.host, putt.port)
local f = open(putt.host, putt.port, putt.create)
f:greet()
f:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end
@ -242,7 +243,7 @@ end)
local function tget(gett)
gett = override(gett)
socket.try(gett.host, "missing hostname")
local f = open(gett.host, gett.port)
local f = open(gett.host, gett.port, gett.create)
f:greet()
f:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end
@ -264,7 +265,7 @@ command = socket.protect(function(cmdt)
cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname")
socket.try(cmdt.command, "missing command")
local f = open(cmdt.host, cmdt.port)
local f = open(cmdt.host, cmdt.port, cmdt.create)
f:greet()
f:login(cmdt.user, cmdt.password)
f.try(f.tp:command(cmdt.command, cmdt.argument))
@ -278,4 +279,3 @@ get = socket.protect(function(gett)
else return tget(gett) end
end)
--getmetatable(_M).__index = nil

View File

@ -16,6 +16,7 @@ local string = require("string")
local base = _G
local table = require("table")
module("socket.http")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Program constants
@ -105,26 +106,16 @@ end
-----------------------------------------------------------------------------
local metat = { __index = {} }
-- default connect function, respecting the timeout
local function connect(host, port, create)
local c, e = (create or socket.tcp)()
if not c then return nil, e end
c:settimeout(TIMEOUT)
local r, e = c:connect(host, port or PORT)
if not r then
c:close()
return nil, e
end
return c
end
function open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try(connect(host, port, create))
-- create our http request object, pointing to the socket
local c = socket.try(create or socket.tcp)()
local h = base.setmetatable({ c = c }, metat)
-- make sure the object close gets called on exception
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(TIMEOUT))
h.try(c:connect(host, port or PORT))
-- here everything worked
return h
end
@ -134,11 +125,11 @@ function metat.__index:sendrequestline(method, uri)
end
function metat.__index:sendheaders(headers)
local h = "\r\n"
for i, v in base.pairs(headers) do
self.try(self.c:send(i .. ": " .. v .. "\r\n"))
h = i .. ": " .. v .. "\r\n" .. h
end
-- mark end of request headers
self.try(self.c:send("\r\n"))
self.try(self.c:send(h))
return 1
end
@ -213,7 +204,7 @@ local function adjustheaders(headers, host)
["te"] = "trailers"
}
-- override with user headers
for i,v in pairs(headers or lower) do
for i,v in base.pairs(headers or lower) do
lower[string.lower(i)] = v
end
return lower
@ -232,7 +223,7 @@ local function adjustrequest(reqt)
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
local t = url.parse(reqt.url, default)
-- explicit components override url
for i,v in pairs(reqt) do nreqt[i] = v end
for i,v in base.pairs(reqt) do nreqt[i] = v end
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
-- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt)
@ -276,11 +267,11 @@ function tauthorize(reqt)
return trequest(reqt)
end
function tredirect(reqt, headers)
return trequest {
function tredirect(reqt, location)
local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
url = url.absolute(reqt, headers["location"]),
url = url.absolute(reqt, location),
source = reqt.source,
sink = reqt.sink,
headers = reqt.headers,
@ -288,6 +279,9 @@ function tredirect(reqt, headers)
nredirects = (reqt.nredirects or 0) + 1,
connect = reqt.connect
}
-- pass location header back as a hint we redirected
headers.location = headers.location or location
return result, code, headers, status
end
function trequest(reqt)
@ -301,7 +295,7 @@ function trequest(reqt)
headers = h:receiveheaders()
if shouldredirect(reqt, code, headers) then
h:close()
return tredirect(reqt, headers)
return tredirect(reqt, headers.location)
elseif shouldauthorize(reqt, code) then
h:close()
return tauthorize(reqt)
@ -332,4 +326,3 @@ request = socket.protect(function(reqt, body)
else return trequest(reqt) end
end)
--getmetatable(_M).__index = nil

View File

@ -12,6 +12,7 @@ local string = require("string")
local table = require("table")
local base = _G
module("ltn12")
getmetatable(_M).__index = nil
filter = {}
source = {}
@ -134,8 +135,6 @@ function source.rewind(src)
end
end
local print = print
-- chains a source with a filter
function source.chain(src, f)
base.assert(src and f)
@ -258,7 +257,8 @@ end
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
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
-- pumps all data from a source to a sink, using a step function
@ -267,8 +267,10 @@ 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
if not ret then
if err then return nil, err
else return 1 end
end
end
end
--getmetatable(_M).__index = nil

View File

@ -108,7 +108,7 @@ static int base_open(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Initializes all library modules.
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socketcore(lua_State *L) {
LUASOCKET_API int luaopen_socket_core(lua_State *L) {
int i;
base_open(L);
for (i = 0; mod[i].name; i++) mod[i].func(L);

87
src/makefile Normal file
View File

@ -0,0 +1,87 @@
#------
# Load configuration
#
include ../config
#------
# Hopefully no need to change anything below this line
#
#------
# Modules belonging to socket-core
#
SOCKET_OBJS:= \
luasocket.o \
timeout.o \
buffer.o \
io.o \
auxiliar.o \
options.o \
inet.o \
tcp.o \
udp.o \
except.o \
select.o \
$(COMPAT)/compat-5.1.o \
usocket.o
#------
# Modules belonging mime-core
#
MIME_OBJS:=\
mime.o \
$(COMPAT)/compat-5.1.o
#------
# Modules belonging unix (local domain sockets)
#
UNIX_OBJS:=\
buffer.o \
auxiliar.o \
options.o \
timeout.o \
io.o \
usocket.o \
unix.o
all: $(SOCKET_SO) $(MIME_SO)
$(SOCKET_SO): $(SOCKET_OBJS)
$(LD) $(LDFLAGS) -o $@ $^
$(MIME_SO): $(MIME_OBJS)
$(LD) $(LDFLAGS) -o $@ $^
$(UNIX_SO): $(UNIX_OBJS)
$(LD) $(LDFLAGS) -o $@ $^
#------
# List of dependencies
#
auxiliar.o: auxiliar.c auxiliar.h
buffer.o: buffer.c buffer.h io.h timeout.h
except.o: except.c except.h
inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h
io.o: io.c io.h timeout.h
luasocket.o: luasocket.c luasocket.h auxiliar.h except.h timeout.h \
buffer.h io.h inet.h socket.h usocket.h tcp.h udp.h select.h
mime.o: mime.c mime.h
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
usocket.h inet.h
select.o: select.c socket.h io.h timeout.h usocket.h select.h
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h tcp.h buffer.h
timeout.o: timeout.c auxiliar.h timeout.h
udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h udp.h
unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h options.h \
unix.h buffer.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS)
rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS)
#------
# End of makefile configuration
#

View File

@ -14,6 +14,7 @@ local mime = require("mime.core")
local io = require("io")
local string = require("string")
module("mime")
getmetatable(_M).__index = nil
-- encode, decode and wrap algorithm tables
encodet = {}
@ -84,5 +85,3 @@ end
function stuff()
return ltn12.filter.cycle(dot, 2)
end
--getmetatable(_M).__index = nil

View File

@ -18,6 +18,7 @@ local tp = require("socket.tp")
local ltn12 = require("ltn12")
local mime = require("mime")
module("socket.smtp")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Program constants
@ -111,12 +112,12 @@ function metat.__index:send(mailt)
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
end
function open(server, port)
local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT))
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
create, TIMEOUT))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
if s.tp:command("QUIT") then s.tp:check("2..") end
s:close()
end)
return s
@ -165,10 +166,9 @@ end
local function send_source(mesgt)
-- set content-type if user didn't override
if not mesgt.headers or not mesgt.headers["content-type"] then
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n')
end
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
else coroutine.yield("\r\n") end
-- finish headers
coroutine.yield("\r\n")
-- send body from source
while true do
local chunk, err = mesgt.body()
@ -182,21 +182,20 @@ end
local function send_string(mesgt)
-- set content-type if user didn't override
if not mesgt.headers or not mesgt.headers["content-type"] then
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n')
end
-- finish headers
coroutine.yield("\r\n")
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
else coroutine.yield("\r\n") end
-- send body from string
coroutine.yield(mesgt.body)
end
-- yield the headers one by one
-- yield the headers all at once
local function send_headers(mesgt)
if mesgt.headers then
local h = ""
for i,v in base.pairs(mesgt.headers) do
coroutine.yield(i .. ':' .. v .. "\r\n")
h = i .. ': ' .. v .. "\r\n" .. h
end
coroutine.yield(h)
end
end
@ -237,12 +236,10 @@ end
-- High level SMTP API
-----------------------------------------------------------------------------
send = socket.protect(function(mailt)
local s = open(mailt.server, mailt.port)
local s = open(mailt.server, mailt.port, mailt.create)
local ext = s:greet(mailt.domain)
s:auth(mailt.user, mailt.password, ext)
s:send(mailt)
s:quit()
return s:close()
end)
--getmetatable(_M).__index = nil

View File

@ -12,6 +12,7 @@ local string = require("string")
local math = require("math")
local socket = require("socket.core")
module("socket")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Exported auxiliar functions
@ -131,5 +132,3 @@ sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet)
-- clear globals from namespace
getmetatable(_M).__index = nil

View File

@ -1,70 +0,0 @@
/*=========================================================================*\
* Simple client SSL support
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <lua.h>
#include <lauxlib.h>
#include "ssl.h"
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_wrap(lua_State *L);
/* functions in library namespace */
static luaL_reg func[] = {
{"wrap", global_create},
{NULL, NULL}
};
static luaL_reg wrap[] = {
{"__tostring", aux_tostring},
{"__gc", meth_close},
{"close", meth_close},
{"receive", meth_receive},
{"send", meth_send},
{NULL, NULL}
};
static luaL_reg owned[] = {
{"__tostring", aux_tostring},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int ssl_open(lua_State *L)
{
aux_newclass(L, "ssl{wraper}", wrap);
aux_newclass(L, "ssl{owned}", owned);
lua_pushstring(L, "ssl")
lua_newtable(L);
luaL_openlib(L, NULL, func, 0);
lua_settable(L, -3);
return 0;
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Wraps a tcp object into an SSL object
\*-------------------------------------------------------------------------*/
static int global_wrap(lua_State *L) {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
/* change class of tcp object */
aux_setclass(L, "ssl{owned}", 1);
/* create wrapper */
p_wrap wrap = (p_wrap) lua_newuserdata(L, sizeof(t_wrap));
/* lock reference */
lua_pushvalue(L, 1);
wrap->ref = lua_ref(L, 1);
/* initialize wrapper */
wrap->tcp = tcp;
io_init(&tcp->io, wrap_send, wrap_recv, wrap);
return 1;
}

View File

@ -1,29 +0,0 @@
#ifndef SSL_H
#define SSL_H
/*=========================================================================*\
* Simple client SSL support
* LuaSocket toolkit
*
* This is just a simple example to show how to extend LuaSocket
*
* RCS ID: $Id$
\*=========================================================================*/
#include <lua.h>
#include <openssl/ssl.h>
#include "buffer.h"
#include "timeout.h"
#include "socket.h"
#include "tcp.h"
typedef struct t_wrap_ {
p_tcp tcp;
SSL* ssl;
int ref;
} t_wrap;
typedef t_wrap *p_wrap;
int ssl_open(lua_State *L);
#endif /* SSL_H */

View File

@ -13,6 +13,7 @@ local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.tp")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Program constants
@ -98,7 +99,8 @@ end
function metat.__index:source(source, step)
local sink = socket.sink("keep-open", self.c)
return ltn12.pump.all(source, sink, step or ltn12.pump.step)
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
return ret, err
end
-- closes the underlying c
@ -108,8 +110,8 @@ function metat.__index:close()
end
-- connect with server and return c object
function connect(host, port, timeout)
local c, e = socket.tcp()
function connect(host, port, create, timeout)
local c, e = (create or socket.tcp())
if not c then return nil, e end
c:settimeout(timeout or TIMEOUT)
local r, e = c:connect(host, port)
@ -120,4 +122,3 @@ function connect(host, port, timeout)
return base.setmetatable({c = c}, metat)
end
--getmetatable(_M).__index = nil

View File

@ -12,6 +12,7 @@ local string = require("string")
local base = _G
local table = require("table")
module("socket.url")
getmetatable(_M).__index = nil
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
@ -279,4 +280,3 @@ function build_path(parsed, unsafe)
return path
end
--getmetatable(_M).__index = nil

View File

@ -74,7 +74,10 @@ int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
double t = tm_get(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
if (n <= 0) {
Sleep(1000*t);
return 0;
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
/*-------------------------------------------------------------------------*\

View File

@ -48,18 +48,19 @@ source = smtp.message{
}
}
--[[
sink = ltn12.sink.file(io.stdout)
ltn12.pump.all(source, sink)
]]
function filter(s)
if s then io.write(s) end
return s
end
-- finally send it
r, e = smtp.send{
rcpt = {"<diego@tecgraf.puc-rio.br>",
"<diego@princeton.edu>" },
from = "<diego@princeton.edu>",
source = source,
server = "mail.cs.princeton.edu"
source = ltn12.source.chain(source, filter),
--server = "mail.cs.princeton.edu"
server = "localhost",
port = 2525
}
print(r, e)