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 url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class. tcp{client}:shutdown() was checking for group instead of class.

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? 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!!! 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 leave code for losers that don't have nanosleep
ftp.send/recv return bytes transfered? ftp.send/recv return bytes transfered?
@ -41,7 +32,16 @@ testar os options!
- proteger ou atomizar o conjunto (timedout, receive), (timedout, send) - proteger ou atomizar o conjunto (timedout, receive), (timedout, send)
- inet_ntoa também é uma merda. - inet_ntoa também é uma merda.
eliminate globals from namespaces created by module().
* BUG NO SET DO TINYIRC!!! SINISTRO. * BUG NO SET DO TINYIRC!!! SINISTRO.
* _VERSION, _DEBUG, etc. * _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-5.1 directory
# #
COMPAT=compat-5.1r3 COMPAT=compat-5.1r4
#------ #------
# Top of your Lua installation # 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;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br> &nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> &nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b> <b>}</b>
</p> </p>
@ -138,7 +139,9 @@ authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<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><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> </ul>
<p class=return> <p class=return>
@ -188,6 +191,7 @@ ftp.<b>put{</b><br>
&nbsp;&nbsp;[port = <i>number</i>,]<br> &nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br> &nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> &nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b> <b>}</b>
</p> </p>
@ -220,7 +224,9 @@ authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<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><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> </ul>
<p class=return> <p class=return>

View File

@ -131,7 +131,8 @@ http.<b>request{</b><br>
&nbsp;&nbsp;[source = <i>LTN12 source</i>],<br> &nbsp;&nbsp;[source = <i>LTN12 source</i>],<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> &nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[proxy = <i>string</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> <b>}</b>
</p> </p>
@ -178,7 +179,9 @@ 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><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><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><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> </ul>
<p class=return> <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: <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 <li> Improved: HTTP, SMTP, and FTP functions to accept a new field
<tt>create</tt> that overrides the function used to create socket objects; <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 <li> Fixed: <tt>url.absolute()</tt> to work when <tt>base_url</tt> is in
parsed form; parsed form;
<li> Fixed: <tt>http.request()</tt> not to redirect when the location <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 <li> Fixed: "Bug" that caused <tt>gethostbyname</tt> to crash under VMS
(Renato Maia); (Renato Maia);
<li> Fixed: <tt>tcp:send("")</tt> to return 0 bytes sent (Alexander Marinov); <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> </ul>
<!-- incompatible +++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- incompatible +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->

View File

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

View File

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

View File

@ -127,6 +127,7 @@ smtp.<b>send{</b><br>
&nbsp;&nbsp;[port = <i>number</i>,]<br> &nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[domain = <i>string</i>,]<br> &nbsp;&nbsp;[domain = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br> &nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b> <b>}</b>
</p> </p>
@ -138,6 +139,7 @@ doesn't have a simple interface. However, see the
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
@ -158,7 +160,9 @@ local machine host name;
<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><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> </ul>
<p class=return> <p class=return>
@ -167,7 +171,7 @@ If successful, the function returns 1. Otherwise, the function returns
</p> </p>
<p class=note> <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 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

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

View File

@ -79,7 +79,7 @@ reported by <b><tt>nil</tt></b> followed by a message describing the error.
<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>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 <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.
@ -111,7 +111,7 @@ method returns <b><tt>nil</tt></b> followed by an error message.
<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 server sockets. is available and is a shortcut for the creation of server sockets.
</p> </p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -173,8 +173,11 @@ is available and is a shortcut for the creation of client sockets.
<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 connect, causing it to return in case of method affects the behavior of <tt>connect</tt>, causing it to return
a timeout. 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> </p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -328,11 +331,11 @@ substring to be sent.
</p> </p>
<p class=return> <p class=return>
If successful, the method returns the number of bytes accepted by If successful, the method returns the number of bytes sent.
the transport layer. In case of error, the method returns In case of error, the method returns
<b><tt>nil</tt></b>, followed by an error message, followed by the <b><tt>nil</tt></b>, followed by an error message, followed by the
partial number of bytes accepted by the transport layer. index of the first character within <tt>[i, j]</tt> that has not been sent yet
The error message can be '<tt>closed</tt>' in case (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 the connection was closed before the transmission was completed or the
string '<tt>timeout</tt>' in case there was a timeout during the string '<tt>timeout</tt>' in case there was a timeout during the
operation. operation.
@ -433,7 +436,7 @@ of bandwidth.
<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> <tt>Age</tt> is the new age in seconds.
</p> </p>
<p class=return> <p class=return>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -108,7 +108,7 @@ static int base_open(lua_State *L) {
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Initializes all library modules. * Initializes all library modules.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socketcore(lua_State *L) { LUASOCKET_API int luaopen_socket_core(lua_State *L) {
int i; int i;
base_open(L); base_open(L);
for (i = 0; mod[i].name; i++) mod[i].func(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 io = require("io")
local string = require("string") local string = require("string")
module("mime") module("mime")
getmetatable(_M).__index = nil
-- encode, decode and wrap algorithm tables -- encode, decode and wrap algorithm tables
encodet = {} encodet = {}
@ -84,5 +85,3 @@ end
function stuff() function stuff()
return ltn12.filter.cycle(dot, 2) return ltn12.filter.cycle(dot, 2)
end end
--getmetatable(_M).__index = nil

View File

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

View File

@ -12,6 +12,7 @@ local string = require("string")
local math = require("math") local math = require("math")
local socket = require("socket.core") local socket = require("socket.core")
module("socket") module("socket")
getmetatable(_M).__index = nil
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Exported auxiliar functions -- Exported auxiliar functions
@ -131,5 +132,3 @@ sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet) 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 socket = require("socket")
local ltn12 = require("ltn12") local ltn12 = require("ltn12")
module("socket.tp") module("socket.tp")
getmetatable(_M).__index = nil
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Program constants -- Program constants
@ -98,7 +99,8 @@ end
function metat.__index:source(source, step) function metat.__index:source(source, step)
local sink = socket.sink("keep-open", self.c) 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 end
-- closes the underlying c -- closes the underlying c
@ -108,8 +110,8 @@ function metat.__index:close()
end end
-- connect with server and return c object -- connect with server and return c object
function connect(host, port, timeout) function connect(host, port, create, timeout)
local c, e = socket.tcp() local c, e = (create or socket.tcp())
if not c then return nil, e end if not c then return nil, e end
c:settimeout(timeout or TIMEOUT) c:settimeout(timeout or TIMEOUT)
local r, e = c:connect(host, port) local r, e = c:connect(host, port)
@ -120,4 +122,3 @@ function connect(host, port, timeout)
return base.setmetatable({c = c}, metat) return base.setmetatable({c = c}, metat)
end end
--getmetatable(_M).__index = nil

View File

@ -12,6 +12,7 @@ local string = require("string")
local base = _G local base = _G
local table = require("table") local table = require("table")
module("socket.url") module("socket.url")
getmetatable(_M).__index = nil
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation -- Encodes a string into its escaped hexadecimal representation
@ -279,4 +280,3 @@ function build_path(parsed, unsafe)
return path return path
end 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); double t = tm_get(tm);
tv.tv_sec = (int) t; tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); 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{
} }
} }
--[[ function filter(s)
sink = ltn12.sink.file(io.stdout) if s then io.write(s) end
ltn12.pump.all(source, sink) return s
]] end
-- finally send it
r, e = smtp.send{ r, e = smtp.send{
rcpt = {"<diego@tecgraf.puc-rio.br>", rcpt = {"<diego@tecgraf.puc-rio.br>",
"<diego@princeton.edu>" }, "<diego@princeton.edu>" },
from = "<diego@princeton.edu>", from = "<diego@princeton.edu>",
source = source, source = ltn12.source.chain(source, filter),
server = "mail.cs.princeton.edu" --server = "mail.cs.princeton.edu"
server = "localhost",
port = 2525
} }
print(r, e) print(r, e)