aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-06-15 06:24:00 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-06-15 06:24:00 +0000
commit58096449c6044b7aade5cd41cfd71c6bec1d273d (patch)
tree1814ffebe89c4c2556d84f97f66db37a7e8b4554 /src
parent9ed7f955e5fc69af9bf1794fa2c8cd227981ba24 (diff)
downloadluasocket-58096449c6044b7aade5cd41cfd71c6bec1d273d.tar.gz
luasocket-58096449c6044b7aade5cd41cfd71c6bec1d273d.tar.bz2
luasocket-58096449c6044b7aade5cd41cfd71c6bec1d273d.zip
Manual is almost done. HTTP is missing.
Implemented new distribution scheme. Select is now purely C. HTTP reimplemented seems faster dunno why. LTN12 functions that coroutines fail gracefully.
Diffstat (limited to 'src')
-rw-r--r--src/auxiliar.c50
-rw-r--r--src/auxiliar.h25
-rw-r--r--src/buffer.c9
-rw-r--r--src/except.c52
-rw-r--r--src/except.h35
-rw-r--r--src/ftp.lua73
-rw-r--r--src/http.lua351
-rw-r--r--src/inet.c1
-rw-r--r--src/ltn12.lua21
-rw-r--r--src/luasocket.c71
-rw-r--r--src/luasocket.h1
-rw-r--r--src/mime.c12
-rw-r--r--src/mime.h1
-rw-r--r--src/mime.lua14
-rw-r--r--src/select.c221
-rw-r--r--src/smtp.lua50
-rw-r--r--src/socket.lua13
-rw-r--r--src/tcp.c5
-rw-r--r--src/timeout.c8
-rw-r--r--src/tp.lua26
-rw-r--r--src/udp.c5
-rw-r--r--src/url.lua4
22 files changed, 621 insertions, 427 deletions
diff --git a/src/auxiliar.c b/src/auxiliar.c
index b1f9203..9a37e10 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -7,7 +7,6 @@
7#include <string.h> 7#include <string.h>
8#include <stdio.h> 8#include <stdio.h>
9 9
10#include "luasocket.h"
11#include "auxiliar.h" 10#include "auxiliar.h"
12 11
13/*=========================================================================*\ 12/*=========================================================================*\
@@ -16,16 +15,15 @@
16/*-------------------------------------------------------------------------*\ 15/*-------------------------------------------------------------------------*\
17* Initializes the module 16* Initializes the module
18\*-------------------------------------------------------------------------*/ 17\*-------------------------------------------------------------------------*/
19int aux_open(lua_State *L) 18int aux_open(lua_State *L) {
20{
21 return 0; 19 return 0;
22} 20}
23 21
24/*-------------------------------------------------------------------------*\ 22/*-------------------------------------------------------------------------*\
25* Creates a new class with given methods 23* Creates a new class with given methods
24* Methods whose names start with __ are passed directly to the metatable.
26\*-------------------------------------------------------------------------*/ 25\*-------------------------------------------------------------------------*/
27void aux_newclass(lua_State *L, const char *classname, luaL_reg *func) 26void aux_newclass(lua_State *L, const char *classname, luaL_reg *func) {
28{
29 luaL_newmetatable(L, classname); /* mt */ 27 luaL_newmetatable(L, classname); /* mt */
30 /* create __index table to place methods */ 28 /* create __index table to place methods */
31 lua_pushstring(L, "__index"); /* mt,"__index" */ 29 lua_pushstring(L, "__index"); /* mt,"__index" */
@@ -46,10 +44,30 @@ void aux_newclass(lua_State *L, const char *classname, luaL_reg *func)
46} 44}
47 45
48/*-------------------------------------------------------------------------*\ 46/*-------------------------------------------------------------------------*\
47* Prints the value of a class in a nice way
48\*-------------------------------------------------------------------------*/
49int aux_tostring(lua_State *L) {
50 char buf[32];
51 if (!lua_getmetatable(L, 1)) goto error;
52 lua_pushstring(L, "__index");
53 lua_gettable(L, -2);
54 if (!lua_istable(L, -1)) goto error;
55 lua_pushstring(L, "class");
56 lua_gettable(L, -2);
57 if (!lua_isstring(L, -1)) goto error;
58 sprintf(buf, "%p", lua_touserdata(L, 1));
59 lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
60 return 1;
61error:
62 lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
63 lua_error(L);
64 return 1;
65}
66
67/*-------------------------------------------------------------------------*\
49* Insert class into group 68* Insert class into group
50\*-------------------------------------------------------------------------*/ 69\*-------------------------------------------------------------------------*/
51void aux_add2group(lua_State *L, const char *classname, const char *groupname) 70void aux_add2group(lua_State *L, const char *classname, const char *groupname) {
52{
53 luaL_getmetatable(L, classname); 71 luaL_getmetatable(L, classname);
54 lua_pushstring(L, groupname); 72 lua_pushstring(L, groupname);
55 lua_pushboolean(L, 1); 73 lua_pushboolean(L, 1);
@@ -60,8 +78,7 @@ void aux_add2group(lua_State *L, const char *classname, const char *groupname)
60/*-------------------------------------------------------------------------*\ 78/*-------------------------------------------------------------------------*\
61* Make sure argument is a boolean 79* Make sure argument is a boolean
62\*-------------------------------------------------------------------------*/ 80\*-------------------------------------------------------------------------*/
63int aux_checkboolean(lua_State *L, int objidx) 81int aux_checkboolean(lua_State *L, int objidx) {
64{
65 if (!lua_isboolean(L, objidx)) 82 if (!lua_isboolean(L, objidx))
66 luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); 83 luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
67 return lua_toboolean(L, objidx); 84 return lua_toboolean(L, objidx);
@@ -71,8 +88,7 @@ int aux_checkboolean(lua_State *L, int objidx)
71* Return userdata pointer if object belongs to a given class, abort with 88* Return userdata pointer if object belongs to a given class, abort with
72* error otherwise 89* error otherwise
73\*-------------------------------------------------------------------------*/ 90\*-------------------------------------------------------------------------*/
74void *aux_checkclass(lua_State *L, const char *classname, int objidx) 91void *aux_checkclass(lua_State *L, const char *classname, int objidx) {
75{
76 void *data = aux_getclassudata(L, classname, objidx); 92 void *data = aux_getclassudata(L, classname, objidx);
77 if (!data) { 93 if (!data) {
78 char msg[45]; 94 char msg[45];
@@ -86,8 +102,7 @@ void *aux_checkclass(lua_State *L, const char *classname, int objidx)
86* Return userdata pointer if object belongs to a given group, abort with 102* Return userdata pointer if object belongs to a given group, abort with
87* error otherwise 103* error otherwise
88\*-------------------------------------------------------------------------*/ 104\*-------------------------------------------------------------------------*/
89void *aux_checkgroup(lua_State *L, const char *groupname, int objidx) 105void *aux_checkgroup(lua_State *L, const char *groupname, int objidx) {
90{
91 void *data = aux_getgroupudata(L, groupname, objidx); 106 void *data = aux_getgroupudata(L, groupname, objidx);
92 if (!data) { 107 if (!data) {
93 char msg[45]; 108 char msg[45];
@@ -100,8 +115,7 @@ void *aux_checkgroup(lua_State *L, const char *groupname, int objidx)
100/*-------------------------------------------------------------------------*\ 115/*-------------------------------------------------------------------------*\
101* Set object class 116* Set object class
102\*-------------------------------------------------------------------------*/ 117\*-------------------------------------------------------------------------*/
103void aux_setclass(lua_State *L, const char *classname, int objidx) 118void aux_setclass(lua_State *L, const char *classname, int objidx) {
104{
105 luaL_getmetatable(L, classname); 119 luaL_getmetatable(L, classname);
106 if (objidx < 0) objidx--; 120 if (objidx < 0) objidx--;
107 lua_setmetatable(L, objidx); 121 lua_setmetatable(L, objidx);
@@ -111,8 +125,7 @@ void aux_setclass(lua_State *L, const char *classname, int objidx)
111* Get a userdata pointer if object belongs to a given group. Return NULL 125* Get a userdata pointer if object belongs to a given group. Return NULL
112* otherwise 126* otherwise
113\*-------------------------------------------------------------------------*/ 127\*-------------------------------------------------------------------------*/
114void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) 128void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
115{
116 if (!lua_getmetatable(L, objidx)) 129 if (!lua_getmetatable(L, objidx))
117 return NULL; 130 return NULL;
118 lua_pushstring(L, groupname); 131 lua_pushstring(L, groupname);
@@ -130,7 +143,6 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx)
130* Get a userdata pointer if object belongs to a given class. Return NULL 143* Get a userdata pointer if object belongs to a given class. Return NULL
131* otherwise 144* otherwise
132\*-------------------------------------------------------------------------*/ 145\*-------------------------------------------------------------------------*/
133void *aux_getclassudata(lua_State *L, const char *classname, int objidx) 146void *aux_getclassudata(lua_State *L, const char *classname, int objidx) {
134{
135 return luaL_checkudata(L, objidx, classname); 147 return luaL_checkudata(L, objidx, classname);
136} 148}
diff --git a/src/auxiliar.h b/src/auxiliar.h
index bc45182..70f4704 100644
--- a/src/auxiliar.h
+++ b/src/auxiliar.h
@@ -2,26 +2,28 @@
2#define AUX_H 2#define AUX_H
3/*=========================================================================*\ 3/*=========================================================================*\
4* Auxiliar routines for class hierarchy manipulation 4* Auxiliar routines for class hierarchy manipulation
5* LuaSocket toolkit 5* LuaSocket toolkit (but completely independent of other LuaSocket modules)
6* 6*
7* A LuaSocket class is a name associated with Lua metatables. A LuaSocket 7* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
8* group is a name associated to a class. A class can belong to any number 8* group is a name associated with a class. A class can belong to any number
9* of groups. This module provides the functionality to: 9* of groups. This module provides the functionality to:
10* 10*
11* - create new classes 11* - create new classes
12* - add classes to groups 12* - add classes to groups
13* - set the class of object 13* - set the class of objects
14* - check if an object belongs to a given class or group 14* - check if an object belongs to a given class or group
15* - get the userdata associated to objects
16* - print objects in a pretty way
15* 17*
16* LuaSocket class names follow the convention <module>{<class>}. Modules 18* LuaSocket class names follow the convention <module>{<class>}. Modules
17* can define any number of classes and groups. The module tcp.c, for 19* can define any number of classes and groups. The module tcp.c, for
18* example, defines the classes tcp{master}, tcp{client} and tcp{server} and 20* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
19* the groups tcp{client, server} and tcp{any}. Module functions can then 21* the groups tcp{client,server} and tcp{any}. Module functions can then
20* perform type-checking on it's arguments by either class or group. 22* perform type-checking on their arguments by either class or group.
21* 23*
22* LuaSocket metatables define the __index metamethod as being a table. This 24* LuaSocket metatables define the __index metamethod as being a table. This
23* table has one field for each method supported by the class. In DEBUG 25* table has one field for each method supported by the class, and a field
24* mode, it also has one field with the class name. 26* "class" with the class name.
25* 27*
26* The mapping from class name to the corresponding metatable and the 28* The mapping from class name to the corresponding metatable and the
27* reverse mapping are done using lauxlib. 29* reverse mapping are done using lauxlib.
@@ -32,14 +34,6 @@
32#include <lua.h> 34#include <lua.h>
33#include <lauxlib.h> 35#include <lauxlib.h>
34 36
35/* min and max macros */
36#ifndef MIN
37#define MIN(x, y) ((x) < (y) ? x : y)
38#endif
39#ifndef MAX
40#define MAX(x, y) ((x) > (y) ? x : y)
41#endif
42
43int aux_open(lua_State *L); 37int aux_open(lua_State *L);
44void aux_newclass(lua_State *L, const char *classname, luaL_reg *func); 38void aux_newclass(lua_State *L, const char *classname, luaL_reg *func);
45void aux_add2group(lua_State *L, const char *classname, const char *group); 39void aux_add2group(lua_State *L, const char *classname, const char *group);
@@ -49,5 +43,6 @@ void *aux_checkgroup(lua_State *L, const char *groupname, int objidx);
49void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); 43void *aux_getclassudata(lua_State *L, const char *groupname, int objidx);
50void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); 44void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx);
51int aux_checkboolean(lua_State *L, int objidx); 45int aux_checkboolean(lua_State *L, int objidx);
46int aux_tostring(lua_State *L);
52 47
53#endif /* AUX_H */ 48#endif /* AUX_H */
diff --git a/src/buffer.c b/src/buffer.c
index b771047..fd885a2 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -7,7 +7,6 @@
7#include <lua.h> 7#include <lua.h>
8#include <lauxlib.h> 8#include <lauxlib.h>
9 9
10#include "auxiliar.h"
11#include "buffer.h" 10#include "buffer.h"
12 11
13/*=========================================================================*\ 12/*=========================================================================*\
@@ -20,6 +19,14 @@ static int buf_get(p_buf buf, const char **data, size_t *count);
20static void buf_skip(p_buf buf, size_t count); 19static void buf_skip(p_buf buf, size_t count);
21static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent); 20static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
22 21
22/* min and max macros */
23#ifndef MIN
24#define MIN(x, y) ((x) < (y) ? x : y)
25#endif
26#ifndef MAX
27#define MAX(x, y) ((x) > (y) ? x : y)
28#endif
29
23/*=========================================================================*\ 30/*=========================================================================*\
24* Exported functions 31* Exported functions
25\*=========================================================================*/ 32\*=========================================================================*/
diff --git a/src/except.c b/src/except.c
new file mode 100644
index 0000000..c9eb20e
--- /dev/null
+++ b/src/except.c
@@ -0,0 +1,52 @@
1#include <lauxlib.h>
2#include <stdio.h>
3
4#include "except.h"
5
6static int global_try(lua_State *L);
7static int global_protect(lua_State *L);
8static int protected(lua_State *L);
9
10static luaL_reg func[] = {
11 {"try", global_try},
12 {"protect", global_protect},
13 {NULL, NULL}
14};
15
16/*-------------------------------------------------------------------------*\
17* Exception handling: try method
18\*-------------------------------------------------------------------------*/
19static int global_try(lua_State *L) {
20 if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) {
21 lua_settop(L, 2);
22 lua_error(L);
23 return 0;
24 } else return lua_gettop(L);
25}
26
27/*-------------------------------------------------------------------------*\
28* Exception handling: protect factory
29\*-------------------------------------------------------------------------*/
30static int protected(lua_State *L) {
31 lua_pushvalue(L, lua_upvalueindex(1));
32 lua_insert(L, 1);
33 if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
34 lua_pushnil(L);
35 lua_insert(L, 1);
36 return 2;
37 } else return lua_gettop(L);
38}
39
40static int global_protect(lua_State *L) {
41 lua_insert(L, 1);
42 lua_pushcclosure(L, protected, 1);
43 return 1;
44}
45
46/*-------------------------------------------------------------------------*\
47* Init module
48\*-------------------------------------------------------------------------*/
49int except_open(lua_State *L) {
50 luaL_openlib(L, NULL, func, 0);
51 return 0;
52}
diff --git a/src/except.h b/src/except.h
new file mode 100644
index 0000000..2c57b27
--- /dev/null
+++ b/src/except.h
@@ -0,0 +1,35 @@
1#ifndef EXCEPT_H
2#define EXCEPT_H
3/*=========================================================================*\
4* Exception control
5* LuaSocket toolkit (but completely independent from other modules)
6*
7* This provides support for simple exceptions in Lua. During the
8* development of the HTTP/FTP/SMTP support, it became aparent that
9* error checking was taking a substantial amount of the coding. These
10* function greatly simplify the task of checking errors.
11*
12* The main idea is that functions should return nil as its first return
13* value when it finds an error, and return an error message (or value)
14* following nil. In case of success, as long as the first value is not nil,
15* the other values don't matter.
16*
17* The idea is to nest function calls with the "try" function. This function
18* checks the first value, and calls "error" on the second if the first is
19* nil. Otherwise, it returns all values it received.
20*
21* The protect function returns a new function that behaves exactly like the
22* function it receives, but the new function doesn't throw exceptions: it
23* returns nil followed by the error message instead.
24*
25* With these two function, it's easy to write functions that throw
26* exceptions on error, but that don't interrupt the user script.
27*
28* RCS ID: $Id$
29\*=========================================================================*/
30
31#include <lua.h>
32
33int except_open(lua_State *L);
34
35#endif
diff --git a/src/ftp.lua b/src/ftp.lua
index 79772f8..c130d1a 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -7,7 +7,7 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load other required modules 10-- Load required modules
11----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local socket = require("socket") 12local socket = require("socket")
13local ltn12 = require("ltn12") 13local ltn12 = require("ltn12")
@@ -17,10 +17,7 @@ local tp = require("tp")
17----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
18-- Setup namespace 18-- Setup namespace
19----------------------------------------------------------------------------- 19-----------------------------------------------------------------------------
20local ftp = {} 20_LOADED["ftp"] = getfenv(1)
21-- make all module globals fall into namespace
22setmetatable(ftp, { __index = _G })
23setfenv(1, ftp)
24 21
25----------------------------------------------------------------------------- 22-----------------------------------------------------------------------------
26-- Program constants 23-- Program constants
@@ -32,9 +29,7 @@ PORT = 21
32-- this is the default anonymous password. used when no password is 29-- this is the default anonymous password. used when no password is
33-- provided in url. should be changed to your e-mail. 30-- provided in url. should be changed to your e-mail.
34USER = "ftp" 31USER = "ftp"
35EMAIL = "anonymous@anonymous.org" 32PASSWORD = "anonymous@anonymous.org"
36-- block size used in transfers
37BLOCKSIZE = 2048
38 33
39----------------------------------------------------------------------------- 34-----------------------------------------------------------------------------
40-- Low level FTP API 35-- Low level FTP API
@@ -42,7 +37,7 @@ BLOCKSIZE = 2048
42local metat = { __index = {} } 37local metat = { __index = {} }
43 38
44function open(server, port) 39function open(server, port)
45 local tp = socket.try(socket.tp.connect(server, port or PORT)) 40 local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT))
46 return setmetatable({tp = tp}, metat) 41 return setmetatable({tp = tp}, metat)
47end 42end
48 43
@@ -51,14 +46,17 @@ local function port(portt)
51end 46end
52 47
53local function pasv(pasvt) 48local function pasv(pasvt)
54 return socket.connect(pasvt.ip, pasvt.port) 49 local data = socket.try(socket.tcp())
50 socket.try(data:settimeout(TIMEOUT))
51 socket.try(data:connect(pasvt.ip, pasvt.port))
52 return data
55end 53end
56 54
57function metat.__index:login(user, password) 55function metat.__index:login(user, password)
58 socket.try(self.tp:command("user", user or USER)) 56 socket.try(self.tp:command("user", user or USER))
59 local code, reply = socket.try(self.tp:check{"2..", 331}) 57 local code, reply = socket.try(self.tp:check{"2..", 331})
60 if code == 331 then 58 if code == 331 then
61 socket.try(self.tp:command("pass", password or EMAIL)) 59 socket.try(self.tp:command("pass", password or PASSWORD))
62 socket.try(self.tp:check("2..")) 60 socket.try(self.tp:check("2.."))
63 end 61 end
64 return 1 62 return 1
@@ -104,6 +102,7 @@ function metat.__index:send(sendt)
104 socket.try(self.pasvt or self.portt, "need port or pasv first") 102 socket.try(self.pasvt or self.portt, "need port or pasv first")
105 if self.pasvt then data = socket.try(pasv(self.pasvt)) end 103 if self.pasvt then data = socket.try(pasv(self.pasvt)) end
106 local argument = sendt.argument or string.gsub(sendt.path, "^/", "") 104 local argument = sendt.argument or string.gsub(sendt.path, "^/", "")
105 if argument == "" then argument = nil end
107 local command = sendt.command or "stor" 106 local command = sendt.command or "stor"
108 socket.try(self.tp:command(command, argument)) 107 socket.try(self.tp:command(command, argument))
109 local code, reply = socket.try(self.tp:check{"2..", "1.."}) 108 local code, reply = socket.try(self.tp:check{"2..", "1.."})
@@ -133,6 +132,7 @@ function metat.__index:receive(recvt)
133 socket.try(self.pasvt or self.portt, "need port or pasv first") 132 socket.try(self.pasvt or self.portt, "need port or pasv first")
134 if self.pasvt then data = socket.try(pasv(self.pasvt)) end 133 if self.pasvt then data = socket.try(pasv(self.pasvt)) end
135 local argument = recvt.argument or string.gsub(recvt.path, "^/", "") 134 local argument = recvt.argument or string.gsub(recvt.path, "^/", "")
135 if argument == "" then argument = nil end
136 local command = recvt.command or "retr" 136 local command = recvt.command or "retr"
137 socket.try(self.tp:command(command, argument)) 137 socket.try(self.tp:command(command, argument))
138 local code = socket.try(self.tp:check{"1..", "2.."}) 138 local code = socket.try(self.tp:check{"1..", "2.."})
@@ -182,14 +182,14 @@ end
182-- High level FTP API 182-- High level FTP API
183----------------------------------------------------------------------------- 183-----------------------------------------------------------------------------
184local function tput(putt) 184local function tput(putt)
185 local ftp = socket.ftp.open(putt.host, putt.port) 185 local con = ftp.open(putt.host, putt.port)
186 ftp:greet() 186 con:greet()
187 ftp:login(putt.user, putt.password) 187 con:login(putt.user, putt.password)
188 if putt.type then ftp:type(putt.type) end 188 if putt.type then con:type(putt.type) end
189 ftp:pasv() 189 con:pasv()
190 ftp:send(putt) 190 con:send(putt)
191 ftp:quit() 191 con:quit()
192 return ftp:close() 192 return con:close()
193end 193end
194 194
195local default = { 195local default = {
@@ -198,15 +198,16 @@ local default = {
198} 198}
199 199
200local function parse(u) 200local function parse(u)
201 local putt = socket.try(url.parse(u, default)) 201 local t = socket.try(url.parse(u, default))
202 socket.try(putt.scheme == "ftp", "invalid scheme '" .. putt.scheme .. "'") 202 socket.try(t.scheme == "ftp", "invalid scheme '" .. t.scheme .. "'")
203 socket.try(putt.host, "invalid host") 203 socket.try(t.host, "invalid host")
204 local pat = "^type=(.)$" 204 local pat = "^type=(.)$"
205 if putt.params then 205 if t.params then
206 putt.type = socket.skip(2, string.find(putt.params, pat)) 206 t.type = socket.skip(2, string.find(t.params, pat))
207 socket.try(putt.type == "a" or putt.type == "i") 207 socket.try(t.type == "a" or t.type == "i",
208 "invalid type '" .. t.type .. "'")
208 end 209 end
209 return putt 210 return t
210end 211end
211 212
212local function sput(u, body) 213local function sput(u, body)
@@ -221,17 +222,17 @@ put = socket.protect(function(putt, body)
221end) 222end)
222 223
223local function tget(gett) 224local function tget(gett)
224 local ftp = socket.ftp.open(gett.host, gett.port) 225 local con = ftp.open(gett.host, gett.port)
225 ftp:greet() 226 con:greet()
226 ftp:login(gett.user, gett.password) 227 con:login(gett.user, gett.password)
227 if gett.type then ftp:type(gett.type) end 228 if gett.type then con:type(gett.type) end
228 ftp:pasv() 229 con:pasv()
229 ftp:receive(gett) 230 con:receive(gett)
230 ftp:quit() 231 con:quit()
231 return ftp:close() 232 return con:close()
232end 233end
233 234
234local function sget(u, body) 235local function sget(u)
235 local gett = parse(u) 236 local gett = parse(u)
236 local t = {} 237 local t = {}
237 gett.sink = ltn12.sink.table(t) 238 gett.sink = ltn12.sink.table(t)
@@ -240,7 +241,7 @@ local function sget(u, body)
240end 241end
241 242
242get = socket.protect(function(gett) 243get = socket.protect(function(gett)
243 if type(gett) == "string" then return sget(gett, body) 244 if type(gett) == "string" then return sget(gett)
244 else return tget(gett) end 245 else return tget(gett) end
245end) 246end)
246 247
diff --git a/src/http.lua b/src/http.lua
index ebe6b54..129b562 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -7,7 +7,7 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load other required modules 10-- Load required modules
11------------------------------------------------------------------------------- 11-------------------------------------------------------------------------------
12local socket = require("socket") 12local socket = require("socket")
13local ltn12 = require("ltn12") 13local ltn12 = require("ltn12")
@@ -17,42 +17,68 @@ local url = require("url")
17----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
18-- Setup namespace 18-- Setup namespace
19------------------------------------------------------------------------------- 19-------------------------------------------------------------------------------
20http = {} 20_LOADED["http"] = getfenv(1)
21-- make all module globals fall into namespace
22setmetatable(http, { __index = _G })
23setfenv(1, http)
24 21
25----------------------------------------------------------------------------- 22-----------------------------------------------------------------------------
26-- Program constants 23-- Program constants
27----------------------------------------------------------------------------- 24-----------------------------------------------------------------------------
28-- connection timeout in seconds 25-- connection timeout in seconds
29TIMEOUT = 60 26TIMEOUT = 4
30-- default port for document retrieval 27-- default port for document retrieval
31PORT = 80 28PORT = 80
32-- user agent field sent in request 29-- user agent field sent in request
33USERAGENT = socket.version 30USERAGENT = socket.VERSION
34-- block size used in transfers 31-- block size used in transfers
35BLOCKSIZE = 2048 32BLOCKSIZE = 2048
36 33
37----------------------------------------------------------------------------- 34-----------------------------------------------------------------------------
38-- Function return value selectors 35-- Low level HTTP API
39----------------------------------------------------------------------------- 36-----------------------------------------------------------------------------
40local function second(a, b) 37local metat = { __index = {} }
41 return b 38
39function open(host, port)
40 local con = socket.try(socket.tcp())
41 socket.try(con:settimeout(TIMEOUT))
42 port = port or PORT
43 socket.try(con:connect(host, port))
44 return setmetatable({ con = con }, metat)
45end
46
47function metat.__index:sendrequestline(method, uri)
48 local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
49 return socket.try(self.con:send(reqline))
42end 50end
43 51
44local function third(a, b, c) 52function metat.__index:sendheaders(headers)
45 return c 53 for i, v in pairs(headers) do
54 socket.try(self.con:send(i .. ": " .. v .. "\r\n"))
55 end
56 -- mark end of request headers
57 socket.try(self.con:send("\r\n"))
58 return 1
46end 59end
47 60
48local function receive_headers(reqt, respt, tmp) 61function metat.__index:sendbody(headers, source, step)
49 local sock = tmp.sock 62 source = source or ltn12.source.empty()
63 step = step or ltn12.pump.step
64 -- if we don't know the size in advance, send chunked and hope for the best
65 local mode
66 if headers["content-length"] then mode = "keep-open"
67 else mode = "http-chunked" end
68 return socket.try(ltn12.pump.all(source, socket.sink(mode, self.con), step))
69end
70
71function metat.__index:receivestatusline()
72 local status = socket.try(self.con:receive())
73 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
74 return socket.try(tonumber(code), status)
75end
76
77function metat.__index:receiveheaders()
50 local line, name, value 78 local line, name, value
51 local headers = {} 79 local headers = {}
52 -- store results
53 respt.headers = headers
54 -- get first line 80 -- get first line
55 line = socket.try(sock:receive()) 81 line = socket.try(self.con:receive())
56 -- headers go until a blank line is found 82 -- headers go until a blank line is found
57 while line ~= "" do 83 while line ~= "" do
58 -- get field-name and value 84 -- get field-name and value
@@ -60,189 +86,137 @@ local function receive_headers(reqt, respt, tmp)
60 socket.try(name and value, "malformed reponse headers") 86 socket.try(name and value, "malformed reponse headers")
61 name = string.lower(name) 87 name = string.lower(name)
62 -- get next line (value might be folded) 88 -- get next line (value might be folded)
63 line = socket.try(sock:receive()) 89 line = socket.try(self.con:receive())
64 -- unfold any folded values 90 -- unfold any folded values
65 while string.find(line, "^%s") do 91 while string.find(line, "^%s") do
66 value = value .. line 92 value = value .. line
67 line = socket.try(sock:receive()) 93 line = socket.try(self.con:receive())
68 end 94 end
69 -- save pair in table 95 -- save pair in table
70 if headers[name] then headers[name] = headers[name] .. ", " .. value 96 if headers[name] then headers[name] = headers[name] .. ", " .. value
71 else headers[name] = value end 97 else headers[name] = value end
72 end 98 end
99 return headers
73end 100end
74 101
75local function receive_body(reqt, respt, tmp) 102function metat.__index:receivebody(headers, sink, step)
76 local sink = reqt.sink or ltn12.sink.null() 103 sink = sink or ltn12.sink.null()
77 local step = reqt.step or ltn12.pump.step 104 step = step or ltn12.pump.step
78 local source 105 local length = tonumber(headers["content-length"])
79 local te = respt.headers["transfer-encoding"] 106 local TE = headers["transfer-encoding"]
80 if te and te ~= "identity" then 107 local mode
81 -- get by chunked transfer-coding of message body 108 if TE and TE ~= "identity" then mode = "http-chunked"
82 source = socket.source("http-chunked", tmp.sock) 109 elseif tonumber(headers["content-length"]) then mode = "by-length"
83 elseif tonumber(respt.headers["content-length"]) then 110 else mode = "default" end
84 -- get by content-length 111 return socket.try(ltn12.pump.all(socket.source(mode, self.con, length),
85 local length = tonumber(respt.headers["content-length"]) 112 sink, step))
86 source = socket.source("by-length", tmp.sock, length)
87 else
88 -- get it all until connection closes
89 source = socket.source(tmp.sock)
90 end
91 socket.try(ltn12.pump.all(source, sink, step))
92end 113end
93 114
94local function send_headers(sock, headers) 115function metat.__index:close()
95 -- send request headers 116 return self.con:close()
96 for i, v in pairs(headers) do
97 socket.try(sock:send(i .. ": " .. v .. "\r\n"))
98 end
99 -- mark end of request headers
100 socket.try(sock:send("\r\n"))
101end 117end
102 118
103local function should_receive_body(reqt, respt, tmp) 119-----------------------------------------------------------------------------
104 if reqt.method == "HEAD" then return nil end 120-- High level HTTP API
105 if respt.code == 204 or respt.code == 304 then return nil end 121-----------------------------------------------------------------------------
106 if respt.code >= 100 and respt.code < 200 then return nil end 122local function uri(reqt)
107 return 1 123 local u = reqt
108end 124 if not reqt.proxy and not PROXY then
109 125 u = {
110local function receive_status(reqt, respt, tmp) 126 path = reqt.path,
111 local status = socket.try(tmp.sock:receive()) 127 params = reqt.params,
112 local code = third(string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) 128 query = reqt.query,
113 -- store results 129 fragment = reqt.fragment
114 respt.code, respt.status = tonumber(code), status
115end
116
117local function request_uri(reqt, respt, tmp)
118 local u = tmp.parsed
119 if not reqt.proxy then
120 local parsed = tmp.parsed
121 u = {
122 path = parsed.path,
123 params = parsed.params,
124 query = parsed.query,
125 fragment = parsed.fragment
126 } 130 }
127 end 131 end
128 return url.build(u) 132 return url.build(u)
129end 133end
130 134
131local function send_request(reqt, respt, tmp) 135local function adjustheaders(headers, host)
132 local uri = request_uri(reqt, respt, tmp)
133 local headers = tmp.headers
134 local step = reqt.step or ltn12.pump.step
135 -- send request line
136 socket.try(tmp.sock:send((reqt.method or "GET")
137 .. " " .. uri .. " HTTP/1.1\r\n"))
138 if reqt.source and not headers["content-length"] then
139 headers["transfer-encoding"] = "chunked"
140 end
141 send_headers(tmp.sock, headers)
142 -- send request message body, if any
143 if not reqt.source then return end
144 if headers["content-length"] then
145 socket.try(ltn12.pump.all(reqt.source,
146 socket.sink(tmp.sock), step))
147 else
148 socket.try(ltn12.pump.all(reqt.source,
149 socket.sink("http-chunked", tmp.sock), step))
150 end
151end
152
153local function open(reqt, respt, tmp)
154 local proxy = reqt.proxy or PROXY
155 local host, port
156 if proxy then
157 local pproxy = url.parse(proxy)
158 socket.try(pproxy.port and pproxy.host, "invalid proxy")
159 host, port = pproxy.host, pproxy.port
160 else
161 host, port = tmp.parsed.host, tmp.parsed.port
162 end
163 -- store results
164 tmp.sock = socket.try(socket.tcp())
165 socket.try(tmp.sock:settimeout(reqt.timeout or TIMEOUT))
166 socket.try(tmp.sock:connect(host, port))
167end
168
169local function adjust_headers(reqt, respt, tmp)
170 local lower = {} 136 local lower = {}
171 -- override with user values 137 -- override with user values
172 for i,v in (reqt.headers or lower) do 138 for i,v in (headers or lower) do
173 lower[string.lower(i)] = v 139 lower[string.lower(i)] = v
174 end 140 end
175 lower["user-agent"] = lower["user-agent"] or USERAGENT 141 lower["user-agent"] = lower["user-agent"] or USERAGENT
176 -- these cannot be overriden 142 -- these cannot be overriden
177 lower["host"] = tmp.parsed.host 143 lower["host"] = host
178 lower["connection"] = "close" 144 return lower
179 -- store results
180 tmp.headers = lower
181end 145end
182 146
183local function parse_url(reqt, respt, tmp) 147local function adjustrequest(reqt)
184 -- parse url with default fields 148 -- parse url with default fields
185 local parsed = url.parse(reqt.url, { 149 local parsed = url.parse(reqt.url, {
186 host = "", 150 host = "",
187 port = PORT, 151 port = PORT,
188 path ="/", 152 path ="/",
189 scheme = "http" 153 scheme = "http"
190 }) 154 })
191 -- scheme has to be http 155 -- explicit info in reqt overrides that given by the URL
192 socket.try(parsed.scheme == "http", 156 for i,v in reqt do parsed[i] = v end
193 string.format("unknown scheme '%s'", parsed.scheme)) 157 -- compute uri if user hasn't overriden
194 -- explicit authentication info overrides that given by the URL 158 parsed.uri = parsed.uri or uri(parsed)
195 parsed.user = reqt.user or parsed.user 159 -- adjust headers in request
196 parsed.password = reqt.password or parsed.password 160 parsed.headers = adjustheaders(parsed.headers, parsed.host)
197 -- store results 161 return parsed
198 tmp.parsed = parsed
199end 162end
200 163
201-- forward declaration 164local function shouldredirect(reqt, respt)
202local request_p 165 return (reqt.redirect ~= false) and
166 (respt.code == 301 or respt.code == 302) and
167 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
168 and (not reqt.nredirects or reqt.nredirects < 5)
169end
203 170
204local function should_authorize(reqt, respt, tmp) 171local function shouldauthorize(reqt, respt)
205 -- if there has been an authorization attempt, it must have failed 172 -- if there has been an authorization attempt, it must have failed
206 if reqt.headers and reqt.headers["authorization"] then return nil end 173 if reqt.headers and reqt.headers["authorization"] then return nil end
207 -- if last attempt didn't fail due to lack of authentication, 174 -- if last attempt didn't fail due to lack of authentication,
208 -- or we don't have authorization information, we can't retry 175 -- or we don't have authorization information, we can't retry
209 return respt.code == 401 and tmp.parsed.user and tmp.parsed.password 176 return respt.code == 401 and reqt.user and reqt.password
210end 177end
211 178
212local function clone(headers) 179local function shouldreceivebody(reqt, respt)
213 if not headers then return nil end 180 if reqt.method == "HEAD" then return nil end
214 local copy = {} 181 local code = respt.code
215 for i,v in pairs(headers) do 182 if code == 204 or code == 304 then return nil end
216 copy[i] = v 183 if code >= 100 and code < 200 then return nil end
217 end 184 return 1
218 return copy
219end 185end
220 186
221local function authorize(reqt, respt, tmp) 187local requestp, authorizep, redirectp
222 local headers = clone(reqt.headers) or {} 188
223 headers["authorization"] = "Basic " .. 189function requestp(reqt)
224 (mime.b64(tmp.parsed.user .. ":" .. tmp.parsed.password)) 190 local reqt = adjustrequest(reqt)
225 local autht = { 191 local respt = {}
226 method = reqt.method, 192 local con = open(reqt.host, reqt.port)
227 url = reqt.url, 193 con:sendrequestline(reqt.method, reqt.uri)
228 source = reqt.source, 194 con:sendheaders(reqt.headers)
229 sink = reqt.sink, 195 con:sendbody(reqt.headers, reqt.source, reqt.step)
230 headers = headers, 196 respt.code, respt.status = con:receivestatusline()
231 timeout = reqt.timeout, 197 respt.headers = con:receiveheaders()
232 proxy = reqt.proxy, 198 if shouldredirect(reqt, respt) then
233 } 199 con:close()
234 request_p(autht, respt, tmp) 200 return redirectp(reqt, respt)
201 elseif shouldauthorize(reqt, respt) then
202 con:close()
203 return authorizep(reqt, respt)
204 elseif shouldreceivebody(reqt, respt) then
205 con:receivebody(respt.headers, reqt.sink, reqt.step)
206 end
207 con:close()
208 return respt
235end 209end
236 210
237local function should_redirect(reqt, respt, tmp) 211function authorizep(reqt, respt)
238 return (reqt.redirect ~= false) and 212 local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
239 (respt.code == 301 or respt.code == 302) and 213 reqt.headers["authorization"] = auth
240 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") 214 return requestp(reqt)
241 and (not tmp.nredirects or tmp.nredirects < 5)
242end 215end
243 216
244local function redirect(reqt, respt, tmp) 217function redirectp(reqt, respt)
245 tmp.nredirects = (tmp.nredirects or 0) + 1 218 -- we create a new table to get rid of anything we don't
219 -- absolutely need, including authentication info
246 local redirt = { 220 local redirt = {
247 method = reqt.method, 221 method = reqt.method,
248 -- the RFC says the redirect URL has to be absolute, but some 222 -- the RFC says the redirect URL has to be absolute, but some
@@ -251,69 +225,38 @@ local function redirect(reqt, respt, tmp)
251 source = reqt.source, 225 source = reqt.source,
252 sink = reqt.sink, 226 sink = reqt.sink,
253 headers = reqt.headers, 227 headers = reqt.headers,
254 timeout = reqt.timeout, 228 proxy = reqt.proxy,
255 proxy = reqt.proxy 229 nredirects = (reqt.nredirects or 0) + 1
256 } 230 }
257 request_p(redirt, respt, tmp) 231 respt = requestp(redirt)
258 -- we pass the location header as a clue we redirected 232 -- we pass the location header as a clue we redirected
259 if respt.headers then respt.headers.location = redirt.url end 233 if respt.headers then respt.headers.location = redirt.url end
260end
261
262local function skip_continue(reqt, respt, tmp)
263 if respt.code == 100 then
264 receive_status(reqt, respt, tmp)
265 end
266end
267
268-- execute a request of through an exception
269function request_p(reqt, respt, tmp)
270 parse_url(reqt, respt, tmp)
271 adjust_headers(reqt, respt, tmp)
272 open(reqt, respt, tmp)
273 send_request(reqt, respt, tmp)
274 receive_status(reqt, respt, tmp)
275 skip_continue(reqt, respt, tmp)
276 receive_headers(reqt, respt, tmp)
277 if should_redirect(reqt, respt, tmp) then
278 tmp.sock:close()
279 redirect(reqt, respt, tmp)
280 elseif should_authorize(reqt, respt, tmp) then
281 tmp.sock:close()
282 authorize(reqt, respt, tmp)
283 elseif should_receive_body(reqt, respt, tmp) then
284 receive_body(reqt, respt, tmp)
285 end
286end
287
288function request(reqt)
289 local respt, tmp = {}, {}
290 local s, e = pcall(request_p, reqt, respt, tmp)
291 if not s then respt.error = e end
292 if tmp.sock then tmp.sock:close() end
293 return respt 234 return respt
294end 235end
295 236
296function get(u) 237request = socket.protect(requestp)
238
239get = socket.protect(function(u)
297 local t = {} 240 local t = {}
298 respt = request { 241 local respt = requestp {
299 url = u, 242 url = u,
300 sink = ltn12.sink.table(t) 243 sink = ltn12.sink.table(t)
301 } 244 }
302 return (table.getn(t) > 0 or nil) and table.concat(t), respt.headers, 245 return (table.getn(t) > 0 or nil) and table.concat(t), respt.headers,
303 respt.code, respt.error 246 respt.code
304end 247end)
305 248
306function post(u, body) 249post = socket.protect(function(u, body)
307 local t = {} 250 local t = {}
308 respt = request { 251 local respt = requestp {
309 url = u, 252 url = u,
310 method = "POST", 253 method = "POST",
311 source = ltn12.source.string(body), 254 source = ltn12.source.string(body),
312 sink = ltn12.sink.table(t), 255 sink = ltn12.sink.table(t),
313 headers = { ["content-length"] = string.len(body) } 256 headers = { ["content-length"] = string.len(body) }
314 } 257 }
315 return (table.getn(t) > 0 or nil) and table.concat(t), 258 return (table.getn(t) > 0 or nil) and table.concat(t),
316 respt.headers, respt.code, respt.error 259 respt.headers, respt.code
317end 260end)
318 261
319return http 262return http
diff --git a/src/inet.c b/src/inet.c
index 3a57441..62c67f1 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -10,7 +10,6 @@
10#include <lua.h> 10#include <lua.h>
11#include <lauxlib.h> 11#include <lauxlib.h>
12 12
13#include "luasocket.h"
14#include "inet.h" 13#include "inet.h"
15 14
16/*=========================================================================*\ 15/*=========================================================================*\
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 41855f0..6228247 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -8,9 +8,8 @@
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9-- Setup namespace 9-- Setup namespace
10----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
11local ltn12 = {} 11_LOADED["ltn12"] = getfenv(1)
12setmetatable(ltn12, { __index = _G }) 12
13setfenv(1, ltn12)
14filter = {} 13filter = {}
15source = {} 14source = {}
16sink = {} 15sink = {}
@@ -19,10 +18,6 @@ pump = {}
19-- 2048 seems to be better in windows... 18-- 2048 seems to be better in windows...
20BLOCKSIZE = 2048 19BLOCKSIZE = 2048
21 20
22local function shift(a, b, c)
23 return b, c
24end
25
26----------------------------------------------------------------------------- 21-----------------------------------------------------------------------------
27-- Filter stuff 22-- Filter stuff
28----------------------------------------------------------------------------- 23-----------------------------------------------------------------------------
@@ -53,7 +48,9 @@ local function chain2(f1, f2)
53 end 48 end
54 end) 49 end)
55 return function(chunk) 50 return function(chunk)
56 return shift(coroutine.resume(co, chunk)) 51 local ret, a, b = coroutine.resume(co, chunk)
52 if ret then return a, b
53 else return nil, a end
57 end 54 end
58end 55end
59 56
@@ -149,7 +146,9 @@ function source.chain(src, f)
149 end 146 end
150 end) 147 end)
151 return function() 148 return function()
152 return shift(coroutine.resume(co)) 149 local ret, a, b = coroutine.resume(co)
150 if ret then return a, b
151 else return nil, a end
153 end 152 end
154end 153end
155 154
@@ -166,7 +165,9 @@ function source.cat(...)
166 end 165 end
167 end) 166 end)
168 return function() 167 return function()
169 return shift(coroutine.resume(co)) 168 local ret, a, b = coroutine.resume(co)
169 if ret then return a, b
170 else return nil, a end
170 end 171 end
171end 172end
172 173
diff --git a/src/luasocket.c b/src/luasocket.c
index ca3a52c..2b0a1fa 100644
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -26,7 +26,7 @@
26#include "luasocket.h" 26#include "luasocket.h"
27 27
28#include "auxiliar.h" 28#include "auxiliar.h"
29#include "base.h" 29#include "except.h"
30#include "timeout.h" 30#include "timeout.h"
31#include "buffer.h" 31#include "buffer.h"
32#include "inet.h" 32#include "inet.h"
@@ -35,11 +35,18 @@
35#include "select.h" 35#include "select.h"
36 36
37/*-------------------------------------------------------------------------*\ 37/*-------------------------------------------------------------------------*\
38* Modules 38* Internal function prototypes
39\*-------------------------------------------------------------------------*/
40static int global_skip(lua_State *L);
41static int global_unload(lua_State *L);
42static int base_open(lua_State *L);
43
44/*-------------------------------------------------------------------------*\
45* Modules and functions
39\*-------------------------------------------------------------------------*/ 46\*-------------------------------------------------------------------------*/
40static const luaL_reg mod[] = { 47static const luaL_reg mod[] = {
41 {"auxiliar", aux_open}, 48 {"auxiliar", aux_open},
42 {"base", base_open}, 49 {"except", except_open},
43 {"timeout", tm_open}, 50 {"timeout", tm_open},
44 {"buffer", buf_open}, 51 {"buffer", buf_open},
45 {"inet", inet_open}, 52 {"inet", inet_open},
@@ -49,11 +56,69 @@ static const luaL_reg mod[] = {
49 {NULL, NULL} 56 {NULL, NULL}
50}; 57};
51 58
59static luaL_reg func[] = {
60 {"skip", global_skip},
61 {"__unload", global_unload},
62 {NULL, NULL}
63};
64
65/*-------------------------------------------------------------------------*\
66* Skip a few arguments
67\*-------------------------------------------------------------------------*/
68static int global_skip(lua_State *L) {
69 int amount = luaL_checkint(L, 1);
70 int ret = lua_gettop(L) - amount - 1;
71 return ret >= 0 ? ret : 0;
72}
73
74/*-------------------------------------------------------------------------*\
75* Unloads the library
76\*-------------------------------------------------------------------------*/
77static int global_unload(lua_State *L) {
78 sock_close();
79 return 0;
80}
81
82/*-------------------------------------------------------------------------*\
83* Setup basic stuff.
84\*-------------------------------------------------------------------------*/
85static int base_open(lua_State *L) {
86 if (sock_open()) {
87 /* whoever is loading the library replaced the global environment
88 * with the namespace table */
89 lua_pushvalue(L, LUA_GLOBALSINDEX);
90 /* make sure library is still "requirable" if initialized staticaly */
91 lua_pushstring(L, "_LOADEDLIB");
92 lua_gettable(L, -2);
93 lua_pushstring(L, LUASOCKET_LIBNAME);
94 lua_pushcfunction(L, (lua_CFunction) luaopen_socket);
95 lua_settable(L, -3);
96 lua_pop(L, 1);
97#ifdef LUASOCKET_DEBUG
98 lua_pushstring(L, "DEBUG");
99 lua_pushboolean(L, 1);
100 lua_rawset(L, -3);
101#endif
102 /* make version string available to scripts */
103 lua_pushstring(L, "VERSION");
104 lua_pushstring(L, LUASOCKET_VERSION);
105 lua_rawset(L, -3);
106 /* export other functions */
107 luaL_openlib(L, NULL, func, 0);
108 return 1;
109 } else {
110 lua_pushstring(L, "unable to initialize library");
111 lua_error(L);
112 return 0;
113 }
114}
115
52/*-------------------------------------------------------------------------*\ 116/*-------------------------------------------------------------------------*\
53* Initializes all library modules. 117* Initializes all library modules.
54\*-------------------------------------------------------------------------*/ 118\*-------------------------------------------------------------------------*/
55LUASOCKET_API int luaopen_socket(lua_State *L) { 119LUASOCKET_API int luaopen_socket(lua_State *L) {
56 int i; 120 int i;
121 base_open(L);
57 for (i = 0; mod[i].name; i++) mod[i].func(L); 122 for (i = 0; mod[i].name; i++) mod[i].func(L);
58 return 1; 123 return 1;
59} 124}
diff --git a/src/luasocket.h b/src/luasocket.h
index 716b7ff..6d30605 100644
--- a/src/luasocket.h
+++ b/src/luasocket.h
@@ -25,6 +25,7 @@
25/*-------------------------------------------------------------------------*\ 25/*-------------------------------------------------------------------------*\
26* Initializes the library. 26* Initializes the library.
27\*-------------------------------------------------------------------------*/ 27\*-------------------------------------------------------------------------*/
28#define LUASOCKET_LIBNAME "socket"
28LUASOCKET_API int luaopen_socket(lua_State *L); 29LUASOCKET_API int luaopen_socket(lua_State *L);
29 30
30#endif /* LUASOCKET_H */ 31#endif /* LUASOCKET_H */
diff --git a/src/mime.c b/src/mime.c
index f42528c..5750714 100644
--- a/src/mime.c
+++ b/src/mime.c
@@ -76,7 +76,17 @@ static UC b64unbase[256];
76\*-------------------------------------------------------------------------*/ 76\*-------------------------------------------------------------------------*/
77MIME_API int luaopen_mime(lua_State *L) 77MIME_API int luaopen_mime(lua_State *L)
78{ 78{
79 lua_newtable(L); 79 /* whoever is loading the library replaced the global environment
80 * with the namespace table */
81 lua_pushvalue(L, LUA_GLOBALSINDEX);
82 /* make sure library is still "requirable" if initialized staticaly */
83 lua_pushstring(L, "_LOADEDLIB");
84 lua_gettable(L, -2);
85 lua_pushstring(L, MIME_LIBNAME);
86 lua_pushcfunction(L, (lua_CFunction) luaopen_mime);
87 lua_settable(L, -3);
88 lua_pop(L, 1);
89 /* export functions */
80 luaL_openlib(L, NULL, func, 0); 90 luaL_openlib(L, NULL, func, 0);
81 /* initialize lookup tables */ 91 /* initialize lookup tables */
82 qpsetup(qpclass, qpunbase); 92 qpsetup(qpclass, qpunbase);
diff --git a/src/mime.h b/src/mime.h
index 6febedf..b82d61a 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -19,6 +19,7 @@
19#define MIME_API extern 19#define MIME_API extern
20#endif 20#endif
21 21
22#define MIME_LIBNAME "mime"
22MIME_API int luaopen_mime(lua_State *L); 23MIME_API int luaopen_mime(lua_State *L);
23 24
24#endif /* MIME_H */ 25#endif /* MIME_H */
diff --git a/src/mime.lua b/src/mime.lua
index ecf310d..000404f 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -6,23 +6,15 @@
6----------------------------------------------------------------------------- 6-----------------------------------------------------------------------------
7 7
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9-- Load MIME from dynamic library
10-- Comment these lines if you are loading static
11-----------------------------------------------------------------------------
12local open = assert(loadlib("mime", "luaopen_mime"))
13local mime = assert(open())
14
15-----------------------------------------------------------------------------
16-- Load other required modules 9-- Load other required modules
17----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
11local mime = requirelib("mime", "luaopen_mime", getfenv(1))
18local ltn12 = require("ltn12") 12local ltn12 = require("ltn12")
19 13
20----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
21-- Setup namespace 15-- Setup namespace
22----------------------------------------------------------------------------- 16-----------------------------------------------------------------------------
23-- make all module globals fall into mime namespace 17_LOADED["mime"] = mime
24setmetatable(mime, { __index = _G })
25setfenv(1, mime)
26 18
27-- encode, decode and wrap algorithm tables 19-- encode, decode and wrap algorithm tables
28encodet = {} 20encodet = {}
@@ -48,7 +40,7 @@ end
48 40
49encodet['quoted-printable'] = function(mode) 41encodet['quoted-printable'] = function(mode)
50 return ltn12.filter.cycle(qp, "", 42 return ltn12.filter.cycle(qp, "",
51 (mode == "binary") and "=0D=0A" or "\13\10") 43 (mode == "binary") and "=0D=0A" or "\r\n")
52end 44end
53 45
54-- define the decoding filters 46-- define the decoding filters
diff --git a/src/select.c b/src/select.c
index 1ebd82c..13f9d6e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -9,26 +9,21 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13#include "socket.h" 12#include "socket.h"
14#include "auxiliar.h"
15#include "select.h" 13#include "select.h"
16 14
17/*=========================================================================*\ 15/*=========================================================================*\
18* Internal function prototypes. 16* Internal function prototypes.
19\*=========================================================================*/ 17\*=========================================================================*/
20static int meth_set(lua_State *L); 18static int getfd(lua_State *L);
21static int meth_isset(lua_State *L); 19static int dirty(lua_State *L);
22static int c_select(lua_State *L); 20static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set);
21static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
22static void return_fd(lua_State *L, fd_set *set, int max_fd,
23 int itab, int tab, int start);
24static void make_assoc(lua_State *L, int tab);
23static int global_select(lua_State *L); 25static int global_select(lua_State *L);
24 26
25/* fd_set object methods */
26static luaL_reg set[] = {
27 {"set", meth_set},
28 {"isset", meth_isset},
29 {NULL, NULL}
30};
31
32/* functions in library namespace */ 27/* functions in library namespace */
33static luaL_reg func[] = { 28static luaL_reg func[] = {
34 {"select", global_select}, 29 {"select", global_select},
@@ -36,22 +31,13 @@ static luaL_reg func[] = {
36}; 31};
37 32
38/*=========================================================================*\ 33/*=========================================================================*\
39* Internal function prototypes. 34* Exported functions
40\*=========================================================================*/ 35\*=========================================================================*/
41/*-------------------------------------------------------------------------*\ 36/*-------------------------------------------------------------------------*\
42* Initializes module 37* Initializes module
43\*-------------------------------------------------------------------------*/ 38\*-------------------------------------------------------------------------*/
44int select_open(lua_State *L) 39int select_open(lua_State *L) {
45{ 40 luaL_openlib(L, NULL, func, 0);
46 /* get select auxiliar lua function from lua code and register
47 * pass it as an upvalue to global_select */
48#ifdef LUASOCKET_COMPILED
49#include "select.lch"
50#else
51 lua_dofile(L, "select.lua");
52#endif
53 luaL_openlib(L, NULL, func, 1);
54 aux_newclass(L, "select{fd_set}", set);
55 return 0; 41 return 0;
56} 42}
57 43
@@ -61,64 +47,149 @@ int select_open(lua_State *L)
61/*-------------------------------------------------------------------------*\ 47/*-------------------------------------------------------------------------*\
62* Waits for a set of sockets until a condition is met or timeout. 48* Waits for a set of sockets until a condition is met or timeout.
63\*-------------------------------------------------------------------------*/ 49\*-------------------------------------------------------------------------*/
64static int global_select(lua_State *L) 50static int global_select(lua_State *L) {
65{ 51 int timeout, rtab, wtab, itab, max_fd, ret, ndirty;
66 fd_set *read_fd_set, *write_fd_set; 52 fd_set rset, wset;
67 /* make sure we have enough arguments (nil is the default) */ 53 FD_ZERO(&rset); FD_ZERO(&wset);
68 lua_settop(L, 3); 54 lua_settop(L, 3);
69 /* check timeout */ 55 timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000);
70 if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) 56 lua_newtable(L); itab = lua_gettop(L);
71 luaL_argerror(L, 3, "number or nil expected"); 57 lua_newtable(L); rtab = lua_gettop(L);
72 /* select auxiliar lua function to be called comes first */ 58 lua_newtable(L); wtab = lua_gettop(L);
73 lua_pushvalue(L, lua_upvalueindex(1)); 59 max_fd = collect_fd(L, 1, -1, itab, &rset);
74 lua_insert(L, 1); 60 ndirty = check_dirty(L, 1, rtab, &rset);
75 /* pass fd_set objects */ 61 timeout = ndirty > 0? 0: timeout;
76 read_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 62 max_fd = collect_fd(L, 2, max_fd, itab, &wset);
77 FD_ZERO(read_fd_set); 63 ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout);
78 aux_setclass(L, "select{fd_set}", -1); 64 if (ret > 0 || (ret == 0 && ndirty > 0)) {
79 write_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 65 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
80 FD_ZERO(write_fd_set); 66 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
81 aux_setclass(L, "select{fd_set}", -1); 67 make_assoc(L, rtab);
82 /* pass select auxiliar C function */ 68 make_assoc(L, wtab);
83 lua_pushcfunction(L, c_select); 69 return 2;
84 /* call select auxiliar lua function */ 70 } else if (ret == 0) {
85 lua_call(L, 6, 3); 71 lua_pushstring(L, "timeout");
86 return 3; 72 return 3;
73 } else {
74 lua_pushnil(L);
75 lua_pushnil(L);
76 lua_pushstring(L, "error");
77 return 3;
78 }
87} 79}
88 80
89/*=========================================================================*\ 81/*=========================================================================*\
90* Lua methods 82* Internal functions
91\*=========================================================================*/ 83\*=========================================================================*/
92static int meth_set(lua_State *L) 84static int getfd(lua_State *L) {
93{ 85 int fd = -1;
94 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 86 lua_pushstring(L, "getfd");
95 t_sock fd = (t_sock) lua_tonumber(L, 2); 87 lua_gettable(L, -2);
96 if (fd >= 0) FD_SET(fd, set); 88 if (!lua_isnil(L, -1)) {
97 return 0; 89 lua_pushvalue(L, -2);
90 lua_call(L, 1, 1);
91 if (lua_isnumber(L, -1))
92 fd = lua_tonumber(L, -1);
93 }
94 lua_pop(L, 1);
95 return fd;
98} 96}
99 97
100static int meth_isset(lua_State *L) 98static int dirty(lua_State *L) {
101{ 99 int is = 0;
102 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 100 lua_pushstring(L, "dirty");
103 t_sock fd = (t_sock) lua_tonumber(L, 2); 101 lua_gettable(L, -2);
104 if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); 102 if (!lua_isnil(L, -1)) {
105 else lua_pushnil(L); 103 lua_pushvalue(L, -2);
106 return 1; 104 lua_call(L, 1, 1);
105 is = lua_toboolean(L, -1);
106 }
107 lua_pop(L, 1);
108 return is;
107} 109}
108 110
109/*=========================================================================*\ 111static int collect_fd(lua_State *L, int tab, int max_fd,
110* Internal functions 112 int itab, fd_set *set) {
111\*=========================================================================*/ 113 int i = 1;
112static int c_select(lua_State *L) 114 if (lua_isnil(L, tab))
113{ 115 return max_fd;
114 int max_fd = (int) lua_tonumber(L, 1); 116 while (1) {
115 fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); 117 int fd;
116 fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); 118 lua_pushnumber(L, i);
117 int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); 119 lua_gettable(L, tab);
118 struct timeval tv; 120 if (lua_isnil(L, -1)) {
119 tv.tv_sec = timeout / 1000; 121 lua_pop(L, 1);
120 tv.tv_usec = (timeout % 1000) * 1000; 122 break;
121 lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, 123 }
122 timeout < 0 ? NULL : &tv)); 124 fd = getfd(L);
123 return 1; 125 if (fd > 0) {
126 FD_SET(fd, set);
127 if (max_fd < fd) max_fd = fd;
128 lua_pushnumber(L, fd);
129 lua_pushvalue(L, -2);
130 lua_settable(L, itab);
131 }
132 lua_pop(L, 1);
133 i = i + 1;
134 }
135 return max_fd;
136}
137
138static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
139 int ndirty = 0, i = 1;
140 if (lua_isnil(L, tab))
141 return 0;
142 while (1) {
143 int fd;
144 lua_pushnumber(L, i);
145 lua_gettable(L, tab);
146 if (lua_isnil(L, -1)) {
147 lua_pop(L, 1);
148 break;
149 }
150 fd = getfd(L);
151 if (fd > 0 && dirty(L)) {
152 lua_pushnumber(L, ++ndirty);
153 lua_pushvalue(L, -2);
154 lua_settable(L, dtab);
155 FD_CLR(fd, set);
156 }
157 lua_pop(L, 1);
158 i = i + 1;
159 }
160 return ndirty;
161}
162
163static void return_fd(lua_State *L, fd_set *set, int max_fd,
164 int itab, int tab, int start) {
165 int fd;
166 for (fd = 0; fd < max_fd; fd++) {
167 if (FD_ISSET(fd, set)) {
168 lua_pushnumber(L, ++start);
169 lua_pushnumber(L, fd);
170 lua_gettable(L, itab);
171 lua_settable(L, tab);
172 }
173 }
174}
175
176static void make_assoc(lua_State *L, int tab) {
177 int i = 1, atab;
178 lua_newtable(L); atab = lua_gettop(L);
179 while (1) {
180 lua_pushnumber(L, i);
181 lua_gettable(L, tab);
182 if (!lua_isnil(L, -1)) {
183 lua_pushnumber(L, i);
184 lua_pushvalue(L, -2);
185 lua_settable(L, atab);
186 lua_pushnumber(L, i);
187 lua_settable(L, atab);
188 } else {
189 lua_pop(L, 1);
190 break;
191 }
192 i = i+1;
193 }
124} 194}
195
diff --git a/src/smtp.lua b/src/smtp.lua
index 7ae99a5..dc80c35 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -7,15 +7,9 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load SMTP from dynamic library 10-- Load required modules
11-- Comment these lines if you are loading static
12-----------------------------------------------------------------------------
13local open = assert(loadlib("smtp", "luaopen_smtp"))
14local smtp = assert(open())
15
16-----------------------------------------------------------------------------
17-- Load other required modules
18----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local smtp = requirelib("smtp")
19local socket = require("socket") 13local socket = require("socket")
20local ltn12 = require("ltn12") 14local ltn12 = require("ltn12")
21local tp = require("tp") 15local tp = require("tp")
@@ -23,10 +17,10 @@ local tp = require("tp")
23----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
24-- Setup namespace 18-- Setup namespace
25----------------------------------------------------------------------------- 19-----------------------------------------------------------------------------
26-- make all module globals fall into smtp namespace 20_LOADED["smtp"] = smtp
27setmetatable(smtp, { __index = _G })
28setfenv(1, smtp)
29 21
22-- timeout for connection
23TIMEOUT = 60
30-- default server used to send e-mails 24-- default server used to send e-mails
31SERVER = "localhost" 25SERVER = "localhost"
32-- default port 26-- default port
@@ -94,9 +88,7 @@ function metat.__index:send(mailt)
94end 88end
95 89
96function open(server, port) 90function open(server, port)
97 print(server or SERVER, port or PORT) 91 local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT))
98 local tp, error = tp.connect(server or SERVER, port or PORT)
99 if not tp then return nil, error end
100 return setmetatable({tp = tp}, metat) 92 return setmetatable({tp = tp}, metat)
101end 93end
102 94
@@ -121,7 +113,10 @@ local function send_multipart(mesgt)
121 coroutine.yield('content-type: multipart/mixed; boundary="' .. 113 coroutine.yield('content-type: multipart/mixed; boundary="' ..
122 bd .. '"\r\n\r\n') 114 bd .. '"\r\n\r\n')
123 -- send preamble 115 -- send preamble
124 if mesgt.body.preamble then coroutine.yield(mesgt.body.preamble) end 116 if mesgt.body.preamble then
117 coroutine.yield(mesgt.body.preamble)
118 coroutine.yield("\r\n")
119 end
125 -- send each part separated by a boundary 120 -- send each part separated by a boundary
126 for i, m in ipairs(mesgt.body) do 121 for i, m in ipairs(mesgt.body) do
127 coroutine.yield("\r\n--" .. bd .. "\r\n") 122 coroutine.yield("\r\n--" .. bd .. "\r\n")
@@ -130,7 +125,10 @@ local function send_multipart(mesgt)
130 -- send last boundary 125 -- send last boundary
131 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") 126 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
132 -- send epilogue 127 -- send epilogue
133 if mesgt.body.epilogue then coroutine.yield(mesgt.body.epilogue) end 128 if mesgt.body.epilogue then
129 coroutine.yield(mesgt.body.epilogue)
130 coroutine.yield("\r\n")
131 end
134end 132end
135 133
136-- yield message body from a source 134-- yield message body from a source
@@ -183,12 +181,12 @@ end
183-- set defaul headers 181-- set defaul headers
184local function adjust_headers(mesgt) 182local function adjust_headers(mesgt)
185 local lower = {} 183 local lower = {}
186 for i,v in (mesgt or lower) do 184 for i,v in (mesgt.headers or lower) do
187 lower[string.lower(i)] = v 185 lower[string.lower(i)] = v
188 end 186 end
189 lower["date"] = lower["date"] or 187 lower["date"] = lower["date"] or
190 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) 188 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
191 lower["x-mailer"] = lower["x-mailer"] or socket.version 189 lower["x-mailer"] = lower["x-mailer"] or socket.VERSION
192 -- this can't be overriden 190 -- this can't be overriden
193 lower["mime-version"] = "1.0" 191 lower["mime-version"] = "1.0"
194 mesgt.headers = lower 192 mesgt.headers = lower
@@ -198,18 +196,22 @@ function message(mesgt)
198 adjust_headers(mesgt) 196 adjust_headers(mesgt)
199 -- create and return message source 197 -- create and return message source
200 local co = coroutine.create(function() send_message(mesgt) end) 198 local co = coroutine.create(function() send_message(mesgt) end)
201 return function() return socket.skip(1, coroutine.resume(co)) end 199 return function()
200 local ret, a, b = coroutine.resume(co)
201 if ret then return a, b
202 else return nil, a end
203 end
202end 204end
203 205
204--------------------------------------------------------------------------- 206---------------------------------------------------------------------------
205-- High level SMTP API 207-- High level SMTP API
206----------------------------------------------------------------------------- 208-----------------------------------------------------------------------------
207send = socket.protect(function(mailt) 209send = socket.protect(function(mailt)
208 local smtp = socket.try(open(mailt.server, mailt.port)) 210 local con = open(mailt.server, mailt.port)
209 smtp:greet(mailt.domain) 211 con:greet(mailt.domain)
210 smtp:send(mailt) 212 con:send(mailt)
211 smtp:quit() 213 con:quit()
212 return smtp:close() 214 return con:close()
213end) 215end)
214 216
215return smtp 217return smtp
diff --git a/src/socket.lua b/src/socket.lua
index 418cd1b..9aa6437 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -7,8 +7,8 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8-- Load LuaSocket from dynamic library 8-- Load LuaSocket from dynamic library
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10local open = assert(loadlib("luasocket", "luaopen_socket")) 10local socket = requirelib("luasocket", "luaopen_socket", getfenv(1))
11local socket = assert(open()) 11_LOADED["socket"] = socket
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Auxiliar functions 14-- Auxiliar functions
@@ -116,18 +116,21 @@ socket.sourcet["by-length"] = function(sock, length)
116end 116end
117 117
118socket.sourcet["until-closed"] = function(sock) 118socket.sourcet["until-closed"] = function(sock)
119 local done
119 return setmetatable({ 120 return setmetatable({
120 getfd = function() return sock:getfd() end, 121 getfd = function() return sock:getfd() end,
121 dirty = function() return sock:dirty() end 122 dirty = function() return sock:dirty() end
122 }, { 123 }, {
123 __call = ltn12.source.simplify(function() 124 __call = function()
125 if done then return nil end
124 local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 126 local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
125 if not err then return chunk 127 if not err then return chunk
126 elseif err == "closed" then 128 elseif err == "closed" then
127 sock:close() 129 sock:close()
128 return partial, ltn12.source.empty() 130 done = 1
131 return partial
129 else return nil, err end 132 else return nil, err end
130 end) 133 end
131 }) 134 })
132end 135end
133 136
diff --git a/src/tcp.c b/src/tcp.c
index 90cfcde..845e0a3 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -9,13 +9,10 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13
14#include "auxiliar.h" 12#include "auxiliar.h"
15#include "socket.h" 13#include "socket.h"
16#include "inet.h" 14#include "inet.h"
17#include "options.h" 15#include "options.h"
18#include "base.h"
19#include "tcp.h" 16#include "tcp.h"
20 17
21/*=========================================================================*\ 18/*=========================================================================*\
@@ -41,7 +38,7 @@ static int meth_dirty(lua_State *L);
41/* tcp object methods */ 38/* tcp object methods */
42static luaL_reg tcp[] = { 39static luaL_reg tcp[] = {
43 {"__gc", meth_close}, 40 {"__gc", meth_close},
44 {"__tostring", base_meth_tostring}, 41 {"__tostring", aux_tostring},
45 {"accept", meth_accept}, 42 {"accept", meth_accept},
46 {"bind", meth_bind}, 43 {"bind", meth_bind},
47 {"close", meth_close}, 44 {"close", meth_close},
diff --git a/src/timeout.c b/src/timeout.c
index bd6c3b4..4f9a315 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -26,6 +26,14 @@
26#endif 26#endif
27#endif 27#endif
28 28
29/* min and max macros */
30#ifndef MIN
31#define MIN(x, y) ((x) < (y) ? x : y)
32#endif
33#ifndef MAX
34#define MAX(x, y) ((x) > (y) ? x : y)
35#endif
36
29/*=========================================================================*\ 37/*=========================================================================*\
30* Internal function prototypes 38* Internal function prototypes
31\*=========================================================================*/ 39\*=========================================================================*/
diff --git a/src/tp.lua b/src/tp.lua
index 3e9dba6..56dd8bc 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -2,24 +2,28 @@
2-- Unified SMTP/FTP subsystem 2-- Unified SMTP/FTP subsystem
3-- LuaSocket toolkit. 3-- LuaSocket toolkit.
4-- Author: Diego Nehab 4-- Author: Diego Nehab
5-- Conforming to: RFC 2616, LTN7
6-- RCS ID: $Id$ 5-- RCS ID: $Id$
7----------------------------------------------------------------------------- 6-----------------------------------------------------------------------------
8 7
9----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
10-- Load other required modules 9-- Load required modules
11----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
12local socket = require("socket") 11local socket = require("socket")
12local ltn12 = require("ltn12")
13 13
14----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
15-- Setup namespace 15-- Setup namespace
16----------------------------------------------------------------------------- 16-----------------------------------------------------------------------------
17tp = {} 17_LOADED["tp"] = getfenv(1)
18setmetatable(tp, { __index = _G })
19setfenv(1, tp)
20 18
19-----------------------------------------------------------------------------
20-- Program constants
21-----------------------------------------------------------------------------
21TIMEOUT = 60 22TIMEOUT = 60
22 23
24-----------------------------------------------------------------------------
25-- Implementation
26-----------------------------------------------------------------------------
23-- gets server reply (works for SMTP and FTP) 27-- gets server reply (works for SMTP and FTP)
24local function get_reply(control) 28local function get_reply(control)
25 local code, current, sep 29 local code, current, sep
@@ -37,7 +41,6 @@ local function get_reply(control)
37 -- reply ends with same code 41 -- reply ends with same code
38 until code == current and sep == " " 42 until code == current and sep == " "
39 end 43 end
40print(reply)
41 return code, reply 44 return code, reply
42end 45end
43 46
@@ -46,6 +49,7 @@ local metat = { __index = {} }
46 49
47function metat.__index:check(ok) 50function metat.__index:check(ok)
48 local code, reply = get_reply(self.control) 51 local code, reply = get_reply(self.control)
52print(reply)
49 if not code then return nil, reply end 53 if not code then return nil, reply end
50 if type(ok) ~= "function" then 54 if type(ok) ~= "function" then
51 if type(ok) == "table" then 55 if type(ok) == "table" then
@@ -103,11 +107,11 @@ function metat.__index:close()
103end 107end
104 108
105-- connect with server and return control object 109-- connect with server and return control object
106function connect(host, port) 110connect = socket.protect(function(host, port, timeout)
107 local control, err = socket.connect(host, port) 111 local control = socket.try(socket.tcp())
108 if not control then return nil, err end 112 socket.try(control:settimeout(timeout or TIMEOUT))
109 control:settimeout(TIMEOUT) 113 socket.try(control:connect(host, port))
110 return setmetatable({control = control}, metat) 114 return setmetatable({control = control}, metat)
111end 115end)
112 116
113return tp 117return tp
diff --git a/src/udp.c b/src/udp.c
index 4770a2e..51d6402 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -9,13 +9,10 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13
14#include "auxiliar.h" 12#include "auxiliar.h"
15#include "socket.h" 13#include "socket.h"
16#include "inet.h" 14#include "inet.h"
17#include "options.h" 15#include "options.h"
18#include "base.h"
19#include "udp.h" 16#include "udp.h"
20 17
21/*=========================================================================*\ 18/*=========================================================================*\
@@ -51,7 +48,7 @@ static luaL_reg udp[] = {
51 {"close", meth_close}, 48 {"close", meth_close},
52 {"setoption", meth_setoption}, 49 {"setoption", meth_setoption},
53 {"__gc", meth_close}, 50 {"__gc", meth_close},
54 {"__tostring", base_meth_tostring}, 51 {"__tostring", aux_tostring},
55 {"getfd", meth_getfd}, 52 {"getfd", meth_getfd},
56 {"setfd", meth_setfd}, 53 {"setfd", meth_setfd},
57 {"dirty", meth_dirty}, 54 {"dirty", meth_dirty},
diff --git a/src/url.lua b/src/url.lua
index 2441268..aac2a47 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -9,9 +9,7 @@
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Setup namespace 10-- Setup namespace
11----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local url = {} 12_LOADED["url"] = getfenv(1)
13setmetatable(url, { __index = _G })
14setfenv(1, url)
15 13
16----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
17-- Encodes a string into its escaped hexadecimal representation 15-- Encodes a string into its escaped hexadecimal representation