diff --git a/TODO b/TODO
index b2a167e..bd60aaa 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,9 @@
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?
-
test it on Windows!!!
leave code for losers that don't have nanosleep
@@ -45,3 +43,6 @@ testar os options!
* received connections
* - this function is invoked with the client socket
* - 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.
diff --git a/config b/config
index da9fdf4..a85e8e6 100644
--- a/config
+++ b/config
@@ -8,8 +8,8 @@
EXT=so
SOCKET_V=2.0.0
MIME_V=1.0.0
-SOCKET_SO=socket-core.$(EXT).$(SOCKET_V)
-MIME_SO=mime-core.$(EXT).$(MIME_V)
+SOCKET_SO=socket.$(EXT).$(SOCKET_V)
+MIME_SO=mime.$(EXT).$(MIME_V)
UNIX_SO=unix.$(EXT)
#------
@@ -25,13 +25,15 @@ COMPAT=compat-5.1r4
#------
# 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_EXEC=cp
-INSTALL_LINK=ln
#------
# Compiler and linker settings
diff --git a/doc/index.html b/doc/index.html
index e596f8e..3d5acb3 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -168,6 +168,8 @@ support.
Improved: tcp:send(data, i, j) to return (i+sent-1). This is great for non-blocking I/O, but might break some code;
Improved: HTTP, SMTP, and FTP functions to accept a new field
create that overrides the function used to create socket objects;
+ Improved: smtp.message now supports multipart/alternative
+(for the HTML messages we all love so much);
Fixed: smtp.send was hanging on errors returned by LTN12 sources;
Fixed: url.absolute() to work when base_url is in
parsed form;
@@ -183,7 +185,7 @@ group;
Improved: Socket and MIME binaries are called 'core' each inside their
directory (ex. "socket/core.dll"). The 'l' prefix was just a bad idea;
Improved: Using bundles in Mac OS X, instead of dylibs;
- Fixed: luasocket.h to export luaopen_socketcore;
+ Fixed: luasocket.h to export luaopen_socket_core;
Fixed: udp:setpeername() so you can "disconnect" an
UDP socket;
Fixed: A weird bug in HTTP support that caused some requests to
diff --git a/etc/check-links.lua b/etc/check-links.lua
index e06cc91..725cd2a 100644
--- a/etc/check-links.lua
+++ b/etc/check-links.lua
@@ -5,33 +5,26 @@
-- Author: Diego Nehab
-- 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 {}
if table.getn(arg) < 1 then
print("Usage:\n luasocket check-links.lua [-n] {}")
exit()
end
-if arg[1] ~= "-n" then
- -- if using blocking I/O, simulate dispatcher interface
- url = require("socket.url")
- 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
+-- '-n' means we are running in non-blocking mode
+if arg[1] == "-n" then
+ -- if non-blocking I/O was requested, use real dispatcher interface
table.remove(arg, 1)
- dispatch = require("dispatch")
- dispatch.TIMEOUT = 10
- url = require("socket.url")
- http = require("socket.http")
- handler = dispatch.newhandler()
+ handler = dispatch.newhandler("coroutine")
+else
+ -- if using blocking I/O, use fake dispatcher interface
+ handler = dispatch.newhandler("sequential")
end
local nthreads = 0
diff --git a/etc/dispatch.lua b/etc/dispatch.lua
index e6c14a6..98fa8a8 100644
--- a/etc/dispatch.lua
+++ b/etc/dispatch.lua
@@ -11,23 +11,33 @@ module("dispatch")
-- if too much time goes by without any activity in one of our sockets, we
-- 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
--- hack to emulate it in Lua itself
--- This is very inefficient, but is very good for debugging.
-local running
-local resume = coroutine.resume
-function coroutine.resume(co, ...)
- running = co
- return resume(co, unpack(arg))
+local handlert = {}
+
+-- default handler is coroutine
+function newhandler(mode)
+ mode = mode or "coroutine"
+ return handlert[mode]()
end
-function coroutine.running()
- return running
+local function seqstart(self, func)
+ 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
-----------------------------------------------------------------------------
@@ -36,15 +46,11 @@ end
-- 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
-- loading our hack
-function socket.protect(f)
- return f
-end
-
function socket.protect(f)
return function(...)
local co = coroutine.create(f)
while true do
- local results = {resume(co, unpack(arg))}
+ local results = {coroutine.resume(co, unpack(arg))}
local status = table.remove(results, 1)
if not status then
if type(results[1]) == 'table' then
@@ -61,133 +67,7 @@ function socket.protect(f)
end
-----------------------------------------------------------------------------
--- socket.tcp() replacement for non-blocking I/O
------------------------------------------------------------------------------
-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
+-- Simple set data structure. O(1) everything.
-----------------------------------------------------------------------------
local function newset()
local reverse = {}
@@ -214,54 +94,208 @@ local function newset()
end
-----------------------------------------------------------------------------
--- Our dispatcher API.
+-- socket.tcp() wrapper for the coroutine dispatcher
-----------------------------------------------------------------------------
-local metat = { __index = {} }
-
-function metat.__index:start(func)
- local co = coroutine.create(func)
- assert(coroutine.resume(co))
-end
-
-function newhandler()
- local dispatcher = {
- context = {},
- 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))
+local function cowrap(dispatcher, tcp, error)
+ if not tcp then return nil, error end
+ -- put it in non-blocking mode right away
+ tcp:settimeout(0)
+ -- metatable for wrap produces new methods on demand for those that we
+ -- don't override explicitly.
+ local metat = { __index = function(table, key)
+ table[key] = function(...)
+ arg[1] = tcp
+ return tcp[key](unpack(arg))
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
-- for all writable connections, do the same
- for _, who in ipairs(writable) do
- if self.context[who] then
- self.sending:remove(who)
- assert(coroutine.resume(self.context[who].thread))
- end
+ for _, tcp in ipairs(writable) do
+ schedule(wakeup(self.sending, tcp))
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
local now = socket.gettime()
- for who, data in pairs(self.context) do
- if data.last and now - data.last > TIMEOUT then
- self.sending:remove(who)
- self.receiving:remove(who)
- assert(coroutine.resume(self.context[who].thread, "timeout"))
+ for tcp, stamp in pairs(self.stamp) do
+ if tcp.class == "tcp{client}" and now - stamp > TIMEOUT then
+ abort(self.sending, tcp)
+ abort(self.receiving, tcp)
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
+
diff --git a/etc/forward.lua b/etc/forward.lua
new file mode 100644
index 0000000..eac98ae
--- /dev/null
+++ b/etc/forward.lua
@@ -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 ...")
+ 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
diff --git a/luasocket.sln b/luasocket.sln
index 6a1d0b8..006b7f0 100644
--- a/luasocket.sln
+++ b/luasocket.sln
@@ -1,5 +1,5 @@
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
EndProjectSection
EndProject
diff --git a/makefile b/makefile
index 234e162..c84ef10 100644
--- a/makefile
+++ b/makefile
@@ -6,8 +6,10 @@ include config
#------
# Hopefully no need to change anything below this line
#
-INSTALL_SOCKET=$(INSTALL_TOP)/socket
-INSTALL_MIME=$(INSTALL_TOP)/mime
+INSTALL_SOCKET_LUA=$(INSTALL_TOP_LUA)/socket
+INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
+INSTALL_MIME_LUA=$(INSTALL_TOP_LUA)/mime
+INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
all clean:
cd src; $(MAKE) $@
@@ -15,7 +17,7 @@ all clean:
#------
# Files to install
#
-TO_SOCKET:= \
+TO_SOCKET_LUA:= \
socket.lua \
http.lua \
url.lua \
@@ -23,29 +25,28 @@ TO_SOCKET:= \
ftp.lua \
smtp.lua
-TO_TOP:= \
+TO_TOP_LUA:= \
ltn12.lua
-TO_MIME:= \
- $(MIME_SO) \
+TO_MIME_LUA:= \
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
+ cd src; mkdir -p $(INSTALL_TOP_LUA)
+ cd src; mkdir -p $(INSTALL_TOP_LIB)
+ cd src; $(INSTALL_DATA) $(COMPAT)/compat-5.1.lua $(INSTALL_TOP_LUA)
+ cd src; $(INSTALL_DATA) ltn12.lua $(INSTALL_TOP_LUA)
+ cd src; mkdir -p $(INSTALL_SOCKET_LUA)
+ cd src; mkdir -p $(INSTALL_SOCKET_LIB)
+ cd src; $(INSTALL_DATA) $(TO_SOCKET_LUA) $(INSTALL_SOCKET_LUA)
+ cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT)
+ cd src; mkdir -p $(INSTALL_MIME_LUA)
+ cd src; mkdir -p $(INSTALL_MIME_LIB)
+ cd src; $(INSTALL_DATA) $(TO_MIME_LUA) $(INSTALL_MIME_LUA)
+ cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
#------
# End of makefile
diff --git a/makefile.dist b/makefile.dist
index 4ccddbc..8b79653 100644
--- a/makefile.dist
+++ b/makefile.dist
@@ -2,9 +2,9 @@
# Distribution makefile
#--------------------------------------------------------------------------
-DIST = luasocket-2.0-beta3
+DIST = luasocket-2.0
-COMPAT = compat-5.1r2
+COMPAT = compat-5.1r4
LUA = \
ftp.lua \
@@ -37,6 +37,7 @@ EXAMPLES = \
ETC = \
check-links.lua \
+ check-links-nb.lua \
dict.lua \
get.lua \
unix.c \
@@ -76,8 +77,8 @@ CORE = \
wsocket.h
MAKE = \
- makefile.Darwin \
- makefile.Linux \
+ makefile \
+ config \
luasocket.sln \
luasocket.vcproj \
mime.vcproj
diff --git a/mime.vcproj b/mime.vcproj
index 43d289a..c4e328f 100644
--- a/mime.vcproj
+++ b/mime.vcproj
@@ -12,18 +12,18 @@
+ RelativePath="src\compat-5.1r4\compat-5.1.c">
+ RelativePath="src\mime.c">
-
-
-
-
+ RelativePath="..\lua-5.0.2\lib\lua50.lib">
diff --git a/luasocket.vcproj b/socket.vcproj
similarity index 63%
rename from luasocket.vcproj
rename to socket.vcproj
index 71486d6..ddfb46e 100644
--- a/luasocket.vcproj
+++ b/socket.vcproj
@@ -2,7 +2,7 @@
@@ -12,18 +12,18 @@
@@ -63,15 +63,15 @@
@@ -119,91 +119,49 @@
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ RelativePath="src\auxiliar.c">
+ RelativePath="src\buffer.c">
+ RelativePath="src\compat-5.1r4\compat-5.1.c">
+ RelativePath="src\except.c">
+ RelativePath="src\inet.c">
+ RelativePath="src\io.c">
+ RelativePath="src\luasocket.c">
+ RelativePath="src\options.c">
+ RelativePath="src\select.c">
+ RelativePath="src\tcp.c">
+ RelativePath="src\timeout.c">
+ RelativePath="src\udp.c">
+ RelativePath="src\wsocket.c">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ RelativePath="..\lua-5.0.2\lib\lua50.lib">
diff --git a/src/auxiliar.c b/src/auxiliar.c
index 2ebcdd6..b228785 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -127,6 +127,9 @@ void aux_setclass(lua_State *L, const char *classname, int objidx) {
* otherwise
\*-------------------------------------------------------------------------*/
void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
+#if 0
+ return lua_touserdata(L, objidx);
+#else
if (!lua_getmetatable(L, objidx))
return NULL;
lua_pushstring(L, groupname);
@@ -138,6 +141,7 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
lua_pop(L, 2);
return lua_touserdata(L, objidx);
}
+#endif
}
/*-------------------------------------------------------------------------*\
@@ -145,5 +149,9 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
* otherwise
\*-------------------------------------------------------------------------*/
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);
+#endif
}
diff --git a/src/http.lua b/src/http.lua
index 9434d97..fe779a3 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -325,4 +325,3 @@ request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end
end)
-
diff --git a/src/luasocket.h b/src/luasocket.h
index 34a7693..c7d09d8 100644
--- a/src/luasocket.h
+++ b/src/luasocket.h
@@ -27,6 +27,6 @@
/*-------------------------------------------------------------------------*\
* Initializes the library.
\*-------------------------------------------------------------------------*/
-LUASOCKET_API int luaopen_socketcore(lua_State *L);
+LUASOCKET_API int luaopen_socket_core(lua_State *L);
#endif /* LUASOCKET_H */
diff --git a/src/mime.c b/src/mime.c
index 70e0db9..4539e2c 100644
--- a/src/mime.c
+++ b/src/mime.c
@@ -78,7 +78,7 @@ static UC b64unbase[256];
/*-------------------------------------------------------------------------*\
* 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);
/* initialize lookup tables */
diff --git a/src/mime.h b/src/mime.h
index 34031a1..eda0898 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -19,6 +19,6 @@
#define MIME_API extern
#endif
-MIME_API int luaopen_mimecore(lua_State *L);
+MIME_API int luaopen_mime_core(lua_State *L);
#endif /* MIME_H */
diff --git a/src/smtp.lua b/src/smtp.lua
index 46df1ab..5c485c2 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -137,12 +137,24 @@ end
-- send_message forward declaration
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
local function send_multipart(mesgt)
+ -- make sure we have our boundary and send headers
local bd = newboundary()
- -- define boundary and finish headers
- coroutine.yield('content-type: multipart/mixed; boundary="' ..
- bd .. '"\r\n\r\n')
+ local headers = mesgt.headers or {}
+ headers['content-type'] = headers['content-type'] or 'multipart/mixed'
+ headers['content-type'] = headers['content-type'] ..
+ '; boundary="' .. bd .. '"'
+ send_headers(headers)
-- send preamble
if mesgt.body.preamble then
coroutine.yield(mesgt.body.preamble)
@@ -164,11 +176,11 @@ end
-- yield message body from a source
local function send_source(mesgt)
- -- set content-type if user didn't override
- if not mesgt.headers or not mesgt.headers["content-type"] then
- coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
- else coroutine.yield("\r\n") end
- -- finish headers
+ -- make sure we have a content-type
+ local headers = mesgt.headers or {}
+ headers['content-type'] = headers['content-type'] or
+ 'text/plain; charset="iso-8859-1"'
+ send_headers(headers)
-- send body from source
while true do
local chunk, err = mesgt.body()
@@ -180,28 +192,17 @@ end
-- yield message body from a string
local function send_string(mesgt)
- -- set content-type if user didn't override
- if not mesgt.headers or not mesgt.headers["content-type"] then
- coroutine.yield('content-type: text/plain; charset="iso-8859-1"\r\n\r\n')
- else coroutine.yield("\r\n") end
+ -- make sure we have a content-type
+ local headers = mesgt.headers or {}
+ headers['content-type'] = headers['content-type'] or
+ 'text/plain; charset="iso-8859-1"'
+ send_headers(headers)
-- send body from string
coroutine.yield(mesgt.body)
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
function send_message(mesgt)
- send_headers(mesgt)
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
else send_string(mesgt) end
diff --git a/src/wsocket.c b/src/wsocket.c
index c4c51b4..0f6005f 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -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_usec = (int) ((t - tv.tv_sec) * 1.0e6);
if (n <= 0) {
- Sleep(1000*t);
+ Sleep((DWORD) (1000*t));
return 0;
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
diff --git a/test/ftptest.lua b/test/ftptest.lua
index ef1bf0f..63d20e6 100644
--- a/test/ftptest.lua
+++ b/test/ftptest.lua
@@ -12,8 +12,8 @@ local host, port, index_file, index, back, err, ret
local t = socket.gettime()
-host = host or "diego.student.princeton.edu"
-index_file = "test/index.html"
+host = host or "localhost"
+index_file = "index.html"
-- a function that returns a directory listing
diff --git a/test/testmesg.lua b/test/testmesg.lua
index 37e8c11..1dd9a97 100644
--- a/test/testmesg.lua
+++ b/test/testmesg.lua
@@ -3,6 +3,42 @@ local smtp = require("socket.smtp")
local mime = require("mime")
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 = " Hi, there... "
+ },
+ [2] = {
+ headers = { ['content-type'] = 'text/plain' },
+ body = "Hi, there..."
+ }
+ }
+}
+
+r, e = smtp.send{
+ rcpt = {"",
+ "" },
+ from = "",
+ 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
-- plain text, the second part is a PNG image, encoded as base64.
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{
rcpt = {"",
@@ -64,3 +96,5 @@ r, e = smtp.send{
}
print(r, e)
+
+