mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 12:28:21 +01:00
Compiled on Windows. Fixed a bunch of stuff. Almost ready to release.
Implemented a nice dispatcher! Non-blocking check-links and forward server use the dispatcher.
This commit is contained in:
parent
5e8ae76248
commit
773e35ced3
9
TODO
9
TODO
@ -1,11 +1,9 @@
|
|||||||
new instalation scheme???
|
new instalation scheme???
|
||||||
|
|
||||||
test empty socket.select no windows.
|
test empty socket.select no windows.
|
||||||
|
|
||||||
bug by mathew percival?
|
bug by mathew percival?
|
||||||
|
|
||||||
arranjar um jeito de fazer multipart/alternative
|
|
||||||
|
|
||||||
what the hell does __unload do?
|
|
||||||
|
|
||||||
test it on Windows!!!
|
test it on Windows!!!
|
||||||
|
|
||||||
leave code for losers that don't have nanosleep
|
leave code for losers that don't have nanosleep
|
||||||
@ -45,3 +43,6 @@ testar os options!
|
|||||||
* received connections
|
* received connections
|
||||||
* - this function is invoked with the client socket
|
* - this function is invoked with the client socket
|
||||||
* - it calls special send and receive functions that yield on timeout
|
* - it calls special send and receive functions that yield on timeout
|
||||||
|
* arranjar um jeito de fazer multipart/alternative
|
||||||
|
* what the hell does __unload do?
|
||||||
|
* it's there just in case someone wants to use it.
|
||||||
|
12
config
12
config
@ -8,8 +8,8 @@
|
|||||||
EXT=so
|
EXT=so
|
||||||
SOCKET_V=2.0.0
|
SOCKET_V=2.0.0
|
||||||
MIME_V=1.0.0
|
MIME_V=1.0.0
|
||||||
SOCKET_SO=socket-core.$(EXT).$(SOCKET_V)
|
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
|
||||||
MIME_SO=mime-core.$(EXT).$(MIME_V)
|
MIME_SO=mime.$(EXT).$(MIME_V)
|
||||||
UNIX_SO=unix.$(EXT)
|
UNIX_SO=unix.$(EXT)
|
||||||
|
|
||||||
#------
|
#------
|
||||||
@ -25,13 +25,15 @@ COMPAT=compat-5.1r4
|
|||||||
|
|
||||||
#------
|
#------
|
||||||
# Top of your Lua installation
|
# Top of your Lua installation
|
||||||
# Relative paths will be inside src tree
|
# Relative paths will be inside the src tree
|
||||||
#
|
#
|
||||||
INSTALL_TOP=/usr/local/share/lua/5.0
|
#INSTALL_TOP_LUA=/usr/local/share/lua/5.0
|
||||||
|
#INSTALL_TOP_LIB=/usr/local/lib/lua/5.0
|
||||||
|
INSTALL_TOP_LUA=share
|
||||||
|
INSTALL_TOP_LIB=lib
|
||||||
|
|
||||||
INSTALL_DATA=cp
|
INSTALL_DATA=cp
|
||||||
INSTALL_EXEC=cp
|
INSTALL_EXEC=cp
|
||||||
INSTALL_LINK=ln
|
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Compiler and linker settings
|
# Compiler and linker settings
|
||||||
|
@ -168,6 +168,8 @@ 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> Improved: <tt>smtp.message</tt> now supports multipart/alternative
|
||||||
|
(for the HTML messages we all love so much);
|
||||||
<li> Fixed: <tt>smtp.send</tt> was hanging on errors returned by LTN12 sources;
|
<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;
|
||||||
@ -183,7 +185,7 @@ group;
|
|||||||
<li> Improved: Socket and MIME binaries are called 'core' each inside their
|
<li> Improved: Socket and MIME binaries are called 'core' each inside their
|
||||||
directory (ex. "socket/core.dll"). The 'l' prefix was just a bad idea;
|
directory (ex. "socket/core.dll"). The 'l' prefix was just a bad idea;
|
||||||
<li> Improved: Using bundles in Mac OS X, instead of dylibs;
|
<li> Improved: Using bundles in Mac OS X, instead of dylibs;
|
||||||
<li> Fixed: <tt>luasocket.h</tt> to export <tt>luaopen_socketcore</tt>;
|
<li> Fixed: <tt>luasocket.h</tt> to export <tt>luaopen_socket_core</tt>;
|
||||||
<li> Fixed: <tt>udp:setpeername()</tt> so you can "disconnect" an
|
<li> Fixed: <tt>udp:setpeername()</tt> so you can "disconnect" an
|
||||||
<tt>UDP</tt> socket;
|
<tt>UDP</tt> socket;
|
||||||
<li> Fixed: A weird bug in HTTP support that caused some requests to
|
<li> Fixed: A weird bug in HTTP support that caused some requests to
|
||||||
|
@ -5,33 +5,26 @@
|
|||||||
-- Author: Diego Nehab
|
-- Author: Diego Nehab
|
||||||
-- RCS ID: $$
|
-- RCS ID: $$
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local dispatch, url, http, handler
|
local url = require("socket.url")
|
||||||
|
local dispatch = require("dispatch")
|
||||||
|
local http = require("socket.http")
|
||||||
|
dispatch.TIMEOUT = 10
|
||||||
|
|
||||||
|
-- make sure the user knows how to invoke us
|
||||||
arg = arg or {}
|
arg = arg or {}
|
||||||
if table.getn(arg) < 1 then
|
if table.getn(arg) < 1 then
|
||||||
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
|
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
|
||||||
exit()
|
exit()
|
||||||
end
|
end
|
||||||
|
|
||||||
if arg[1] ~= "-n" then
|
-- '-n' means we are running in non-blocking mode
|
||||||
-- if using blocking I/O, simulate dispatcher interface
|
if arg[1] == "-n" then
|
||||||
url = require("socket.url")
|
-- if non-blocking I/O was requested, use real dispatcher interface
|
||||||
http = require("socket.http")
|
|
||||||
handler = {
|
|
||||||
start = function(self, f)
|
|
||||||
f()
|
|
||||||
end,
|
|
||||||
tcp = socket.tcp
|
|
||||||
}
|
|
||||||
http.TIMEOUT = 10
|
|
||||||
else
|
|
||||||
-- if non-blocking I/O was requested, disable dispatcher
|
|
||||||
table.remove(arg, 1)
|
table.remove(arg, 1)
|
||||||
dispatch = require("dispatch")
|
handler = dispatch.newhandler("coroutine")
|
||||||
dispatch.TIMEOUT = 10
|
else
|
||||||
url = require("socket.url")
|
-- if using blocking I/O, use fake dispatcher interface
|
||||||
http = require("socket.http")
|
handler = dispatch.newhandler("sequential")
|
||||||
handler = dispatch.newhandler()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local nthreads = 0
|
local nthreads = 0
|
||||||
|
404
etc/dispatch.lua
404
etc/dispatch.lua
@ -11,23 +11,33 @@ module("dispatch")
|
|||||||
|
|
||||||
-- if too much time goes by without any activity in one of our sockets, we
|
-- if too much time goes by without any activity in one of our sockets, we
|
||||||
-- just kill it
|
-- just kill it
|
||||||
TIMEOUT = 10
|
TIMEOUT = 60
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Mega hack. Don't try to do this at home.
|
-- We implement 3 types of dispatchers:
|
||||||
|
-- sequential
|
||||||
|
-- coroutine
|
||||||
|
-- threaded
|
||||||
|
-- The user can choose whatever one is needed
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Lua 5.1 has coroutine.running(). We need it here, so we use this terrible
|
local handlert = {}
|
||||||
-- hack to emulate it in Lua itself
|
|
||||||
-- This is very inefficient, but is very good for debugging.
|
-- default handler is coroutine
|
||||||
local running
|
function newhandler(mode)
|
||||||
local resume = coroutine.resume
|
mode = mode or "coroutine"
|
||||||
function coroutine.resume(co, ...)
|
return handlert[mode]()
|
||||||
running = co
|
|
||||||
return resume(co, unpack(arg))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function coroutine.running()
|
local function seqstart(self, func)
|
||||||
return running
|
return func()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- sequential handler simply calls the functions and doesn't wrap I/O
|
||||||
|
function handlert.sequential()
|
||||||
|
return {
|
||||||
|
tcp = socket.tcp,
|
||||||
|
start = seqstart
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
@ -36,15 +46,11 @@ end
|
|||||||
-- we can't yield across calls to protect, so we rewrite it with coxpcall
|
-- we can't yield across calls to protect, so we rewrite it with coxpcall
|
||||||
-- make sure you don't require any module that uses socket.protect before
|
-- make sure you don't require any module that uses socket.protect before
|
||||||
-- loading our hack
|
-- loading our hack
|
||||||
function socket.protect(f)
|
|
||||||
return f
|
|
||||||
end
|
|
||||||
|
|
||||||
function socket.protect(f)
|
function socket.protect(f)
|
||||||
return function(...)
|
return function(...)
|
||||||
local co = coroutine.create(f)
|
local co = coroutine.create(f)
|
||||||
while true do
|
while true do
|
||||||
local results = {resume(co, unpack(arg))}
|
local results = {coroutine.resume(co, unpack(arg))}
|
||||||
local status = table.remove(results, 1)
|
local status = table.remove(results, 1)
|
||||||
if not status then
|
if not status then
|
||||||
if type(results[1]) == 'table' then
|
if type(results[1]) == 'table' then
|
||||||
@ -61,133 +67,7 @@ function socket.protect(f)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- socket.tcp() replacement for non-blocking I/O
|
-- Simple set data structure. O(1) everything.
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function newtrap(dispatcher)
|
|
||||||
-- try to create underlying socket
|
|
||||||
local tcp, error = socket.tcp()
|
|
||||||
if not tcp then return nil, error end
|
|
||||||
-- put it in non-blocking mode right away
|
|
||||||
tcp:settimeout(0)
|
|
||||||
-- metatable for trap produces new methods on demand for those that we
|
|
||||||
-- don't override explicitly.
|
|
||||||
local metat = { __index = function(table, key)
|
|
||||||
table[key] = function(...)
|
|
||||||
return tcp[key](tcp, unpack(arg))
|
|
||||||
end
|
|
||||||
end}
|
|
||||||
-- does user want to do his own non-blocking I/O?
|
|
||||||
local zero = false
|
|
||||||
-- create a trap object that will behave just like a real socket object
|
|
||||||
local trap = { }
|
|
||||||
-- we ignore settimeout to preserve our 0 timeout, but record whether
|
|
||||||
-- the user wants to do his own non-blocking I/O
|
|
||||||
function trap:settimeout(mode, value)
|
|
||||||
if value == 0 then
|
|
||||||
zero = true
|
|
||||||
else
|
|
||||||
zero = false
|
|
||||||
end
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
-- send in non-blocking mode and yield on timeout
|
|
||||||
function trap:send(data, first, last)
|
|
||||||
first = (first or 1) - 1
|
|
||||||
local result, error
|
|
||||||
while true do
|
|
||||||
-- tell dispatcher we want to keep sending before we yield
|
|
||||||
dispatcher.sending:insert(tcp)
|
|
||||||
-- mark time we started waiting
|
|
||||||
dispatcher.context[tcp].last = socket.gettime()
|
|
||||||
-- 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
|
|
||||||
-- try sending
|
|
||||||
result, error, first = tcp:send(data, first+1, last)
|
|
||||||
-- 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
|
|
||||||
-- or simply return partial read, if user requested timeout = 0
|
|
||||||
function trap:receive(pattern, partial)
|
|
||||||
local error = "timeout"
|
|
||||||
local value
|
|
||||||
while true do
|
|
||||||
-- tell dispatcher we want to keep receiving before we yield
|
|
||||||
dispatcher.receiving:insert(tcp)
|
|
||||||
-- mark time we started waiting
|
|
||||||
dispatcher.context[tcp].last = socket.gettime()
|
|
||||||
-- 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
|
|
||||||
-- try receiving
|
|
||||||
value, error, partial = tcp:receive(pattern, partial)
|
|
||||||
-- if we are done, or there was an unexpected error,
|
|
||||||
-- break away from loop
|
|
||||||
if (error ~= "timeout") or zero then
|
|
||||||
return value, error, partial
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- connect in non-blocking mode and yield on timeout
|
|
||||||
function trap:connect(host, port)
|
|
||||||
local result, error = tcp:connect(host, port)
|
|
||||||
-- mark time we started waiting
|
|
||||||
dispatcher.context[tcp].last = socket.gettime()
|
|
||||||
if error == "timeout" then
|
|
||||||
-- tell dispatcher we will be able to write uppon connection
|
|
||||||
dispatcher.sending:insert(tcp)
|
|
||||||
-- 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
|
|
||||||
-- when we come back, check if connection was successful
|
|
||||||
result, error = tcp:connect(host, port)
|
|
||||||
if result or error == "already connected" then return 1
|
|
||||||
else return nil, "non-blocking connect failed" end
|
|
||||||
else return result, error end
|
|
||||||
end
|
|
||||||
-- accept in non-blocking mode and yield on timeout
|
|
||||||
function trap:accept()
|
|
||||||
local result, error = tcp:accept()
|
|
||||||
while error == "timeout" do
|
|
||||||
-- mark time we started waiting
|
|
||||||
dispatcher.context[tcp].last = socket.gettime()
|
|
||||||
-- tell dispatcher we will be able to read uppon connection
|
|
||||||
dispatcher.receiving:insert(tcp)
|
|
||||||
-- 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
|
|
||||||
end
|
|
||||||
return result, error
|
|
||||||
end
|
|
||||||
-- remove thread from context
|
|
||||||
function trap:close()
|
|
||||||
dispatcher.context[tcp] = nil
|
|
||||||
return tcp:close()
|
|
||||||
end
|
|
||||||
-- add newly created socket to context
|
|
||||||
dispatcher.context[tcp] = {
|
|
||||||
thread = coroutine.running()
|
|
||||||
}
|
|
||||||
return setmetatable(trap, metat)
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Our set data structure
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local function newset()
|
local function newset()
|
||||||
local reverse = {}
|
local reverse = {}
|
||||||
@ -214,54 +94,208 @@ local function newset()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Our dispatcher API.
|
-- socket.tcp() wrapper for the coroutine dispatcher
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
local metat = { __index = {} }
|
local function cowrap(dispatcher, tcp, error)
|
||||||
|
if not tcp then return nil, error end
|
||||||
function metat.__index:start(func)
|
-- put it in non-blocking mode right away
|
||||||
local co = coroutine.create(func)
|
tcp:settimeout(0)
|
||||||
assert(coroutine.resume(co))
|
-- metatable for wrap produces new methods on demand for those that we
|
||||||
end
|
-- don't override explicitly.
|
||||||
|
local metat = { __index = function(table, key)
|
||||||
function newhandler()
|
table[key] = function(...)
|
||||||
local dispatcher = {
|
arg[1] = tcp
|
||||||
context = {},
|
return tcp[key](unpack(arg))
|
||||||
sending = newset(),
|
|
||||||
receiving = newset()
|
|
||||||
}
|
|
||||||
function dispatcher.tcp()
|
|
||||||
return newtrap(dispatcher)
|
|
||||||
end
|
|
||||||
return setmetatable(dispatcher, metat)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- step through all active threads
|
|
||||||
function metat.__index:step()
|
|
||||||
-- check which sockets are interesting and act on them
|
|
||||||
local readable, writable = socket.select(self.receiving,
|
|
||||||
self.sending, 1)
|
|
||||||
-- for all readable connections, resume their threads
|
|
||||||
for _, who in ipairs(readable) do
|
|
||||||
if self.context[who] then
|
|
||||||
self.receiving:remove(who)
|
|
||||||
assert(coroutine.resume(self.context[who].thread))
|
|
||||||
end
|
end
|
||||||
|
return table[key]
|
||||||
|
end}
|
||||||
|
-- does our user want to do his own non-blocking I/O?
|
||||||
|
local zero = false
|
||||||
|
-- create a wrap object that will behave just like a real socket object
|
||||||
|
local wrap = { }
|
||||||
|
-- we ignore settimeout to preserve our 0 timeout, but record whether
|
||||||
|
-- the user wants to do his own non-blocking I/O
|
||||||
|
function wrap:settimeout(value, mode)
|
||||||
|
if value == 0 then zero = true
|
||||||
|
else zero = false end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
-- send in non-blocking mode and yield on timeout
|
||||||
|
function wrap:send(data, first, last)
|
||||||
|
first = (first or 1) - 1
|
||||||
|
local result, error
|
||||||
|
while true do
|
||||||
|
-- return control to dispatcher and tell it we want to send
|
||||||
|
-- if upon return the dispatcher tells us we timed out,
|
||||||
|
-- return an error to whoever called us
|
||||||
|
if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
|
||||||
|
return nil, "timeout"
|
||||||
|
end
|
||||||
|
-- try sending
|
||||||
|
result, error, first = tcp:send(data, first+1, last)
|
||||||
|
-- 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
|
||||||
|
-- or simply return partial read, if user requested timeout = 0
|
||||||
|
function wrap:receive(pattern, partial)
|
||||||
|
local error = "timeout"
|
||||||
|
local value
|
||||||
|
while true do
|
||||||
|
-- return control to dispatcher and tell it we want to receive
|
||||||
|
-- if upon return the dispatcher tells us we timed out,
|
||||||
|
-- return an error to whoever called us
|
||||||
|
if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
|
||||||
|
return nil, "timeout"
|
||||||
|
end
|
||||||
|
-- try receiving
|
||||||
|
value, error, partial = tcp:receive(pattern, partial)
|
||||||
|
-- if we are done, or there was an unexpected error,
|
||||||
|
-- break away from loop. also, if the user requested
|
||||||
|
-- zero timeout, return all we got
|
||||||
|
if (error ~= "timeout") or zero then
|
||||||
|
return value, error, partial
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- connect in non-blocking mode and yield on timeout
|
||||||
|
function wrap:connect(host, port)
|
||||||
|
local result, error = tcp:connect(host, port)
|
||||||
|
if error == "timeout" then
|
||||||
|
-- return control to dispatcher. we will be writable when
|
||||||
|
-- connection succeeds.
|
||||||
|
-- if upon return the dispatcher tells us we have a
|
||||||
|
-- timeout, just abort
|
||||||
|
if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
|
||||||
|
return nil, "timeout"
|
||||||
|
end
|
||||||
|
-- when we come back, check if connection was successful
|
||||||
|
result, error = tcp:connect(host, port)
|
||||||
|
if result or error == "already connected" then return 1
|
||||||
|
else return nil, "non-blocking connect failed" end
|
||||||
|
else return result, error end
|
||||||
|
end
|
||||||
|
-- accept in non-blocking mode and yield on timeout
|
||||||
|
function wrap:accept()
|
||||||
|
while 1 do
|
||||||
|
-- return control to dispatcher. we will be readable when a
|
||||||
|
-- connection arrives.
|
||||||
|
-- if upon return the dispatcher tells us we have a
|
||||||
|
-- timeout, just abort
|
||||||
|
if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
|
||||||
|
return nil, "timeout"
|
||||||
|
end
|
||||||
|
local client, error = tcp:accept()
|
||||||
|
if error ~= "timeout" then
|
||||||
|
return cowrap(dispatcher, client, error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- remove cortn from context
|
||||||
|
function wrap:close()
|
||||||
|
dispatcher.stamp[tcp] = nil
|
||||||
|
dispatcher.sending.set:remove(tcp)
|
||||||
|
dispatcher.sending.cortn[tcp] = nil
|
||||||
|
dispatcher.receiving.set:remove(tcp)
|
||||||
|
dispatcher.receiving.cortn[tcp] = nil
|
||||||
|
return tcp:close()
|
||||||
|
end
|
||||||
|
return setmetatable(wrap, metat)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- Our coroutine dispatcher
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
local cometat = { __index = {} }
|
||||||
|
|
||||||
|
function schedule(cortn, status, operation, tcp)
|
||||||
|
if status then
|
||||||
|
if cortn and operation then
|
||||||
|
operation.set:insert(tcp)
|
||||||
|
operation.cortn[tcp] = cortn
|
||||||
|
operation.stamp[tcp] = socket.gettime()
|
||||||
|
end
|
||||||
|
else error(operation) end
|
||||||
|
end
|
||||||
|
|
||||||
|
function kick(operation, tcp)
|
||||||
|
operation.cortn[tcp] = nil
|
||||||
|
operation.set:remove(tcp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function wakeup(operation, tcp)
|
||||||
|
local cortn = operation.cortn[tcp]
|
||||||
|
-- if cortn is still valid, wake it up
|
||||||
|
if cortn then
|
||||||
|
kick(operation, tcp)
|
||||||
|
return cortn, coroutine.resume(cortn)
|
||||||
|
-- othrewise, just get scheduler not to do anything
|
||||||
|
else
|
||||||
|
return nil, true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function abort(operation, tcp)
|
||||||
|
local cortn = operation.cortn[tcp]
|
||||||
|
if cortn then
|
||||||
|
kick(operation, tcp)
|
||||||
|
coroutine.resume(cortn, "timeout")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- step through all active cortns
|
||||||
|
function cometat.__index:step()
|
||||||
|
-- check which sockets are interesting and act on them
|
||||||
|
local readable, writable = socket.select(self.receiving.set,
|
||||||
|
self.sending.set, 1)
|
||||||
|
-- for all readable connections, resume their cortns and reschedule
|
||||||
|
-- when they yield back to us
|
||||||
|
for _, tcp in ipairs(readable) do
|
||||||
|
schedule(wakeup(self.receiving, tcp))
|
||||||
end
|
end
|
||||||
-- for all writable connections, do the same
|
-- for all writable connections, do the same
|
||||||
for _, who in ipairs(writable) do
|
for _, tcp in ipairs(writable) do
|
||||||
if self.context[who] then
|
schedule(wakeup(self.sending, tcp))
|
||||||
self.sending:remove(who)
|
|
||||||
assert(coroutine.resume(self.context[who].thread))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
-- politely ask replacement I/O functions in idle threads to
|
-- politely ask replacement I/O functions in idle cortns to
|
||||||
-- return reporting a timeout
|
-- return reporting a timeout
|
||||||
local now = socket.gettime()
|
local now = socket.gettime()
|
||||||
for who, data in pairs(self.context) do
|
for tcp, stamp in pairs(self.stamp) do
|
||||||
if data.last and now - data.last > TIMEOUT then
|
if tcp.class == "tcp{client}" and now - stamp > TIMEOUT then
|
||||||
self.sending:remove(who)
|
abort(self.sending, tcp)
|
||||||
self.receiving:remove(who)
|
abort(self.receiving, tcp)
|
||||||
assert(coroutine.resume(self.context[who].thread, "timeout"))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function cometat.__index:start(func)
|
||||||
|
local cortn = coroutine.create(func)
|
||||||
|
schedule(cortn, coroutine.resume(cortn))
|
||||||
|
end
|
||||||
|
|
||||||
|
function handlert.coroutine()
|
||||||
|
local stamp = {}
|
||||||
|
local dispatcher = {
|
||||||
|
stamp = stamp,
|
||||||
|
sending = {
|
||||||
|
name = "sending",
|
||||||
|
set = newset(),
|
||||||
|
cortn = {},
|
||||||
|
stamp = stamp
|
||||||
|
},
|
||||||
|
receiving = {
|
||||||
|
name = "receiving",
|
||||||
|
set = newset(),
|
||||||
|
cortn = {},
|
||||||
|
stamp = stamp
|
||||||
|
},
|
||||||
|
}
|
||||||
|
function dispatcher.tcp()
|
||||||
|
return cowrap(dispatcher, socket.tcp())
|
||||||
|
end
|
||||||
|
return setmetatable(dispatcher, cometat)
|
||||||
|
end
|
||||||
|
|
||||||
|
65
etc/forward.lua
Normal file
65
etc/forward.lua
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
-- load our favourite library
|
||||||
|
local dispatch = require("dispatch")
|
||||||
|
local handler = dispatch.newhandler()
|
||||||
|
|
||||||
|
-- make sure the user knows how to invoke us
|
||||||
|
if table.getn(arg) < 1 then
|
||||||
|
print("Usage")
|
||||||
|
print(" lua forward.lua <iport:ohost:oport> ...")
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- function to move data from one socket to the other
|
||||||
|
local function move(foo, bar)
|
||||||
|
local live
|
||||||
|
while 1 do
|
||||||
|
local data, error, partial = foo:receive(2048)
|
||||||
|
live = data or error == "timeout"
|
||||||
|
data = data or partial
|
||||||
|
local result, error = bar:send(data)
|
||||||
|
if not live or not result then
|
||||||
|
foo:close()
|
||||||
|
bar:close()
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- for each tunnel, start a new server
|
||||||
|
for i, v in ipairs(arg) do
|
||||||
|
-- capture forwarding parameters
|
||||||
|
local _, _, iport, ohost, oport = string.find(v, "([^:]+):([^:]+):([^:]+)")
|
||||||
|
assert(iport, "invalid arguments")
|
||||||
|
-- create our server socket
|
||||||
|
local server = assert(handler.tcp())
|
||||||
|
assert(server:setoption("reuseaddr", true))
|
||||||
|
assert(server:bind("*", iport))
|
||||||
|
assert(server:listen(32))
|
||||||
|
-- handler for the server object loops accepting new connections
|
||||||
|
handler:start(function()
|
||||||
|
while 1 do
|
||||||
|
local client = assert(server:accept())
|
||||||
|
assert(client:settimeout(0))
|
||||||
|
-- for each new connection, start a new client handler
|
||||||
|
handler:start(function()
|
||||||
|
-- handler tries to connect to peer
|
||||||
|
local peer = assert(handler.tcp())
|
||||||
|
assert(peer:settimeout(0))
|
||||||
|
assert(peer:connect(ohost, oport))
|
||||||
|
-- if sucessful, starts a new handler to send data from
|
||||||
|
-- client to peer
|
||||||
|
handler:start(function()
|
||||||
|
move(client, peer)
|
||||||
|
end)
|
||||||
|
-- afte starting new handler, enter in loop sending data from
|
||||||
|
-- peer to client
|
||||||
|
move(peer, client)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- simply loop stepping the server
|
||||||
|
while 1 do
|
||||||
|
handler:step()
|
||||||
|
end
|
@ -1,5 +1,5 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "luasocket.vcproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
37
makefile
37
makefile
@ -6,8 +6,10 @@ include config
|
|||||||
#------
|
#------
|
||||||
# Hopefully no need to change anything below this line
|
# Hopefully no need to change anything below this line
|
||||||
#
|
#
|
||||||
INSTALL_SOCKET=$(INSTALL_TOP)/socket
|
INSTALL_SOCKET_LUA=$(INSTALL_TOP_LUA)/socket
|
||||||
INSTALL_MIME=$(INSTALL_TOP)/mime
|
INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
|
||||||
|
INSTALL_MIME_LUA=$(INSTALL_TOP_LUA)/mime
|
||||||
|
INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
|
||||||
|
|
||||||
all clean:
|
all clean:
|
||||||
cd src; $(MAKE) $@
|
cd src; $(MAKE) $@
|
||||||
@ -15,7 +17,7 @@ all clean:
|
|||||||
#------
|
#------
|
||||||
# Files to install
|
# Files to install
|
||||||
#
|
#
|
||||||
TO_SOCKET:= \
|
TO_SOCKET_LUA:= \
|
||||||
socket.lua \
|
socket.lua \
|
||||||
http.lua \
|
http.lua \
|
||||||
url.lua \
|
url.lua \
|
||||||
@ -23,29 +25,28 @@ TO_SOCKET:= \
|
|||||||
ftp.lua \
|
ftp.lua \
|
||||||
smtp.lua
|
smtp.lua
|
||||||
|
|
||||||
TO_TOP:= \
|
TO_TOP_LUA:= \
|
||||||
ltn12.lua
|
ltn12.lua
|
||||||
|
|
||||||
TO_MIME:= \
|
TO_MIME_LUA:= \
|
||||||
$(MIME_SO) \
|
|
||||||
mime.lua
|
mime.lua
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# Install LuaSocket according to recommendation
|
# Install LuaSocket according to recommendation
|
||||||
#
|
#
|
||||||
install: all
|
install: all
|
||||||
cd src; mkdir -p $(INSTALL_TOP)
|
cd src; mkdir -p $(INSTALL_TOP_LUA)
|
||||||
cd src; $(INSTALL_DATA) $(COMPAT)/compat-5.1.lua $(INSTALL_TOP)
|
cd src; mkdir -p $(INSTALL_TOP_LIB)
|
||||||
cd src; $(INSTALL_DATA) ltn12.lua $(INSTALL_TOP)
|
cd src; $(INSTALL_DATA) $(COMPAT)/compat-5.1.lua $(INSTALL_TOP_LUA)
|
||||||
cd src; mkdir -p $(INSTALL_SOCKET)
|
cd src; $(INSTALL_DATA) ltn12.lua $(INSTALL_TOP_LUA)
|
||||||
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET)
|
cd src; mkdir -p $(INSTALL_SOCKET_LUA)
|
||||||
cd src; $(INSTALL_DATA) $(TO_SOCKET) $(INSTALL_SOCKET)
|
cd src; mkdir -p $(INSTALL_SOCKET_LIB)
|
||||||
cd src; cd $(INSTALL_SOCKET); $(INSTALL_LINK) -s $(SOCKET_SO) core.$(EXT)
|
cd src; $(INSTALL_DATA) $(TO_SOCKET_LUA) $(INSTALL_SOCKET_LUA)
|
||||||
cd src; cd $(INSTALL_SOCKET); $(INSTALL_LINK) -s socket.lua init.lua
|
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT)
|
||||||
cd src; mkdir -p $(INSTALL_MIME)
|
cd src; mkdir -p $(INSTALL_MIME_LUA)
|
||||||
cd src; $(INSTALL_DATA) $(TO_MIME) $(INSTALL_MIME)
|
cd src; mkdir -p $(INSTALL_MIME_LIB)
|
||||||
cd src; cd $(INSTALL_MIME); $(INSTALL_LINK) -s $(MIME_SO) core.$(EXT)
|
cd src; $(INSTALL_DATA) $(TO_MIME_LUA) $(INSTALL_MIME_LUA)
|
||||||
cd src; cd $(INSTALL_MIME); $(INSTALL_LINK) -s mime.lua init.lua
|
cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
|
||||||
|
|
||||||
#------
|
#------
|
||||||
# End of makefile
|
# End of makefile
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
# Distribution makefile
|
# Distribution makefile
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
DIST = luasocket-2.0-beta3
|
DIST = luasocket-2.0
|
||||||
|
|
||||||
COMPAT = compat-5.1r2
|
COMPAT = compat-5.1r4
|
||||||
|
|
||||||
LUA = \
|
LUA = \
|
||||||
ftp.lua \
|
ftp.lua \
|
||||||
@ -37,6 +37,7 @@ EXAMPLES = \
|
|||||||
|
|
||||||
ETC = \
|
ETC = \
|
||||||
check-links.lua \
|
check-links.lua \
|
||||||
|
check-links-nb.lua \
|
||||||
dict.lua \
|
dict.lua \
|
||||||
get.lua \
|
get.lua \
|
||||||
unix.c \
|
unix.c \
|
||||||
@ -76,8 +77,8 @@ CORE = \
|
|||||||
wsocket.h
|
wsocket.h
|
||||||
|
|
||||||
MAKE = \
|
MAKE = \
|
||||||
makefile.Darwin \
|
makefile \
|
||||||
makefile.Linux \
|
config \
|
||||||
luasocket.sln \
|
luasocket.sln \
|
||||||
luasocket.vcproj \
|
luasocket.vcproj \
|
||||||
mime.vcproj
|
mime.vcproj
|
||||||
|
32
mime.vcproj
32
mime.vcproj
@ -12,18 +12,18 @@
|
|||||||
<Configurations>
|
<Configurations>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Debug|Win32"
|
Name="Debug|Win32"
|
||||||
OutputDirectory=".\"
|
OutputDirectory="src"
|
||||||
IntermediateDirectory=".\"
|
IntermediateDirectory="src"
|
||||||
ConfigurationType="2"
|
ConfigurationType="2"
|
||||||
CharacterSet="2">
|
CharacterSet="2">
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="..\..\include, compat-5.1r2"
|
AdditionalIncludeDirectories="src\compat-5.1r4, ..\lua-5.0.2\include"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;MIME_API=__declspec(dllexport)"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;MIME_API=__declspec(dllexport)"
|
||||||
MinimalRebuild="TRUE"
|
MinimalRebuild="TRUE"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="5"
|
RuntimeLibrary="3"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
@ -32,7 +32,7 @@
|
|||||||
Name="VCCustomBuildTool"/>
|
Name="VCCustomBuildTool"/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
OutputFile="$(OutDir)/cmime.dll"
|
OutputFile="$(OutDir)/mime.dll"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="TRUE"
|
GenerateDebugInformation="TRUE"
|
||||||
ProgramDatabaseFile="$(OutDir)/mime.pdb"
|
ProgramDatabaseFile="$(OutDir)/mime.pdb"
|
||||||
@ -62,15 +62,15 @@
|
|||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Release|Win32"
|
Name="Release|Win32"
|
||||||
OutputDirectory="."
|
OutputDirectory="src"
|
||||||
IntermediateDirectory="."
|
IntermediateDirectory="src"
|
||||||
ConfigurationType="2"
|
ConfigurationType="2"
|
||||||
CharacterSet="2">
|
CharacterSet="2">
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
AdditionalIncludeDirectories="../../include, compat-5.1r2"
|
AdditionalIncludeDirectories="src\compat-5.1r4, ..\lua-5.0.2\include"
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
|
||||||
RuntimeLibrary="4"
|
RuntimeLibrary="2"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
@ -79,7 +79,7 @@
|
|||||||
Name="VCCustomBuildTool"/>
|
Name="VCCustomBuildTool"/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
OutputFile="$(OutDir)/cmime.dll"
|
OutputFile="$(OutDir)/mime.dll"
|
||||||
LinkIncremental="1"
|
LinkIncremental="1"
|
||||||
GenerateDebugInformation="TRUE"
|
GenerateDebugInformation="TRUE"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
@ -117,19 +117,16 @@
|
|||||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||||
<File
|
<File
|
||||||
RelativePath=".\compat-5.1r2\compat-5.1.c">
|
RelativePath="src\compat-5.1r4\compat-5.1.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\mime.c">
|
RelativePath="src\mime.c">
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Header Files"
|
Name="Header Files"
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||||
<File
|
|
||||||
RelativePath=".\mime.h">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
@ -137,10 +134,7 @@
|
|||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\lib\liblua.lib">
|
RelativePath="..\lua-5.0.2\lib\lua50.lib">
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\lib\liblualib.lib">
|
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<VisualStudioProject
|
<VisualStudioProject
|
||||||
ProjectType="Visual C++"
|
ProjectType="Visual C++"
|
||||||
Version="7.10"
|
Version="7.10"
|
||||||
Name="luasocket"
|
Name="socket"
|
||||||
ProjectGUID="{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
ProjectGUID="{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
|
||||||
Keyword="Win32Proj">
|
Keyword="Win32Proj">
|
||||||
<Platforms>
|
<Platforms>
|
||||||
@ -12,18 +12,18 @@
|
|||||||
<Configurations>
|
<Configurations>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Debug|Win32"
|
Name="Debug|Win32"
|
||||||
OutputDirectory=".\"
|
OutputDirectory="src"
|
||||||
IntermediateDirectory=".\"
|
IntermediateDirectory="src"
|
||||||
ConfigurationType="2"
|
ConfigurationType="2"
|
||||||
CharacterSet="2">
|
CharacterSet="2">
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="..\..\include, compat-5.1r2"
|
AdditionalIncludeDirectories="src\compat-5.1r4, ..\lua-5.0.2\include, src"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport)"
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport)"
|
||||||
MinimalRebuild="TRUE"
|
MinimalRebuild="TRUE"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="5"
|
RuntimeLibrary="3"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
@ -33,12 +33,12 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalDependencies="ws2_32.lib"
|
AdditionalDependencies="ws2_32.lib"
|
||||||
OutputFile="$(OutDir)/csocket.dll"
|
OutputFile="$(OutDir)/socket.dll"
|
||||||
LinkIncremental="2"
|
LinkIncremental="2"
|
||||||
GenerateDebugInformation="TRUE"
|
GenerateDebugInformation="TRUE"
|
||||||
ProgramDatabaseFile="$(OutDir)/luasocket.pdb"
|
ProgramDatabaseFile="$(OutDir)/socket.pdb"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
ImportLibrary="$(OutDir)/luasocket.lib"
|
ImportLibrary="$(OutDir)/socket.lib"
|
||||||
TargetMachine="1"/>
|
TargetMachine="1"/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCMIDLTool"/>
|
Name="VCMIDLTool"/>
|
||||||
@ -63,15 +63,15 @@
|
|||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Release|Win32"
|
Name="Release|Win32"
|
||||||
OutputDirectory="."
|
OutputDirectory="./src"
|
||||||
IntermediateDirectory="."
|
IntermediateDirectory="./src"
|
||||||
ConfigurationType="2"
|
ConfigurationType="2"
|
||||||
CharacterSet="2">
|
CharacterSet="2">
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
AdditionalIncludeDirectories="../../include, compat-5.1r2"
|
AdditionalIncludeDirectories="src\compat-5.1r4, ..\lua-5.0.2\include"
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
|
||||||
RuntimeLibrary="4"
|
RuntimeLibrary="2"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="TRUE"
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
@ -81,13 +81,13 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalDependencies="ws2_32.lib"
|
AdditionalDependencies="ws2_32.lib"
|
||||||
OutputFile="$(OutDir)/csocket.dll"
|
OutputFile="$(OutDir)/socket.dll"
|
||||||
LinkIncremental="1"
|
LinkIncremental="1"
|
||||||
GenerateDebugInformation="TRUE"
|
GenerateDebugInformation="TRUE"
|
||||||
SubSystem="2"
|
SubSystem="2"
|
||||||
OptimizeReferences="2"
|
OptimizeReferences="2"
|
||||||
EnableCOMDATFolding="2"
|
EnableCOMDATFolding="2"
|
||||||
ImportLibrary="$(OutDir)/luasocket.lib"
|
ImportLibrary="$(OutDir)/socket.lib"
|
||||||
TargetMachine="1"/>
|
TargetMachine="1"/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCMIDLTool"/>
|
Name="VCMIDLTool"/>
|
||||||
@ -119,91 +119,49 @@
|
|||||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||||
<File
|
<File
|
||||||
RelativePath=".\auxiliar.c">
|
RelativePath="src\auxiliar.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\buffer.c">
|
RelativePath="src\buffer.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\compat-5.1r2\compat-5.1.c">
|
RelativePath="src\compat-5.1r4\compat-5.1.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\except.c">
|
RelativePath="src\except.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\inet.c">
|
RelativePath="src\inet.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\io.c">
|
RelativePath="src\io.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\luasocket.c">
|
RelativePath="src\luasocket.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\options.c">
|
RelativePath="src\options.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\select.c">
|
RelativePath="src\select.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\tcp.c">
|
RelativePath="src\tcp.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\timeout.c">
|
RelativePath="src\timeout.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\udp.c">
|
RelativePath="src\udp.c">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\wsocket.c">
|
RelativePath="src\wsocket.c">
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Header Files"
|
Name="Header Files"
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||||
<File
|
|
||||||
RelativePath=".\auxiliar.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\base.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\buffer.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\inet.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\io.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\luasocket.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\options.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\select.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\smtp.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\socket.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\tcp.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\timeout.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\udp.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\wsocket.h">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
@ -211,10 +169,7 @@
|
|||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\lib\liblua.lib">
|
RelativePath="..\lua-5.0.2\lib\lua50.lib">
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\lib\liblualib.lib">
|
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
@ -127,6 +127,9 @@ void aux_setclass(lua_State *L, const char *classname, int objidx) {
|
|||||||
* otherwise
|
* otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
||||||
|
#if 0
|
||||||
|
return lua_touserdata(L, objidx);
|
||||||
|
#else
|
||||||
if (!lua_getmetatable(L, objidx))
|
if (!lua_getmetatable(L, objidx))
|
||||||
return NULL;
|
return NULL;
|
||||||
lua_pushstring(L, groupname);
|
lua_pushstring(L, groupname);
|
||||||
@ -138,6 +141,7 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
|||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
return lua_touserdata(L, objidx);
|
return lua_touserdata(L, objidx);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -145,5 +149,9 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
|||||||
* otherwise
|
* otherwise
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void *aux_getclassudata(lua_State *L, const char *classname, int objidx) {
|
void *aux_getclassudata(lua_State *L, const char *classname, int objidx) {
|
||||||
|
#if 0
|
||||||
|
return lua_touserdata(L, objidx);
|
||||||
|
#else
|
||||||
return luaL_checkudata(L, objidx, classname);
|
return luaL_checkudata(L, objidx, classname);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -325,4 +325,3 @@ request = socket.protect(function(reqt, body)
|
|||||||
if base.type(reqt) == "string" then return srequest(reqt, body)
|
if base.type(reqt) == "string" then return srequest(reqt, body)
|
||||||
else return trequest(reqt) end
|
else return trequest(reqt) end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -27,6 +27,6 @@
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes the library.
|
* Initializes the library.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
LUASOCKET_API int luaopen_socketcore(lua_State *L);
|
LUASOCKET_API int luaopen_socket_core(lua_State *L);
|
||||||
|
|
||||||
#endif /* LUASOCKET_H */
|
#endif /* LUASOCKET_H */
|
||||||
|
@ -78,7 +78,7 @@ static UC b64unbase[256];
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
MIME_API int luaopen_mimecore(lua_State *L)
|
MIME_API int luaopen_mime_core(lua_State *L)
|
||||||
{
|
{
|
||||||
luaL_openlib(L, "mime", func, 0);
|
luaL_openlib(L, "mime", func, 0);
|
||||||
/* initialize lookup tables */
|
/* initialize lookup tables */
|
||||||
|
@ -19,6 +19,6 @@
|
|||||||
#define MIME_API extern
|
#define MIME_API extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MIME_API int luaopen_mimecore(lua_State *L);
|
MIME_API int luaopen_mime_core(lua_State *L);
|
||||||
|
|
||||||
#endif /* MIME_H */
|
#endif /* MIME_H */
|
||||||
|
49
src/smtp.lua
49
src/smtp.lua
@ -137,12 +137,24 @@ end
|
|||||||
-- send_message forward declaration
|
-- send_message forward declaration
|
||||||
local send_message
|
local send_message
|
||||||
|
|
||||||
|
-- yield the headers all at once, it's faster
|
||||||
|
local function send_headers(headers)
|
||||||
|
local h = "\r\n"
|
||||||
|
for i,v in base.pairs(headers) do
|
||||||
|
h = i .. ': ' .. v .. "\r\n" .. h
|
||||||
|
end
|
||||||
|
coroutine.yield(h)
|
||||||
|
end
|
||||||
|
|
||||||
-- yield multipart message body from a multipart message table
|
-- yield multipart message body from a multipart message table
|
||||||
local function send_multipart(mesgt)
|
local function send_multipart(mesgt)
|
||||||
|
-- make sure we have our boundary and send headers
|
||||||
local bd = newboundary()
|
local bd = newboundary()
|
||||||
-- define boundary and finish headers
|
local headers = mesgt.headers or {}
|
||||||
coroutine.yield('content-type: multipart/mixed; boundary="' ..
|
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
|
||||||
bd .. '"\r\n\r\n')
|
headers['content-type'] = headers['content-type'] ..
|
||||||
|
'; boundary="' .. bd .. '"'
|
||||||
|
send_headers(headers)
|
||||||
-- send preamble
|
-- send preamble
|
||||||
if mesgt.body.preamble then
|
if mesgt.body.preamble then
|
||||||
coroutine.yield(mesgt.body.preamble)
|
coroutine.yield(mesgt.body.preamble)
|
||||||
@ -164,11 +176,11 @@ end
|
|||||||
|
|
||||||
-- yield message body from a source
|
-- yield message body from a source
|
||||||
local function send_source(mesgt)
|
local function send_source(mesgt)
|
||||||
-- set content-type if user didn't override
|
-- make sure we have a content-type
|
||||||
if not mesgt.headers or not mesgt.headers["content-type"] then
|
local headers = mesgt.headers or {}
|
||||||
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
|
headers['content-type'] = headers['content-type'] or
|
||||||
else coroutine.yield("\r\n") end
|
'text/plain; charset="iso-8859-1"'
|
||||||
-- finish headers
|
send_headers(headers)
|
||||||
-- send body from source
|
-- send body from source
|
||||||
while true do
|
while true do
|
||||||
local chunk, err = mesgt.body()
|
local chunk, err = mesgt.body()
|
||||||
@ -180,28 +192,17 @@ end
|
|||||||
|
|
||||||
-- yield message body from a string
|
-- yield message body from a string
|
||||||
local function send_string(mesgt)
|
local function send_string(mesgt)
|
||||||
-- set content-type if user didn't override
|
-- make sure we have a content-type
|
||||||
if not mesgt.headers or not mesgt.headers["content-type"] then
|
local headers = mesgt.headers or {}
|
||||||
coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
|
headers['content-type'] = headers['content-type'] or
|
||||||
else coroutine.yield("\r\n") end
|
'text/plain; charset="iso-8859-1"'
|
||||||
|
send_headers(headers)
|
||||||
-- send body from string
|
-- send body from string
|
||||||
coroutine.yield(mesgt.body)
|
coroutine.yield(mesgt.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 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
|
|
||||||
h = i .. ': ' .. v .. "\r\n" .. h
|
|
||||||
end
|
|
||||||
coroutine.yield(h)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- message source
|
-- message source
|
||||||
function send_message(mesgt)
|
function send_message(mesgt)
|
||||||
send_headers(mesgt)
|
|
||||||
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
|
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
|
||||||
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
|
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
|
||||||
else send_string(mesgt) end
|
else send_string(mesgt) end
|
||||||
|
@ -75,7 +75,7 @@ int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm 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);
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
Sleep(1000*t);
|
Sleep((DWORD) (1000*t));
|
||||||
return 0;
|
return 0;
|
||||||
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
|
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ local host, port, index_file, index, back, err, ret
|
|||||||
|
|
||||||
local t = socket.gettime()
|
local t = socket.gettime()
|
||||||
|
|
||||||
host = host or "diego.student.princeton.edu"
|
host = host or "localhost"
|
||||||
index_file = "test/index.html"
|
index_file = "index.html"
|
||||||
|
|
||||||
|
|
||||||
-- a function that returns a directory listing
|
-- a function that returns a directory listing
|
||||||
|
@ -3,6 +3,42 @@ local smtp = require("socket.smtp")
|
|||||||
local mime = require("mime")
|
local mime = require("mime")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
|
|
||||||
|
function filter(s)
|
||||||
|
if s then io.write(s) end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
source = smtp.message {
|
||||||
|
headers = { ['content-type'] = 'multipart/alternative' },
|
||||||
|
body = {
|
||||||
|
[1] = {
|
||||||
|
headers = { ['content-type'] = 'text/html' },
|
||||||
|
body = "<html> <body> Hi, <b>there</b>...</body> </html>"
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
headers = { ['content-type'] = 'text/plain' },
|
||||||
|
body = "Hi, there..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r, e = smtp.send{
|
||||||
|
rcpt = {"<diego@tecgraf.puc-rio.br>",
|
||||||
|
"<diego@princeton.edu>" },
|
||||||
|
from = "<diego@princeton.edu>",
|
||||||
|
source = ltn12.source.chain(source, filter),
|
||||||
|
--server = "mail.cs.princeton.edu"
|
||||||
|
server = "localhost",
|
||||||
|
port = 2525
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
os.exit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- creates a source to send a message with two parts. The first part is
|
-- creates a source to send a message with two parts. The first part is
|
||||||
-- plain text, the second part is a PNG image, encoded as base64.
|
-- plain text, the second part is a PNG image, encoded as base64.
|
||||||
source = smtp.message{
|
source = smtp.message{
|
||||||
@ -48,10 +84,6 @@ source = smtp.message{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(s)
|
|
||||||
if s then io.write(s) end
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
|
|
||||||
r, e = smtp.send{
|
r, e = smtp.send{
|
||||||
rcpt = {"<diego@tecgraf.puc-rio.br>",
|
rcpt = {"<diego@tecgraf.puc-rio.br>",
|
||||||
@ -64,3 +96,5 @@ r, e = smtp.send{
|
|||||||
}
|
}
|
||||||
|
|
||||||
print(r, e)
|
print(r, e)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user