aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCaleb Maclennan <caleb@alerque.com>2023-11-10 09:12:04 +0300
committerCaleb Maclennan <caleb@alerque.com>2023-11-10 09:12:04 +0300
commit5c4fc93d5f4137bf4c22ddf1a048c907a4a26727 (patch)
treea9a68e1f6a9c3bfe2b64fa1c3a4098865b7d3b5d /src
parentccef3bc4e2aa6ee5b997a80aabb58f4ff0b0e98f (diff)
parent43a97b7f0053313b43906371dbdc226271e6c8ab (diff)
downloadluasocket-hjelmeland-patch-1.tar.gz
luasocket-hjelmeland-patch-1.tar.bz2
luasocket-hjelmeland-patch-1.zip
Merge branch 'master' into hjelmeland-patch-1hjelmeland-patch-1
Diffstat (limited to 'src')
-rw-r--r--src/auxiliar.c10
-rw-r--r--src/auxiliar.h20
-rw-r--r--src/buffer.c10
-rw-r--r--src/buffer.h15
-rw-r--r--src/compat.c22
-rw-r--r--src/compat.h19
-rw-r--r--src/except.c62
-rw-r--r--src/except.h33
-rw-r--r--src/ftp.lua92
-rw-r--r--src/http.lua131
-rwxr-xr-x[-rw-r--r--]src/inet.c20
-rw-r--r--src/inet.h26
-rw-r--r--src/io.c4
-rw-r--r--src/io.h13
-rw-r--r--src/ltn12.lua15
-rwxr-xr-x[-rw-r--r--]src/luasocket.c12
-rw-r--r--src/luasocket.h15
-rwxr-xr-x[-rw-r--r--]src/makefile174
-rw-r--r--src/mbox.lua15
-rwxr-xr-x[-rw-r--r--]src/mime.c165
-rw-r--r--src/mime.h11
-rw-r--r--src/mime.lua15
-rw-r--r--src/options.c175
-rw-r--r--src/options.h110
-rw-r--r--src/select.c17
-rw-r--r--src/select.h8
-rw-r--r--src/serial.c7
-rwxr-xr-x[-rw-r--r--]src/socket.h57
-rw-r--r--src/tcp.c55
-rw-r--r--src/tcp.h10
-rw-r--r--src/timeout.c22
-rw-r--r--src/timeout.h18
-rw-r--r--src/tp.lua12
-rwxr-xr-x[-rw-r--r--]src/udp.c111
-rw-r--r--src/udp.h13
-rw-r--r--src/unix.c349
-rw-r--r--src/unix.h8
-rw-r--r--src/unixdgram.c405
-rw-r--r--src/unixdgram.h28
-rw-r--r--src/unixstream.c355
-rw-r--r--src/unixstream.h29
-rw-r--r--src/url.lua98
-rw-r--r--src/usocket.c15
-rwxr-xr-x[-rw-r--r--]src/wsocket.c29
44 files changed, 2035 insertions, 795 deletions
diff --git a/src/auxiliar.c b/src/auxiliar.c
index 18fa8e4..93a66a0 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -2,14 +2,11 @@
2* Auxiliar routines for class hierarchy manipulation 2* Auxiliar routines for class hierarchy manipulation
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
6#include "auxiliar.h"
5#include <string.h> 7#include <string.h>
6#include <stdio.h> 8#include <stdio.h>
7 9
8#include "auxiliar.h"
9
10/*=========================================================================*\
11* Exported functions
12\*=========================================================================*/
13/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------*\
14* Initializes the module 11* Initializes the module
15\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
@@ -143,7 +140,7 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
143* otherwise 140* otherwise
144\*-------------------------------------------------------------------------*/ 141\*-------------------------------------------------------------------------*/
145void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { 142void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
146 return luaL_checkudata(L, objidx, classname); 143 return luaL_testudata(L, objidx, classname);
147} 144}
148 145
149/*-------------------------------------------------------------------------*\ 146/*-------------------------------------------------------------------------*\
@@ -155,4 +152,3 @@ int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
155 luaL_typename(L, narg)); 152 luaL_typename(L, narg));
156 return luaL_argerror(L, narg, msg); 153 return luaL_argerror(L, narg, msg);
157} 154}
158
diff --git a/src/auxiliar.h b/src/auxiliar.h
index 65511d4..e8c3ead 100644
--- a/src/auxiliar.h
+++ b/src/auxiliar.h
@@ -29,20 +29,26 @@
29* reverse mapping are done using lauxlib. 29* reverse mapping are done using lauxlib.
30\*=========================================================================*/ 30\*=========================================================================*/
31 31
32#include "lua.h" 32#include "luasocket.h"
33#include "lauxlib.h" 33
34#include "compat.h" 34#ifndef _WIN32
35#pragma GCC visibility push(hidden)
36#endif
35 37
36int auxiliar_open(lua_State *L); 38int auxiliar_open(lua_State *L);
37void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); 39void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
40int auxiliar_tostring(lua_State *L);
38void auxiliar_add2group(lua_State *L, const char *classname, const char *group); 41void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
39void auxiliar_setclass(lua_State *L, const char *classname, int objidx); 42int auxiliar_checkboolean(lua_State *L, int objidx);
40void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); 43void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
41void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); 44void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
42void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); 45void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
43void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); 46void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
44int auxiliar_checkboolean(lua_State *L, int objidx); 47void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
45int auxiliar_tostring(lua_State *L);
46int auxiliar_typeerror(lua_State *L, int narg, const char *tname); 48int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
47 49
50#ifndef _WIN32
51#pragma GCC visibility pop
52#endif
53
48#endif /* AUXILIAR_H */ 54#endif /* AUXILIAR_H */
diff --git a/src/buffer.c b/src/buffer.c
index fff1634..7148be3 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2,10 +2,7 @@
2* Input/Output interface for Lua programs 2* Input/Output interface for Lua programs
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "lua.h" 5#include "luasocket.h"
6#include "lauxlib.h"
7#include "compat.h"
8
9#include "buffer.h" 6#include "buffer.h"
10 7
11/*=========================================================================*\ 8/*=========================================================================*\
@@ -106,11 +103,14 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
106* object:receive() interface 103* object:receive() interface
107\*-------------------------------------------------------------------------*/ 104\*-------------------------------------------------------------------------*/
108int buffer_meth_receive(lua_State *L, p_buffer buf) { 105int buffer_meth_receive(lua_State *L, p_buffer buf) {
109 int err = IO_DONE, top = lua_gettop(L); 106 int err = IO_DONE, top;
110 luaL_Buffer b; 107 luaL_Buffer b;
111 size_t size; 108 size_t size;
112 const char *part = luaL_optlstring(L, 3, "", &size); 109 const char *part = luaL_optlstring(L, 3, "", &size);
113 timeout_markstart(buf->tm); 110 timeout_markstart(buf->tm);
111 /* make sure we don't confuse buffer stuff with arguments */
112 lua_settop(L, 3);
113 top = lua_gettop(L);
114 /* initialize buffer with optional extra prefix 114 /* initialize buffer with optional extra prefix
115 * (useful for concatenating previous partial results) */ 115 * (useful for concatenating previous partial results) */
116 luaL_buffinit(L, &b); 116 luaL_buffinit(L, &b);
diff --git a/src/buffer.h b/src/buffer.h
index 1281bb3..a0901fc 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -15,8 +15,7 @@
15* The module is built on top of the I/O abstraction defined in io.h and the 15* The module is built on top of the I/O abstraction defined in io.h and the
16* timeout management is done with the timeout.h interface. 16* timeout management is done with the timeout.h interface.
17\*=========================================================================*/ 17\*=========================================================================*/
18#include "lua.h" 18#include "luasocket.h"
19
20#include "io.h" 19#include "io.h"
21#include "timeout.h" 20#include "timeout.h"
22 21
@@ -34,12 +33,20 @@ typedef struct t_buffer_ {
34} t_buffer; 33} t_buffer;
35typedef t_buffer *p_buffer; 34typedef t_buffer *p_buffer;
36 35
36#ifndef _WIN32
37#pragma GCC visibility push(hidden)
38#endif
39
37int buffer_open(lua_State *L); 40int buffer_open(lua_State *L);
38void buffer_init(p_buffer buf, p_io io, p_timeout tm); 41void buffer_init(p_buffer buf, p_io io, p_timeout tm);
39int buffer_meth_send(lua_State *L, p_buffer buf);
40int buffer_meth_receive(lua_State *L, p_buffer buf);
41int buffer_meth_getstats(lua_State *L, p_buffer buf); 42int buffer_meth_getstats(lua_State *L, p_buffer buf);
42int buffer_meth_setstats(lua_State *L, p_buffer buf); 43int buffer_meth_setstats(lua_State *L, p_buffer buf);
44int buffer_meth_send(lua_State *L, p_buffer buf);
45int buffer_meth_receive(lua_State *L, p_buffer buf);
43int buffer_isempty(p_buffer buf); 46int buffer_isempty(p_buffer buf);
44 47
48#ifndef _WIN32
49#pragma GCC visibility pop
50#endif
51
45#endif /* BUF_H */ 52#endif /* BUF_H */
diff --git a/src/compat.c b/src/compat.c
index c2d99cb..34ffdaf 100644
--- a/src/compat.c
+++ b/src/compat.c
@@ -1,10 +1,12 @@
1#include "luasocket.h"
1#include "compat.h" 2#include "compat.h"
2 3
3#if LUA_VERSION_NUM==501 4#if LUA_VERSION_NUM==501
5
4/* 6/*
5** Adapted from Lua 5.2 7** Adapted from Lua 5.2
6*/ 8*/
7void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { 9void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
8 luaL_checkstack(L, nup+1, "too many upvalues"); 10 luaL_checkstack(L, nup+1, "too many upvalues");
9 for (; l->name != NULL; l++) { /* fill the table with given functions */ 11 for (; l->name != NULL; l++) { /* fill the table with given functions */
10 int i; 12 int i;
@@ -16,4 +18,22 @@ void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
16 } 18 }
17 lua_pop(L, nup); /* remove upvalues */ 19 lua_pop(L, nup); /* remove upvalues */
18} 20}
21
22/*
23** Duplicated from Lua 5.2
24*/
25void *luasocket_testudata (lua_State *L, int ud, const char *tname) {
26 void *p = lua_touserdata(L, ud);
27 if (p != NULL) { /* value is a userdata? */
28 if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
29 luaL_getmetatable(L, tname); /* get correct metatable */
30 if (!lua_rawequal(L, -1, -2)) /* not the same? */
31 p = NULL; /* value is a userdata with wrong metatable */
32 lua_pop(L, 2); /* remove both metatables */
33 return p;
34 }
35 }
36 return NULL; /* value is not a userdata with a metatable */
37}
38
19#endif 39#endif
diff --git a/src/compat.h b/src/compat.h
index 7bf8010..fa2d7d7 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -1,11 +1,22 @@
1#ifndef COMPAT_H 1#ifndef COMPAT_H
2#define COMPAT_H 2#define COMPAT_H
3 3
4#include "lua.h"
5#include "lauxlib.h"
6
7#if LUA_VERSION_NUM==501 4#if LUA_VERSION_NUM==501
8void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); 5
6#ifndef _WIN32
7#pragma GCC visibility push(hidden)
8#endif
9
10void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
11void *luasocket_testudata ( lua_State *L, int arg, const char *tname);
12
13#ifndef _WIN32
14#pragma GCC visibility pop
15#endif
16
17#define luaL_setfuncs luasocket_setfuncs
18#define luaL_testudata luasocket_testudata
19
9#endif 20#endif
10 21
11#endif 22#endif
diff --git a/src/except.c b/src/except.c
index 261ac98..9c3317f 100644
--- a/src/except.c
+++ b/src/except.c
@@ -2,17 +2,13 @@
2* Simple exception support 2* Simple exception support
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <stdio.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "except.h" 6#include "except.h"
7#include <stdio.h>
12 8
13#if LUA_VERSION_NUM < 502 9#if LUA_VERSION_NUM < 502
14#define lua_pcallk(L, na, nr, err, ctx, cont) \ 10#define lua_pcallk(L, na, nr, err, ctx, cont) \
15 ((void)ctx,(void)cont,lua_pcall(L, na, nr, err)) 11 (((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
16#endif 12#endif
17 13
18#if LUA_VERSION_NUM < 503 14#if LUA_VERSION_NUM < 503
@@ -39,18 +35,17 @@ static luaL_Reg func[] = {
39* Try factory 35* Try factory
40\*-------------------------------------------------------------------------*/ 36\*-------------------------------------------------------------------------*/
41static void wrap(lua_State *L) { 37static void wrap(lua_State *L) {
42 lua_newtable(L); 38 lua_createtable(L, 1, 0);
43 lua_pushnumber(L, 1); 39 lua_pushvalue(L, -2);
44 lua_pushvalue(L, -3); 40 lua_rawseti(L, -2, 1);
45 lua_settable(L, -3); 41 lua_pushvalue(L, lua_upvalueindex(1));
46 lua_insert(L, -2); 42 lua_setmetatable(L, -2);
47 lua_pop(L, 1);
48} 43}
49 44
50static int finalize(lua_State *L) { 45static int finalize(lua_State *L) {
51 if (!lua_toboolean(L, 1)) { 46 if (!lua_toboolean(L, 1)) {
52 lua_pushvalue(L, lua_upvalueindex(1)); 47 lua_pushvalue(L, lua_upvalueindex(2));
53 lua_pcall(L, 0, 0, 0); 48 lua_call(L, 0, 0);
54 lua_settop(L, 2); 49 lua_settop(L, 2);
55 wrap(L); 50 wrap(L);
56 lua_error(L); 51 lua_error(L);
@@ -58,15 +53,17 @@ static int finalize(lua_State *L) {
58 } else return lua_gettop(L); 53 } else return lua_gettop(L);
59} 54}
60 55
61static int do_nothing(lua_State *L) { 56static int do_nothing(lua_State *L) {
62 (void) L; 57 (void) L;
63 return 0; 58 return 0;
64} 59}
65 60
66static int global_newtry(lua_State *L) { 61static int global_newtry(lua_State *L) {
67 lua_settop(L, 1); 62 lua_settop(L, 1);
68 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); 63 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
69 lua_pushcclosure(L, finalize, 1); 64 lua_pushvalue(L, lua_upvalueindex(1));
65 lua_insert(L, -2);
66 lua_pushcclosure(L, finalize, 2);
70 return 1; 67 return 1;
71} 68}
72 69
@@ -74,13 +71,16 @@ static int global_newtry(lua_State *L) {
74* Protect factory 71* Protect factory
75\*-------------------------------------------------------------------------*/ 72\*-------------------------------------------------------------------------*/
76static int unwrap(lua_State *L) { 73static int unwrap(lua_State *L) {
77 if (lua_istable(L, -1)) { 74 if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
78 lua_pushnumber(L, 1); 75 int r = lua_rawequal(L, -1, lua_upvalueindex(1));
79 lua_gettable(L, -2); 76 lua_pop(L, 1);
80 lua_pushnil(L); 77 if (r) {
81 lua_insert(L, -2); 78 lua_pushnil(L);
82 return 1; 79 lua_rawgeti(L, -2, 1);
83 } else return 0; 80 return 1;
81 }
82 }
83 return 0;
84} 84}
85 85
86static int protected_finish(lua_State *L, int status, lua_KContext ctx) { 86static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
@@ -103,14 +103,17 @@ static int protected_cont(lua_State *L) {
103 103
104static int protected_(lua_State *L) { 104static int protected_(lua_State *L) {
105 int status; 105 int status;
106 lua_pushvalue(L, lua_upvalueindex(1)); 106 lua_pushvalue(L, lua_upvalueindex(2));
107 lua_insert(L, 1); 107 lua_insert(L, 1);
108 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); 108 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
109 return protected_finish(L, status, 0); 109 return protected_finish(L, status, 0);
110} 110}
111 111
112static int global_protect(lua_State *L) { 112static int global_protect(lua_State *L) {
113 lua_pushcclosure(L, protected_, 1); 113 lua_settop(L, 1);
114 lua_pushvalue(L, lua_upvalueindex(1));
115 lua_insert(L, 1);
116 lua_pushcclosure(L, protected_, 2);
114 return 1; 117 return 1;
115} 118}
116 119
@@ -118,6 +121,9 @@ static int global_protect(lua_State *L) {
118* Init module 121* Init module
119\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
120int except_open(lua_State *L) { 123int except_open(lua_State *L) {
121 luaL_setfuncs(L, func, 0); 124 lua_newtable(L); /* metatable for wrapped exceptions */
125 lua_pushboolean(L, 0);
126 lua_setfield(L, -2, "__metatable");
127 luaL_setfuncs(L, func, 1);
122 return 0; 128 return 0;
123} 129}
diff --git a/src/except.h b/src/except.h
index 1e7a245..71c31fd 100644
--- a/src/except.h
+++ b/src/except.h
@@ -9,25 +9,38 @@
9* error checking was taking a substantial amount of the coding. These 9* error checking was taking a substantial amount of the coding. These
10* function greatly simplify the task of checking errors. 10* function greatly simplify the task of checking errors.
11* 11*
12* The main idea is that functions should return nil as its first return 12* The main idea is that functions should return nil as their first return
13* value when it finds an error, and return an error message (or value) 13* values when they find 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, 14* following nil. In case of success, as long as the first value is not nil,
15* the other values don't matter. 15* the other values don't matter.
16* 16*
17* The idea is to nest function calls with the "try" function. This function 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 18* checks the first value, and, if it's falsy, wraps the second value in a
19* nil. Otherwise, it returns all values it received. 19* table with metatable and calls "error" on it. Otherwise, it returns all
20* values it received. Basically, it works like the Lua "assert" function,
21* but it creates errors targeted specifically at "protect".
20* 22*
21* The protect function returns a new function that behaves exactly like the 23* The "newtry" function is a factory for "try" functions that call a
22* function it receives, but the new function doesn't throw exceptions: it 24* finalizer in protected mode before calling "error".
23* returns nil followed by the error message instead.
24* 25*
25* With these two function, it's easy to write functions that throw 26* The "protect" function returns a new function that behaves exactly like
26* exceptions on error, but that don't interrupt the user script. 27* the function it receives, but the new function catches exceptions thrown
28* by "try" functions and returns nil followed by the error message instead.
29*
30* With these three functions, it's easy to write functions that throw
31* exceptions on error, but that don't interrupt the user script.
27\*=========================================================================*/ 32\*=========================================================================*/
28 33
29#include "lua.h" 34#include "luasocket.h"
35
36#ifndef _WIN32
37#pragma GCC visibility push(hidden)
38#endif
30 39
31int except_open(lua_State *L); 40int except_open(lua_State *L);
32 41
42#ifndef _WIN32
43#pragma GCC visibility pop
44#endif
45
33#endif 46#endif
diff --git a/src/ftp.lua b/src/ftp.lua
index 917cd89..0ebc508 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -23,7 +23,7 @@ local _M = socket.ftp
23-- timeout in seconds before the program gives up on a connection 23-- timeout in seconds before the program gives up on a connection
24_M.TIMEOUT = 60 24_M.TIMEOUT = 60
25-- default port for ftp service 25-- default port for ftp service
26_M.PORT = 21 26local PORT = 21
27-- this is the default anonymous password. used when no password is 27-- this is the default anonymous password. used when no password is
28-- provided in url. should be changed to your e-mail. 28-- provided in url. should be changed to your e-mail.
29_M.USER = "ftp" 29_M.USER = "ftp"
@@ -35,7 +35,7 @@ _M.PASSWORD = "anonymous@anonymous.org"
35local metat = { __index = {} } 35local metat = { __index = {} }
36 36
37function _M.open(server, port, create) 37function _M.open(server, port, create)
38 local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create)) 38 local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
39 local f = base.setmetatable({ tp = tp }, metat) 39 local f = base.setmetatable({ tp = tp }, metat)
40 -- make sure everything gets closed in an exception 40 -- make sure everything gets closed in an exception
41 f.try = socket.newtry(function() f:close() end) 41 f.try = socket.newtry(function() f:close() end)
@@ -51,12 +51,12 @@ end
51function metat.__index:pasvconnect() 51function metat.__index:pasvconnect()
52 self.data = self.try(socket.tcp()) 52 self.data = self.try(socket.tcp())
53 self.try(self.data:settimeout(_M.TIMEOUT)) 53 self.try(self.data:settimeout(_M.TIMEOUT))
54 self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) 54 self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
55end 55end
56 56
57function metat.__index:login(user, password) 57function metat.__index:login(user, password)
58 self.try(self.tp:command("user", user or _M.USER)) 58 self.try(self.tp:command("user", user or _M.USER))
59 local code, reply = self.try(self.tp:check{"2..", 331}) 59 local code, _ = self.try(self.tp:check{"2..", 331})
60 if code == 331 then 60 if code == 331 then
61 self.try(self.tp:command("pass", password or _M.PASSWORD)) 61 self.try(self.tp:command("pass", password or _M.PASSWORD))
62 self.try(self.tp:check("2..")) 62 self.try(self.tp:check("2.."))
@@ -66,37 +66,70 @@ end
66 66
67function metat.__index:pasv() 67function metat.__index:pasv()
68 self.try(self.tp:command("pasv")) 68 self.try(self.tp:command("pasv"))
69 local code, reply = self.try(self.tp:check("2..")) 69 local _, reply = self.try(self.tp:check("2.."))
70 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" 70 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
71 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) 71 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
72 self.try(a and b and c and d and p1 and p2, reply) 72 self.try(a and b and c and d and p1 and p2, reply)
73 self.pasvt = { 73 self.pasvt = {
74 ip = string.format("%d.%d.%d.%d", a, b, c, d), 74 address = string.format("%d.%d.%d.%d", a, b, c, d),
75 port = p1*256 + p2 75 port = p1*256 + p2
76 } 76 }
77 if self.server then 77 if self.server then
78 self.server:close() 78 self.server:close()
79 self.server = nil 79 self.server = nil
80 end 80 end
81 return self.pasvt.ip, self.pasvt.port 81 return self.pasvt.address, self.pasvt.port
82end 82end
83 83
84function metat.__index:port(ip, port) 84function metat.__index:epsv()
85 self.try(self.tp:command("epsv"))
86 local _, reply = self.try(self.tp:check("229"))
87 local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
88 local _, _, _, port = string.match(reply, pattern)
89 self.try(port, "invalid epsv response")
90 self.pasvt = {
91 address = self.tp:getpeername(),
92 port = port
93 }
94 if self.server then
95 self.server:close()
96 self.server = nil
97 end
98 return self.pasvt.address, self.pasvt.port
99end
100
101
102function metat.__index:port(address, port)
85 self.pasvt = nil 103 self.pasvt = nil
86 if not ip then 104 if not address then
87 ip, port = self.try(self.tp:getcontrol():getsockname()) 105 address = self.try(self.tp:getsockname())
88 self.server = self.try(socket.bind(ip, 0)) 106 self.server = self.try(socket.bind(address, 0))
89 ip, port = self.try(self.server:getsockname()) 107 address, port = self.try(self.server:getsockname())
90 self.try(self.server:settimeout(_M.TIMEOUT)) 108 self.try(self.server:settimeout(_M.TIMEOUT))
91 end 109 end
92 local pl = math.mod(port, 256) 110 local pl = math.mod(port, 256)
93 local ph = (port - pl)/256 111 local ph = (port - pl)/256
94 local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") 112 local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",")
95 self.try(self.tp:command("port", arg)) 113 self.try(self.tp:command("port", arg))
96 self.try(self.tp:check("2..")) 114 self.try(self.tp:check("2.."))
97 return 1 115 return 1
98end 116end
99 117
118function metat.__index:eprt(family, address, port)
119 self.pasvt = nil
120 if not address then
121 address = self.try(self.tp:getsockname())
122 self.server = self.try(socket.bind(address, 0))
123 address, port = self.try(self.server:getsockname())
124 self.try(self.server:settimeout(_M.TIMEOUT))
125 end
126 local arg = string.format("|%s|%s|%d|", family, address, port)
127 self.try(self.tp:command("eprt", arg))
128 self.try(self.tp:check("2.."))
129 return 1
130end
131
132
100function metat.__index:send(sendt) 133function metat.__index:send(sendt)
101 self.try(self.pasvt or self.server, "need port or pasv first") 134 self.try(self.pasvt or self.server, "need port or pasv first")
102 -- if there is a pasvt table, we already sent a PASV command 135 -- if there is a pasvt table, we already sent a PASV command
@@ -109,13 +142,13 @@ function metat.__index:send(sendt)
109 local command = sendt.command or "stor" 142 local command = sendt.command or "stor"
110 -- send the transfer command and check the reply 143 -- send the transfer command and check the reply
111 self.try(self.tp:command(command, argument)) 144 self.try(self.tp:command(command, argument))
112 local code, reply = self.try(self.tp:check{"2..", "1.."}) 145 local code, _ = self.try(self.tp:check{"2..", "1.."})
113 -- if there is not a a pasvt table, then there is a server 146 -- if there is not a pasvt table, then there is a server
114 -- and we already sent a PORT command 147 -- and we already sent a PORT command
115 if not self.pasvt then self:portconnect() end 148 if not self.pasvt then self:portconnect() end
116 -- get the sink, source and step for the transfer 149 -- get the sink, source and step for the transfer
117 local step = sendt.step or ltn12.pump.step 150 local step = sendt.step or ltn12.pump.step
118 local readt = {self.tp.c} 151 local readt = { self.tp }
119 local checkstep = function(src, snk) 152 local checkstep = function(src, snk)
120 -- check status in control connection while downloading 153 -- check status in control connection while downloading
121 local readyt = socket.select(readt, nil, 0) 154 local readyt = socket.select(readt, nil, 0)
@@ -207,7 +240,7 @@ local function tput(putt)
207 f:greet() 240 f:greet()
208 f:login(putt.user, putt.password) 241 f:login(putt.user, putt.password)
209 if putt.type then f:type(putt.type) end 242 if putt.type then f:type(putt.type) end
210 f:pasv() 243 f:epsv()
211 local sent = f:send(putt) 244 local sent = f:send(putt)
212 f:quit() 245 f:quit()
213 f:close() 246 f:close()
@@ -219,7 +252,7 @@ local default = {
219 scheme = "ftp" 252 scheme = "ftp"
220} 253}
221 254
222local function parse(u) 255local function genericform(u)
223 local t = socket.try(url.parse(u, default)) 256 local t = socket.try(url.parse(u, default))
224 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") 257 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
225 socket.try(t.host, "missing hostname") 258 socket.try(t.host, "missing hostname")
@@ -232,8 +265,10 @@ local function parse(u)
232 return t 265 return t
233end 266end
234 267
268_M.genericform = genericform
269
235local function sput(u, body) 270local function sput(u, body)
236 local putt = parse(u) 271 local putt = genericform(u)
237 putt.source = ltn12.source.string(body) 272 putt.source = ltn12.source.string(body)
238 return tput(putt) 273 return tput(putt)
239end 274end
@@ -250,14 +285,14 @@ local function tget(gett)
250 f:greet() 285 f:greet()
251 f:login(gett.user, gett.password) 286 f:login(gett.user, gett.password)
252 if gett.type then f:type(gett.type) end 287 if gett.type then f:type(gett.type) end
253 f:pasv() 288 f:epsv()
254 f:receive(gett) 289 f:receive(gett)
255 f:quit() 290 f:quit()
256 return f:close() 291 return f:close()
257end 292end
258 293
259local function sget(u) 294local function sget(u)
260 local gett = parse(u) 295 local gett = genericform(u)
261 local t = {} 296 local t = {}
262 gett.sink = ltn12.sink.table(t) 297 gett.sink = ltn12.sink.table(t)
263 tget(gett) 298 tget(gett)
@@ -271,8 +306,17 @@ _M.command = socket.protect(function(cmdt)
271 local f = _M.open(cmdt.host, cmdt.port, cmdt.create) 306 local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
272 f:greet() 307 f:greet()
273 f:login(cmdt.user, cmdt.password) 308 f:login(cmdt.user, cmdt.password)
274 f.try(f.tp:command(cmdt.command, cmdt.argument)) 309 if type(cmdt.command) == "table" then
275 if cmdt.check then f.try(f.tp:check(cmdt.check)) end 310 local argument = cmdt.argument or {}
311 local check = cmdt.check or {}
312 for i,cmd in ipairs(cmdt.command) do
313 f.try(f.tp:command(cmd, argument[i]))
314 if check[i] then f.try(f.tp:check(check[i])) end
315 end
316 else
317 f.try(f.tp:command(cmdt.command, cmdt.argument))
318 if cmdt.check then f.try(f.tp:check(cmdt.check)) end
319 end
276 f:quit() 320 f:quit()
277 return f:close() 321 return f:close()
278end) 322end)
@@ -282,4 +326,4 @@ _M.get = socket.protect(function(gett)
282 else return tget(gett) end 326 else return tget(gett) end
283end) 327end)
284 328
285return _M \ No newline at end of file 329return _M
diff --git a/src/http.lua b/src/http.lua
index 45ffa15..fbd5ff6 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -23,11 +23,24 @@ local _M = socket.http
23----------------------------------------------------------------------------- 23-----------------------------------------------------------------------------
24-- connection timeout in seconds 24-- connection timeout in seconds
25_M.TIMEOUT = 60 25_M.TIMEOUT = 60
26-- default port for document retrieval
27_M.PORT = 80
28-- user agent field sent in request 26-- user agent field sent in request
29_M.USERAGENT = socket._VERSION 27_M.USERAGENT = socket._VERSION
30 28
29-- supported schemes and their particulars
30local SCHEMES = {
31 http = {
32 port = 80
33 , create = function(t)
34 return socket.tcp end }
35 , https = {
36 port = 443
37 , create = function(t)
38 local https = assert(
39 require("ssl.https"), 'LuaSocket: LuaSec not found')
40 local tcp = assert(
41 https.tcp, 'LuaSocket: Function tcp() not available from LuaSec')
42 return tcp(t) end }}
43
31----------------------------------------------------------------------------- 44-----------------------------------------------------------------------------
32-- Reads MIME headers from a connection, unfolding where needed 45-- Reads MIME headers from a connection, unfolding where needed
33----------------------------------------------------------------------------- 46-----------------------------------------------------------------------------
@@ -76,7 +89,7 @@ socket.sourcet["http-chunked"] = function(sock, headers)
76 -- was it the last chunk? 89 -- was it the last chunk?
77 if size > 0 then 90 if size > 0 then
78 -- if not, get chunk and skip terminating CRLF 91 -- if not, get chunk and skip terminating CRLF
79 local chunk, err, part = sock:receive(size) 92 local chunk, err, _ = sock:receive(size)
80 if chunk then sock:receive() end 93 if chunk then sock:receive() end
81 return chunk, err 94 return chunk, err
82 else 95 else
@@ -108,13 +121,13 @@ local metat = { __index = {} }
108 121
109function _M.open(host, port, create) 122function _M.open(host, port, create)
110 -- create socket with user connect function, or with default 123 -- create socket with user connect function, or with default
111 local c = socket.try((create or socket.tcp)()) 124 local c = socket.try(create())
112 local h = base.setmetatable({ c = c }, metat) 125 local h = base.setmetatable({ c = c }, metat)
113 -- create finalized try 126 -- create finalized try
114 h.try = socket.newtry(function() h:close() end) 127 h.try = socket.newtry(function() h:close() end)
115 -- set timeout before connecting 128 -- set timeout before connecting
116 h.try(c:settimeout(_M.TIMEOUT)) 129 h.try(c:settimeout(_M.TIMEOUT))
117 h.try(c:connect(host, port or _M.PORT)) 130 h.try(c:connect(host, port))
118 -- here everything worked 131 -- here everything worked
119 return h 132 return h
120end 133end
@@ -144,10 +157,15 @@ function metat.__index:sendbody(headers, source, step)
144end 157end
145 158
146function metat.__index:receivestatusline() 159function metat.__index:receivestatusline()
147 local status = self.try(self.c:receive(5)) 160 local status,ec = self.try(self.c:receive(5))
148 -- identify HTTP/0.9 responses, which do not contain a status line 161 -- identify HTTP/0.9 responses, which do not contain a status line
149 -- this is just a heuristic, but is what the RFC recommends 162 -- this is just a heuristic, but is what the RFC recommends
150 if status ~= "HTTP/" then return nil, status end 163 if status ~= "HTTP/" then
164 if ec == "timeout" then
165 return 408
166 end
167 return nil, status
168 end
151 -- otherwise proceed reading a status line 169 -- otherwise proceed reading a status line
152 status = self.try(self.c:receive("*l", status)) 170 status = self.try(self.c:receive("*l", status))
153 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) 171 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
@@ -209,7 +227,10 @@ end
209 227
210local function adjustheaders(reqt) 228local function adjustheaders(reqt)
211 -- default headers 229 -- default headers
212 local host = string.gsub(reqt.authority, "^.-@", "") 230 local host = reqt.host
231 local port = tostring(reqt.port)
232 if port ~= tostring(SCHEMES[reqt.scheme].port) then
233 host = host .. ':' .. port end
213 local lower = { 234 local lower = {
214 ["user-agent"] = _M.USERAGENT, 235 ["user-agent"] = _M.USERAGENT,
215 ["host"] = host, 236 ["host"] = host,
@@ -218,15 +239,16 @@ local function adjustheaders(reqt)
218 } 239 }
219 -- if we have authentication information, pass it along 240 -- if we have authentication information, pass it along
220 if reqt.user and reqt.password then 241 if reqt.user and reqt.password then
221 lower["authorization"] = 242 lower["authorization"] =
222 "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) 243 "Basic " .. (mime.b64(reqt.user .. ":" ..
244 url.unescape(reqt.password)))
223 end 245 end
224 -- if we have proxy authentication information, pass it along 246 -- if we have proxy authentication information, pass it along
225 local proxy = reqt.proxy or _M.PROXY 247 local proxy = reqt.proxy or _M.PROXY
226 if proxy then 248 if proxy then
227 proxy = url.parse(proxy) 249 proxy = url.parse(proxy)
228 if proxy.user and proxy.password then 250 if proxy.user and proxy.password then
229 lower["proxy-authorization"] = 251 lower["proxy-authorization"] =
230 "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password)) 252 "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password))
231 end 253 end
232 end 254 end
@@ -239,10 +261,8 @@ end
239 261
240-- default url parts 262-- default url parts
241local default = { 263local default = {
242 host = "", 264 path ="/"
243 port = _M.PORT, 265 , scheme = "http"
244 path ="/",
245 scheme = "http"
246} 266}
247 267
248local function adjustrequest(reqt) 268local function adjustrequest(reqt)
@@ -250,25 +270,48 @@ local function adjustrequest(reqt)
250 local nreqt = reqt.url and url.parse(reqt.url, default) or {} 270 local nreqt = reqt.url and url.parse(reqt.url, default) or {}
251 -- explicit components override url 271 -- explicit components override url
252 for i,v in base.pairs(reqt) do nreqt[i] = v end 272 for i,v in base.pairs(reqt) do nreqt[i] = v end
253 if nreqt.port == "" then nreqt.port = 80 end 273 -- default to scheme particulars
254 socket.try(nreqt.host and nreqt.host ~= "", 274 local schemedefs, host, port, method
255 "invalid host '" .. base.tostring(nreqt.host) .. "'") 275 = SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method
276 if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end
277 if not (port and port ~= '') then nreqt.port = schemedefs.port end
278 if not (method and method ~= '') then nreqt.method = 'GET' end
279 if not (host and host ~= "") then
280 socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
281 end
256 -- compute uri if user hasn't overriden 282 -- compute uri if user hasn't overriden
257 nreqt.uri = reqt.uri or adjusturi(nreqt) 283 nreqt.uri = reqt.uri or adjusturi(nreqt)
258 -- adjust headers in request 284 -- adjust headers in request
259 nreqt.headers = adjustheaders(nreqt) 285 nreqt.headers = adjustheaders(nreqt)
286 if nreqt.source
287 and not nreqt.headers["content-length"]
288 and not nreqt.headers["transfer-encoding"]
289 then
290 nreqt.headers["transfer-encoding"] = "chunked"
291 end
292
260 -- ajust host and port if there is a proxy 293 -- ajust host and port if there is a proxy
261 nreqt.host, nreqt.port = adjustproxy(nreqt) 294 nreqt.host, nreqt.port = adjustproxy(nreqt)
262 return nreqt 295 return nreqt
263end 296end
264 297
265local function shouldredirect(reqt, code, headers) 298local function shouldredirect(reqt, code, headers)
266 return headers.location and 299 local location = headers.location
267 string.gsub(headers.location, "%s", "") ~= "" and 300 if not location then return false end
268 (reqt.redirect ~= false) and 301 location = string.gsub(location, "%s", "")
302 if location == "" then return false end
303 -- the RFC says the redirect URL may be relative
304 location = url.absolute(reqt.url, location)
305 local scheme = url.parse(location).scheme
306 if scheme and (not SCHEMES[scheme]) then return false end
307 -- avoid https downgrades
308 if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end
309 return (reqt.redirect ~= false) and
269 (code == 301 or code == 302 or code == 303 or code == 307) and 310 (code == 301 or code == 302 or code == 303 or code == 307) and
270 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") 311 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
271 and (not reqt.nredirects or reqt.nredirects < 5) 312 and ((false == reqt.maxredirects)
313 or ((reqt.nredirects or 0)
314 < (reqt.maxredirects or 5)))
272end 315end
273 316
274local function shouldreceivebody(reqt, code) 317local function shouldreceivebody(reqt, code)
@@ -282,17 +325,23 @@ end
282local trequest, tredirect 325local trequest, tredirect
283 326
284--[[local]] function tredirect(reqt, location) 327--[[local]] function tredirect(reqt, location)
328 -- the RFC says the redirect URL may be relative
329 local newurl = url.absolute(reqt.url, location)
330 -- if switching schemes, reset port and create function
331 if url.parse(newurl).scheme ~= reqt.scheme then
332 reqt.port = nil
333 reqt.create = nil end
334 -- make new request
285 local result, code, headers, status = trequest { 335 local result, code, headers, status = trequest {
286 -- the RFC says the redirect URL has to be absolute, but some 336 url = newurl,
287 -- servers do not respect that
288 url = url.absolute(reqt.url, location),
289 source = reqt.source, 337 source = reqt.source,
290 sink = reqt.sink, 338 sink = reqt.sink,
291 headers = reqt.headers, 339 headers = reqt.headers,
292 proxy = reqt.proxy, 340 proxy = reqt.proxy,
341 maxredirects = reqt.maxredirects,
293 nredirects = (reqt.nredirects or 0) + 1, 342 nredirects = (reqt.nredirects or 0) + 1,
294 create = reqt.create 343 create = reqt.create
295 } 344 }
296 -- pass location header back as a hint we redirected 345 -- pass location header back as a hint we redirected
297 headers = headers or {} 346 headers = headers or {}
298 headers.location = headers.location or location 347 headers.location = headers.location or location
@@ -309,23 +358,25 @@ end
309 h:sendheaders(nreqt.headers) 358 h:sendheaders(nreqt.headers)
310 -- if there is a body, send it 359 -- if there is a body, send it
311 if nreqt.source then 360 if nreqt.source then
312 h:sendbody(nreqt.headers, nreqt.source, nreqt.step) 361 h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
313 end 362 end
314 local code, status = h:receivestatusline() 363 local code, status = h:receivestatusline()
315 -- if it is an HTTP/0.9 server, simply get the body and we are done 364 -- if it is an HTTP/0.9 server, simply get the body and we are done
316 if not code then 365 if not code then
317 h:receive09body(status, nreqt.sink, nreqt.step) 366 h:receive09body(status, nreqt.sink, nreqt.step)
318 return 1, 200 367 return 1, 200
368 elseif code == 408 then
369 return 1, code
319 end 370 end
320 local headers 371 local headers
321 -- ignore any 100-continue messages 372 -- ignore any 100-continue messages
322 while code == 100 do 373 while code == 100 do
323 headers = h:receiveheaders() 374 h:receiveheaders()
324 code, status = h:receivestatusline() 375 code, status = h:receivestatusline()
325 end 376 end
326 headers = h:receiveheaders() 377 headers = h:receiveheaders()
327 -- at this point we should have a honest reply from the server 378 -- at this point we should have a honest reply from the server
328 -- we can't redirect if we already used the source, so we report the error 379 -- we can't redirect if we already used the source, so we report the error
329 if shouldredirect(nreqt, code, headers) and not nreqt.source then 380 if shouldredirect(nreqt, code, headers) and not nreqt.source then
330 h:close() 381 h:close()
331 return tredirect(reqt, headers.location) 382 return tredirect(reqt, headers.location)
@@ -338,11 +389,13 @@ end
338 return 1, code, headers, status 389 return 1, code, headers, status
339end 390end
340 391
341local function srequest(u, b) 392-- turns an url and a body into a generic request
393local function genericform(u, b)
342 local t = {} 394 local t = {}
343 local reqt = { 395 local reqt = {
344 url = u, 396 url = u,
345 sink = ltn12.sink.table(t) 397 sink = ltn12.sink.table(t),
398 target = t
346 } 399 }
347 if b then 400 if b then
348 reqt.source = ltn12.source.string(b) 401 reqt.source = ltn12.source.string(b)
@@ -352,8 +405,15 @@ local function srequest(u, b)
352 } 405 }
353 reqt.method = "POST" 406 reqt.method = "POST"
354 end 407 end
355 local code, headers, status = socket.skip(1, trequest(reqt)) 408 return reqt
356 return table.concat(t), code, headers, status 409end
410
411_M.genericform = genericform
412
413local function srequest(u, b)
414 local reqt = genericform(u, b)
415 local _, code, headers, status = trequest(reqt)
416 return table.concat(reqt.target), code, headers, status
357end 417end
358 418
359_M.request = socket.protect(function(reqt, body) 419_M.request = socket.protect(function(reqt, body)
@@ -361,4 +421,5 @@ _M.request = socket.protect(function(reqt, body)
361 else return trequest(reqt) end 421 else return trequest(reqt) end
362end) 422end)
363 423
424_M.schemes = SCHEMES
364return _M 425return _M
diff --git a/src/inet.c b/src/inet.c
index 331b800..138c9ab 100644..100755
--- a/src/inet.c
+++ b/src/inet.c
@@ -2,16 +2,13 @@
2* Internet domain functions 2* Internet domain functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
6#include "inet.h"
7
5#include <stdio.h> 8#include <stdio.h>
6#include <stdlib.h> 9#include <stdlib.h>
7#include <string.h> 10#include <string.h>
8 11
9#include "lua.h"
10#include "lauxlib.h"
11#include "compat.h"
12
13#include "inet.h"
14
15/*=========================================================================*\ 12/*=========================================================================*\
16* Internal function prototypes. 13* Internal function prototypes.
17\*=========================================================================*/ 14\*=========================================================================*/
@@ -32,9 +29,6 @@ static luaL_Reg func[] = {
32 { NULL, NULL} 29 { NULL, NULL}
33}; 30};
34 31
35/*=========================================================================*\
36* Exported functions
37\*=========================================================================*/
38/*-------------------------------------------------------------------------*\ 32/*-------------------------------------------------------------------------*\
39* Initializes module 33* Initializes module
40\*-------------------------------------------------------------------------*/ 34\*-------------------------------------------------------------------------*/
@@ -259,7 +253,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
259 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); 253 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
260 if (err) { 254 if (err) {
261 lua_pushnil(L); 255 lua_pushnil(L);
262 lua_pushstring(L, gai_strerror(err)); 256 lua_pushstring(L, LUA_GAI_STRERROR(err));
263 return 2; 257 return 2;
264 } 258 }
265 lua_pushstring(L, name); 259 lua_pushstring(L, name);
@@ -292,7 +286,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
292 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); 286 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
293 if (err) { 287 if (err) {
294 lua_pushnil(L); 288 lua_pushnil(L);
295 lua_pushstring(L, gai_strerror(err)); 289 lua_pushstring(L, LUA_GAI_STRERROR(err));
296 return 2; 290 return 2;
297 } 291 }
298 lua_pushstring(L, name); 292 lua_pushstring(L, name);
@@ -423,8 +417,8 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
423 /* try connecting to remote address */ 417 /* try connecting to remote address */
424 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, 418 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
425 (socklen_t) iterator->ai_addrlen, tm)); 419 (socklen_t) iterator->ai_addrlen, tm));
426 /* if success, break out of loop */ 420 /* if success or timeout is zero, break out of loop */
427 if (err == NULL) { 421 if (err == NULL || timeout_iszero(tm)) {
428 *family = current_family; 422 *family = current_family;
429 break; 423 break;
430 } 424 }
diff --git a/src/inet.h b/src/inet.h
index feb3541..5618b61 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -14,7 +14,7 @@
14* 14*
15* The Lua functions toip and tohostname are also implemented here. 15* The Lua functions toip and tohostname are also implemented here.
16\*=========================================================================*/ 16\*=========================================================================*/
17#include "lua.h" 17#include "luasocket.h"
18#include "socket.h" 18#include "socket.h"
19#include "timeout.h" 19#include "timeout.h"
20 20
@@ -22,21 +22,23 @@
22#define LUASOCKET_INET_ATON 22#define LUASOCKET_INET_ATON
23#endif 23#endif
24 24
25#ifndef _WIN32
26#pragma GCC visibility push(hidden)
27#endif
28
25int inet_open(lua_State *L); 29int inet_open(lua_State *L);
26 30
27const char *inet_trycreate(p_socket ps, int family, int type, int protocol); 31int inet_optfamily(lua_State* L, int narg, const char* def);
28const char *inet_tryconnect(p_socket ps, int *family, const char *address, 32int inet_optsocktype(lua_State* L, int narg, const char* def);
29 const char *serv, p_timeout tm, struct addrinfo *connecthints);
30const char *inet_trybind(p_socket ps, int *family, const char *address,
31 const char *serv, struct addrinfo *bindhints);
32const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
33const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
34 33
35int inet_meth_getpeername(lua_State *L, p_socket ps, int family); 34int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
36int inet_meth_getsockname(lua_State *L, p_socket ps, int family); 35int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
37 36
38int inet_optfamily(lua_State* L, int narg, const char* def); 37const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
39int inet_optsocktype(lua_State* L, int narg, const char* def); 38const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
39const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints);
40const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
41const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints);
40 42
41#ifdef LUASOCKET_INET_ATON 43#ifdef LUASOCKET_INET_ATON
42int inet_aton(const char *cp, struct in_addr *inp); 44int inet_aton(const char *cp, struct in_addr *inp);
@@ -47,4 +49,8 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
47int inet_pton(int af, const char *src, void *dst); 49int inet_pton(int af, const char *src, void *dst);
48#endif 50#endif
49 51
52#ifndef _WIN32
53#pragma GCC visibility pop
54#endif
55
50#endif /* INET_H */ 56#endif /* INET_H */
diff --git a/src/io.c b/src/io.c
index a4230ce..5ad4b3a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -2,11 +2,9 @@
2* Input/Output abstraction 2* Input/Output abstraction
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include "luasocket.h"
5#include "io.h" 6#include "io.h"
6 7
7/*=========================================================================*\
8* Exported functions
9\*=========================================================================*/
10/*-------------------------------------------------------------------------*\ 8/*-------------------------------------------------------------------------*\
11* Initializes C structure 9* Initializes C structure
12\*-------------------------------------------------------------------------*/ 10\*-------------------------------------------------------------------------*/
diff --git a/src/io.h b/src/io.h
index 8cca08a..b8a54df 100644
--- a/src/io.h
+++ b/src/io.h
@@ -12,9 +12,7 @@
12* The module socket.h implements this interface, and thus the module tcp.h 12* The module socket.h implements this interface, and thus the module tcp.h
13* is very simple. 13* is very simple.
14\*=========================================================================*/ 14\*=========================================================================*/
15#include <stdio.h> 15#include "luasocket.h"
16#include "lua.h"
17
18#include "timeout.h" 16#include "timeout.h"
19 17
20/* IO error codes */ 18/* IO error codes */
@@ -58,8 +56,15 @@ typedef struct t_io_ {
58} t_io; 56} t_io;
59typedef t_io *p_io; 57typedef t_io *p_io;
60 58
59#ifndef _WIN32
60#pragma GCC visibility push(hidden)
61#endif
62
61void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); 63void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
62const char *io_strerror(int err); 64const char *io_strerror(int err);
63 65
64#endif /* IO_H */ 66#ifndef _WIN32
67#pragma GCC visibility pop
68#endif
65 69
70#endif /* IO_H */
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 1014de2..4cb17f5 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -9,10 +9,13 @@
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10local string = require("string") 10local string = require("string")
11local table = require("table") 11local table = require("table")
12local unpack = unpack or table.unpack
12local base = _G 13local base = _G
14local select = select
15
13local _M = {} 16local _M = {}
14if module then -- heuristic for exporting a global package table 17if module then -- heuristic for exporting a global package table
15 ltn12 = _M 18 ltn12 = _M -- luacheck: ignore
16end 19end
17local filter,source,sink,pump = {},{},{},{} 20local filter,source,sink,pump = {},{},{},{}
18 21
@@ -124,6 +127,16 @@ function source.string(s)
124 else return source.empty() end 127 else return source.empty() end
125end 128end
126 129
130-- creates table source
131function source.table(t)
132 base.assert('table' == type(t))
133 local i = 0
134 return function()
135 i = i + 1
136 return t[i]
137 end
138end
139
127-- creates rewindable source 140-- creates rewindable source
128function source.rewind(src) 141function source.rewind(src)
129 base.assert(src) 142 base.assert(src)
diff --git a/src/luasocket.c b/src/luasocket.c
index 7d9c802..0fd99f7 100644..100755
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -12,16 +12,6 @@
12* standard Lua read and write functions. 12* standard Lua read and write functions.
13\*=========================================================================*/ 13\*=========================================================================*/
14 14
15/*=========================================================================*\
16* Standard include files
17\*=========================================================================*/
18#include "lua.h"
19#include "lauxlib.h"
20#include "compat.h"
21
22/*=========================================================================*\
23* LuaSocket includes
24\*=========================================================================*/
25#include "luasocket.h" 15#include "luasocket.h"
26#include "auxiliar.h" 16#include "auxiliar.h"
27#include "except.h" 17#include "except.h"
@@ -64,7 +54,7 @@ static luaL_Reg func[] = {
64* Skip a few arguments 54* Skip a few arguments
65\*-------------------------------------------------------------------------*/ 55\*-------------------------------------------------------------------------*/
66static int global_skip(lua_State *L) { 56static int global_skip(lua_State *L) {
67 int amount = luaL_checkinteger(L, 1); 57 int amount = (int) luaL_checkinteger(L, 1);
68 int ret = lua_gettop(L) - amount - 1; 58 int ret = lua_gettop(L) - amount - 1;
69 return ret >= 0 ? ret : 0; 59 return ret >= 0 ? ret : 0;
70} 60}
diff --git a/src/luasocket.h b/src/luasocket.h
index f75d21f..1017fba 100644
--- a/src/luasocket.h
+++ b/src/luasocket.h
@@ -6,21 +6,28 @@
6* Diego Nehab 6* Diego Nehab
7* 9/11/1999 7* 9/11/1999
8\*=========================================================================*/ 8\*=========================================================================*/
9#include "lua.h"
10 9
11/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------* \
12* Current socket library version 11* Current socket library version
13\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
14#define LUASOCKET_VERSION "LuaSocket 3.0-rc1" 13#define LUASOCKET_VERSION "LuaSocket 3.0.0"
15#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" 14#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
16 15
17/*-------------------------------------------------------------------------*\ 16/*-------------------------------------------------------------------------*\
18* This macro prefixes all exported API functions 17* This macro prefixes all exported API functions
19\*-------------------------------------------------------------------------*/ 18\*-------------------------------------------------------------------------*/
20#ifndef LUASOCKET_API 19#ifndef LUASOCKET_API
21#define LUASOCKET_API extern 20#ifdef _WIN32
21#define LUASOCKET_API __declspec(dllexport)
22#else
23#define LUASOCKET_API __attribute__ ((visibility ("default")))
24#endif
22#endif 25#endif
23 26
27#include "lua.h"
28#include "lauxlib.h"
29#include "compat.h"
30
24/*-------------------------------------------------------------------------*\ 31/*-------------------------------------------------------------------------*\
25* Initializes the library. 32* Initializes the library.
26\*-------------------------------------------------------------------------*/ 33\*-------------------------------------------------------------------------*/
diff --git a/src/makefile b/src/makefile
index 2704a92..06f4d19 100644..100755
--- a/src/makefile
+++ b/src/makefile
@@ -12,34 +12,31 @@
12# 12#
13# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw 13# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
14 14
15# PLAT: linux macosx win32 mingw 15# PLAT: linux macosx win32 win64 mingw
16# platform to build for 16# platform to build for
17PLAT?=linux 17PLAT?=linux
18 18
19# LUAV: 5.1 5.2 19# LUAV: 5.1 5.2 5.3 5.4
20# lua version to build against 20# lua version to build against
21LUAV?=5.1 21LUAV?=5.1
22 22
23# MYCFLAGS: to be set by user if needed 23# MYCFLAGS: to be set by user if needed
24MYCFLAGS= 24MYCFLAGS?=
25 25
26# MYLDFLAGS: to be set by user if needed 26# MYLDFLAGS: to be set by user if needed
27MYLDFLAGS= 27MYLDFLAGS?=
28 28
29# DEBUG: NODEBUG DEBUG 29# DEBUG: NODEBUG DEBUG
30# debug mode causes luasocket to collect and returns timing information useful 30# debug mode causes luasocket to collect and returns timing information useful
31# for testing and debugging luasocket itself 31# for testing and debugging luasocket itself
32DEBUG?=NODEBUG 32DEBUG?=NODEBUG
33 33
34# COMPAT: COMPAT NOCOMPAT
35# when compiling for 5.2, use LUA_COMPAT_MODULE
36COMPAT?=NOCOMPAT
37
38# where lua headers are found for macosx builds 34# where lua headers are found for macosx builds
39# LUAINC_macosx: 35# LUAINC_macosx:
40# /opt/local/include 36# /opt/local/include
41LUAINC_macosx_base?=/opt/local/include 37LUAINC_macosx_base?=/opt/local/include
42LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) 38LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV) $(LUAINC_macosx_base)/lua$(LUAV) $(LUAINC_macosx_base)/lua-$(LUAV)
39
43# FIXME default should this default to fink or to macports? 40# FIXME default should this default to fink or to macports?
44# What happens when more than one Lua version is installed? 41# What happens when more than one Lua version is installed?
45LUAPREFIX_macosx?=/opt/local 42LUAPREFIX_macosx?=/opt/local
@@ -52,16 +49,16 @@ LDIR_macosx?=share/lua/$(LUAV)
52# /usr/local/include/lua$(LUAV) 49# /usr/local/include/lua$(LUAV)
53# where lua headers are found for linux builds 50# where lua headers are found for linux builds
54LUAINC_linux_base?=/usr/include 51LUAINC_linux_base?=/usr/include
55LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) 52LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV) $(LUAINC_linux_base)/lua$(LUAV)
56LUAPREFIX_linux?=/usr/local 53LUAPREFIX_linux?=/usr/local
57CDIR_linux?=lib/lua/$(LUAV) 54CDIR_linux?=lib/lua/$(LUAV)
58LDIR_linux?=share/lua/$(LUAV) 55LDIR_linux?=share/lua/$(LUAV)
59 56
60# LUAINC_freebsd: 57# LUAINC_freebsd:
61# /usr/local/include/lua$(LUAV) 58# /usr/local/include/lua$(LUAV)
62# where lua headers are found for linux builds 59# where lua headers are found for freebsd builds
63LUAINC_freebsd_base?=/usr/local/include/ 60LUAINC_freebsd_base?=/usr/local/include/
64LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua$(LUAV) 61LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua/$(LUAV) $(LUAINC_freebsd_base)/lua$(LUAV)
65LUAPREFIX_freebsd?=/usr/local/ 62LUAPREFIX_freebsd?=/usr/local/
66CDIR_freebsd?=lib/lua/$(LUAV) 63CDIR_freebsd?=lib/lua/$(LUAV)
67LDIR_freebsd?=share/lua/$(LUAV) 64LDIR_freebsd?=share/lua/$(LUAV)
@@ -70,7 +67,7 @@ LDIR_freebsd?=share/lua/$(LUAV)
70# LUAINC_mingw: 67# LUAINC_mingw:
71# /opt/local/include 68# /opt/local/include
72LUAINC_mingw_base?=/usr/include 69LUAINC_mingw_base?=/usr/include
73LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) 70LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV) $(LUAINC_mingw_base)/lua$(LUAV)
74LUALIB_mingw_base?=/usr/bin 71LUALIB_mingw_base?=/usr/bin
75LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll 72LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll
76LUAPREFIX_mingw?=/usr 73LUAPREFIX_mingw?=/usr
@@ -81,13 +78,32 @@ LDIR_mingw?=lua/$(LUAV)/lua
81# LUAINC_win32: 78# LUAINC_win32:
82# LUALIB_win32: 79# LUALIB_win32:
83# where lua headers and libraries are found for win32 builds 80# where lua headers and libraries are found for win32 builds
84LUAINC_win32_base?=
85LUAINC_win32?=$(LUAINC_win32_base)/lua/$(LUAV)
86PLATFORM_win32?=Release
87LUAPREFIX_win32?= 81LUAPREFIX_win32?=
88CDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32) 82LUAINC_win32?=$(LUAPREFIX_win32)/include/lua/$(LUAV) $(LUAPREFIX_win32)/include/lua$(LUAV)
89LDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)/lua 83PLATFORM_win32?=Release
90LUALIB_win32?=$(LUAPREFIX_win32)/lua/$(LUAV)/$(PLATFORM_win32) 84CDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)
85LDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)/lua
86LUALIB_win32?=$(LUAPREFIX_win32)/lib/lua/$(LUAV)/$(PLATFORM_win32)
87LUALIBNAME_win32?=lua$(subst .,,$(LUAV)).lib
88
89# LUAINC_win64:
90# LUALIB_win64:
91# where lua headers and libraries are found for win64 builds
92LUAPREFIX_win64?=
93LUAINC_win64?=$(LUAPREFIX_win64)/include/lua/$(LUAV) $(LUAPREFIX_win64)/include/lua$(LUAV)
94PLATFORM_win64?=x64/Release
95CDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)
96LDIR_win64?=bin/lua/$(LUAV)/$(PLATFORM_win64)/lua
97LUALIB_win64?=$(LUAPREFIX_win64)/lib/lua/$(LUAV)/$(PLATFORM_win64)
98LUALIBNAME_win64?=lua$(subst .,,$(LUAV)).lib
99
100
101# LUAINC_solaris:
102LUAINC_solaris_base?=/usr/include
103LUAINC_solaris?=$(LUAINC_solaris_base)/lua/$(LUAV) $(LUAINC_solaris_base)/lua$(LUAV)
104LUAPREFIX_solaris?=/usr/local
105CDIR_solaris?=lib/lua/$(LUAV)
106LDIR_solaris?=share/lua/$(LUAV)
91 107
92# prefix: /usr/local /usr /opt/local /sw 108# prefix: /usr/local /usr /opt/local /sw
93# the top of the default install tree 109# the top of the default install tree
@@ -98,7 +114,7 @@ LDIR?=$(LDIR_$(PLAT))
98 114
99# DESTDIR: (no default) 115# DESTDIR: (no default)
100# used by package managers to install into a temporary destination 116# used by package managers to install into a temporary destination
101DESTDIR= 117DESTDIR?=
102 118
103#------ 119#------
104# Definitions below can be overridden on the make command line, but 120# Definitions below can be overridden on the make command line, but
@@ -131,11 +147,13 @@ print:
131 @echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT)) 147 @echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT))
132 @echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR) 148 @echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR)
133 @echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR) 149 @echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR)
150 @echo CFLAGS=$(CFLAGS)
151 @echo LDFLAGS=$(LDFLAGS)
134 152
135#------ 153#------
136# Supported platforms 154# Supported platforms
137# 155#
138PLATS= macosx linux win32 mingw 156PLATS= macosx linux win32 win64 mingw solaris
139 157
140#------ 158#------
141# Compiler and linker settings 159# Compiler and linker settings
@@ -143,14 +161,10 @@ PLATS= macosx linux win32 mingw
143SO_macosx=so 161SO_macosx=so
144O_macosx=o 162O_macosx=o
145CC_macosx=gcc 163CC_macosx=gcc
146DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN -DLUA_$(COMPAT)_MODULE \ 164DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
147 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 165CFLAGS_macosx=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
148 -DUNIX_API='__attribute__((visibility("default")))' \ 166LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
149 -DMIME_API='__attribute__((visibility("default")))' 167LD_macosx=gcc
150CFLAGS_macosx= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \
151 -fvisibility=hidden
152LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
153LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
154SOCKET_macosx=usocket.o 168SOCKET_macosx=usocket.o
155 169
156#------ 170#------
@@ -159,13 +173,10 @@ SOCKET_macosx=usocket.o
159SO_linux=so 173SO_linux=so
160O_linux=o 174O_linux=o
161CC_linux=gcc 175CC_linux=gcc
162DEF_linux=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 176DEF_linux=-DLUASOCKET_$(DEBUG)
163 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 177CFLAGS_linux=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
164 -DUNIX_API='__attribute__((visibility("default")))' \ 178 -Wimplicit -O2 -ggdb3 -fpic
165 -DMIME_API='__attribute__((visibility("default")))' 179LDFLAGS_linux=-O -shared -fpic -o
166CFLAGS_linux= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
167 -Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
168LDFLAGS_linux=-O -shared -fpic -o
169LD_linux=gcc 180LD_linux=gcc
170SOCKET_linux=usocket.o 181SOCKET_linux=usocket.o
171 182
@@ -175,28 +186,36 @@ SOCKET_linux=usocket.o
175SO_freebsd=so 186SO_freebsd=so
176O_freebsd=o 187O_freebsd=o
177CC_freebsd=gcc 188CC_freebsd=gcc
178DEF_freebsd=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 189DEF_freebsd=-DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN
179 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 190CFLAGS_freebsd=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
180 -DUNIX_API='__attribute__((visibility("default")))' \ 191 -Wimplicit -O2 -ggdb3 -fpic
181 -DMIME_API='__attribute__((visibility("default")))' 192LDFLAGS_freebsd=-O -shared -fpic -o
182CFLAGS_freebsd= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
183 -Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
184LDFLAGS_freebsd=-O -shared -fpic -o
185LD_freebsd=gcc 193LD_freebsd=gcc
186SOCKET_freebsd=usocket.o 194SOCKET_freebsd=usocket.o
187 195
188#------ 196#------
189# Compiler and linker settings 197# Compiler and linker settings
198# for Solaris
199SO_solaris=so
200O_solaris=o
201CC_solaris=gcc
202DEF_solaris=-DLUASOCKET_$(DEBUG)
203CFLAGS_solaris=$(LUAINC:%=-I%) $(DEF) -Wall -Wshadow -Wextra \
204 -Wimplicit -O2 -ggdb3 -fpic
205LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o
206LD_solaris=gcc
207SOCKET_solaris=usocket.o
208
209#------
210# Compiler and linker settings
190# for MingW 211# for MingW
191SO_mingw=dll 212SO_mingw=dll
192O_mingw=o 213O_mingw=o
193CC_mingw=gcc 214CC_mingw=gcc
194DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \ 215DEF_mingw= -DLUASOCKET_$(DEBUG) \
195 -DWINVER=0x0501 -DLUASOCKET_API='__declspec(dllexport)' \ 216 -DWINVER=0x0501
196 -DMIME_API='__declspec(dllexport)' 217CFLAGS_mingw=$(LUAINC:%=-I%) $(DEF) -Wall -O2 -fno-common
197CFLAGS_mingw= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \ 218LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
198 -fvisibility=hidden
199LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
200LD_mingw=gcc 219LD_mingw=gcc
201SOCKET_mingw=wsocket.o 220SOCKET_mingw=wsocket.o
202 221
@@ -208,34 +227,55 @@ SO_win32=dll
208O_win32=obj 227O_win32=obj
209CC_win32=cl 228CC_win32=cl
210DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \ 229DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
211 //D "LUASOCKET_API=__declspec(dllexport)" //D "_CRT_SECURE_NO_WARNINGS" \ 230 //D "_CRT_SECURE_NO_WARNINGS" \
212 //D "_WINDLL" //D "LUA_$(COMPAT)_MODULE" \ 231 //D "_WINDLL" \
213 //D "MIME_API=__declspec(dllexport)" \ 232 //D "LUASOCKET_$(DEBUG)"
214 //D "LUASOCKET_$(DEBUG)" 233CFLAGS_win32=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
215CFLAGS_win32=//I "$(LUAINC)" $(DEF) //O2 //Ot //MD //W3 //nologo
216LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \ 234LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
217 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \ 235 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \
218 //MANIFESTUAC:"level='asInvoker' uiAccess='false'" \ 236 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
219 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \ 237 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
220 //MACHINE:X86 /LIBPATH:"$(shell cmd //c echo $(LUALIB))" \ 238 //MACHINE:X86 /LIBPATH:"$(LUALIB)" \
221 lua$(subst .,,$(LUAV)).lib ws2_32.lib //OUT: 239 $(LUALIBNAME_win32) ws2_32.lib //OUT:
240
222LD_win32=cl 241LD_win32=cl
223SOCKET_win32=wsocket.obj 242SOCKET_win32=wsocket.obj
224 243
244#------
245# Compiler and linker settings
246# for Win64
247SO_win64=dll
248O_win64=obj
249CC_win64=cl
250DEF_win64= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
251 //D "_CRT_SECURE_NO_WARNINGS" \
252 //D "_WINDLL" \
253 //D "LUASOCKET_$(DEBUG)"
254CFLAGS_win64=$(LUAINC:%=//I "%") $(DEF) //O2 //Ot //MD //W3 //nologo
255LDFLAGS_win64= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
256 //MANIFEST //MANIFESTFILE:"intermediate.manifest" \
257 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
258 //SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
259 /LIBPATH:"$(LUALIB)" \
260 $(LUALIBNAME_win64) ws2_32.lib //OUT:
261
262LD_win64=cl
263SOCKET_win64=wsocket.obj
264
225.SUFFIXES: .obj 265.SUFFIXES: .obj
226 266
227.c.obj: 267.c.obj:
228 $(CC) $(LUASOCKET_CFLAGS) //Fo"$@" //c $< 268 $(CC) $(CFLAGS) //Fo"$@" //c $<
229 269
230#------ 270#------
231# Output file names 271# Output file names
232# 272#
233SO=$(SO_$(PLAT)) 273SO=$(SO_$(PLAT))
234O=$(O_$(PLAT)) 274O=$(O_$(PLAT))
235SOCKET_V=3.0-rc1 275SOCKET_V=3.0.0
236MIME_V=1.0.3 276MIME_V=1.0.3
237SOCKET_SO=socket.$(SO).$(SOCKET_V) 277SOCKET_SO=socket-$(SOCKET_V).$(SO)
238MIME_SO=mime.$(SO).$(MIME_V) 278MIME_SO=mime-$(MIME_V).$(SO)
239UNIX_SO=unix.$(SO) 279UNIX_SO=unix.$(SO)
240SERIAL_SO=serial.$(SO) 280SERIAL_SO=serial.$(SO)
241SOCKET=$(SOCKET_$(PLAT)) 281SOCKET=$(SOCKET_$(PLAT))
@@ -286,6 +326,9 @@ UNIX_OBJS=\
286 timeout.$(O) \ 326 timeout.$(O) \
287 io.$(O) \ 327 io.$(O) \
288 usocket.$(O) \ 328 usocket.$(O) \
329 unixstream.$(O) \
330 unixdgram.$(O) \
331 compat.$(O) \
289 unix.$(O) 332 unix.$(O)
290 333
291#------ 334#------
@@ -293,6 +336,7 @@ UNIX_OBJS=\
293# 336#
294SERIAL_OBJS=\ 337SERIAL_OBJS=\
295 buffer.$(O) \ 338 buffer.$(O) \
339 compat.$(O) \
296 auxiliar.$(O) \ 340 auxiliar.$(O) \
297 options.$(O) \ 341 options.$(O) \
298 timeout.$(O) \ 342 timeout.$(O) \
@@ -331,12 +375,18 @@ macosx:
331win32: 375win32:
332 $(MAKE) all PLAT=win32 376 $(MAKE) all PLAT=win32
333 377
378win64:
379 $(MAKE) all PLAT=win64
380
334linux: 381linux:
335 $(MAKE) all-unix PLAT=linux 382 $(MAKE) all-unix PLAT=linux
336 383
337mingw: 384mingw:
338 $(MAKE) all PLAT=mingw 385 $(MAKE) all PLAT=mingw
339 386
387solaris:
388 $(MAKE) all-unix PLAT=solaris
389
340none: 390none:
341 @echo "Please run" 391 @echo "Please run"
342 @echo " make PLATFORM" 392 @echo " make PLATFORM"
@@ -359,7 +409,7 @@ $(UNIX_SO): $(UNIX_OBJS)
359$(SERIAL_SO): $(SERIAL_OBJS) 409$(SERIAL_SO): $(SERIAL_OBJS)
360 $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@ 410 $(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
361 411
362install: 412install:
363 $(INSTALL_DIR) $(INSTALL_TOP_LDIR) 413 $(INSTALL_DIR) $(INSTALL_TOP_LDIR)
364 $(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR) 414 $(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
365 $(INSTALL_DIR) $(INSTALL_SOCKET_LDIR) 415 $(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
diff --git a/src/mbox.lua b/src/mbox.lua
index 7724ae2..12823b0 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -1,8 +1,8 @@
1local _M = {} 1local _M = {}
2 2
3if module then 3if module then
4 mbox = _M 4 mbox = _M -- luacheck: ignore
5end 5end
6 6
7function _M.split_message(message_s) 7function _M.split_message(message_s)
8 local message = {} 8 local message = {}
@@ -29,7 +29,7 @@ end
29function _M.parse_header(header_s) 29function _M.parse_header(header_s)
30 header_s = string.gsub(header_s, "\n[ ]+", " ") 30 header_s = string.gsub(header_s, "\n[ ]+", " ")
31 header_s = string.gsub(header_s, "\n+", "") 31 header_s = string.gsub(header_s, "\n+", "")
32 local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") 32 local _, _, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
33 return name, value 33 return name, value
34end 34end
35 35
@@ -49,9 +49,9 @@ function _M.parse_headers(headers_s)
49end 49end
50 50
51function _M.parse_from(from) 51function _M.parse_from(from)
52 local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") 52 local _, _, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
53 if not address then 53 if not address then
54 _, __, address = string.find(from, "%s*(.+)%s*") 54 _, _, address = string.find(from, "%s*(.+)%s*")
55 end 55 end
56 name = name or "" 56 name = name or ""
57 address = address or "" 57 address = address or ""
@@ -61,9 +61,10 @@ function _M.parse_from(from)
61end 61end
62 62
63function _M.split_mbox(mbox_s) 63function _M.split_mbox(mbox_s)
64 mbox = {} 64 local mbox = {}
65 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" 65 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
66 local nj, i, j = 1, 1, 1 66 local nj, i
67 local j = 1
67 while 1 do 68 while 1 do
68 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) 69 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
69 if not i then break end 70 if not i then break end
diff --git a/src/mime.c b/src/mime.c
index ed44104..05602f5 100644..100755
--- a/src/mime.c
+++ b/src/mime.c
@@ -2,13 +2,10 @@
2* MIME support functions 2* MIME support functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "mime.h" 6#include "mime.h"
7#include <string.h>
8#include <ctype.h>
12 9
13/*=========================================================================*\ 10/*=========================================================================*\
14* Don't want to trust escape character constants 11* Don't want to trust escape character constants
@@ -30,12 +27,12 @@ static int mime_global_eol(lua_State *L);
30static int mime_global_dot(lua_State *L); 27static int mime_global_dot(lua_State *L);
31 28
32static size_t dot(int c, size_t state, luaL_Buffer *buffer); 29static size_t dot(int c, size_t state, luaL_Buffer *buffer);
33static void b64setup(UC *base); 30/*static void b64setup(UC *base);*/
34static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 31static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
35static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); 32static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
36static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 33static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
37 34
38static void qpsetup(UC *class, UC *unbase); 35/*static void qpsetup(UC *class, UC *unbase);*/
39static void qpquote(UC c, luaL_Buffer *buffer); 36static void qpquote(UC c, luaL_Buffer *buffer);
40static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); 37static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
41static size_t qpencode(UC c, UC *input, size_t size, 38static size_t qpencode(UC c, UC *input, size_t size,
@@ -58,17 +55,111 @@ static luaL_Reg func[] = {
58/*-------------------------------------------------------------------------*\ 55/*-------------------------------------------------------------------------*\
59* Quoted-printable globals 56* Quoted-printable globals
60\*-------------------------------------------------------------------------*/ 57\*-------------------------------------------------------------------------*/
61static UC qpclass[256];
62static UC qpbase[] = "0123456789ABCDEF";
63static UC qpunbase[256];
64enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; 58enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
65 59
60static const UC qpclass[] = {
61 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
62 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
63 QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
64 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
65 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
66 QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
67 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
68 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
69 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
70 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
71 QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
72 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
73 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
74 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
75 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
76 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
77 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
78 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
79 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
80 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
81 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
82 QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
83 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
84 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
85 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
86 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
87 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
88 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
89 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
90 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
91 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
92 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
93 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
94 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
95 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
96 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
97 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
98 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
99 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
100 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
101 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
102 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
103 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
104};
105
106static const UC qpbase[] = "0123456789ABCDEF";
107
108static const UC qpunbase[] = {
109 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
110 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
111 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
112 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
113 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
114 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
115 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
116 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
117 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
118 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
119 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
120 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
121 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
122 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
123 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
124 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
125 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
126 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
128 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
129 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
130 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
131 255, 255, 255, 255, 255, 255, 255, 255
132};
133
66/*-------------------------------------------------------------------------*\ 134/*-------------------------------------------------------------------------*\
67* Base64 globals 135* Base64 globals
68\*-------------------------------------------------------------------------*/ 136\*-------------------------------------------------------------------------*/
69static const UC b64base[] = 137static const UC b64base[] =
70 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 138 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
71static UC b64unbase[256]; 139
140static const UC b64unbase[] = {
141 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
142 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
143 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
144 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
145 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
146 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
147 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
148 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
149 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
150 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
151 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
152 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
153 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
154 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
155 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
156 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
157 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
158 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
159 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
160 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
161 255, 255
162};
72 163
73/*=========================================================================*\ 164/*=========================================================================*\
74* Exported functions 165* Exported functions
@@ -76,7 +167,7 @@ static UC b64unbase[256];
76/*-------------------------------------------------------------------------*\ 167/*-------------------------------------------------------------------------*\
77* Initializes module 168* Initializes module
78\*-------------------------------------------------------------------------*/ 169\*-------------------------------------------------------------------------*/
79MIME_API int luaopen_mime_core(lua_State *L) 170LUASOCKET_API int luaopen_mime_core(lua_State *L)
80{ 171{
81 lua_newtable(L); 172 lua_newtable(L);
82 luaL_setfuncs(L, func, 0); 173 luaL_setfuncs(L, func, 0);
@@ -85,8 +176,8 @@ MIME_API int luaopen_mime_core(lua_State *L)
85 lua_pushstring(L, MIME_VERSION); 176 lua_pushstring(L, MIME_VERSION);
86 lua_rawset(L, -3); 177 lua_rawset(L, -3);
87 /* initialize lookup tables */ 178 /* initialize lookup tables */
88 qpsetup(qpclass, qpunbase); 179 /*qpsetup(qpclass, qpunbase);*/
89 b64setup(b64unbase); 180 /*b64setup(b64unbase);*/
90 return 1; 181 return 1;
91} 182}
92 183
@@ -142,6 +233,7 @@ static int mime_global_wrp(lua_State *L)
142 return 2; 233 return 2;
143} 234}
144 235
236#if 0
145/*-------------------------------------------------------------------------*\ 237/*-------------------------------------------------------------------------*\
146* Fill base64 decode map. 238* Fill base64 decode map.
147\*-------------------------------------------------------------------------*/ 239\*-------------------------------------------------------------------------*/
@@ -151,7 +243,14 @@ static void b64setup(UC *unbase)
151 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; 243 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
152 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; 244 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
153 unbase['='] = 0; 245 unbase['='] = 0;
246
247 printf("static const UC b64unbase[] = {\n");
248 for (int i = 0; i < 256; i++) {
249 printf("%d, ", unbase[i]);
250 }
251 printf("\n}\n;");
154} 252}
253#endif
155 254
156/*-------------------------------------------------------------------------*\ 255/*-------------------------------------------------------------------------*\
157* Acumulates bytes in input buffer until 3 bytes are available. 256* Acumulates bytes in input buffer until 3 bytes are available.
@@ -345,12 +444,14 @@ static int mime_global_unb64(lua_State *L)
345* To encode one byte, we need to see the next two. 444* To encode one byte, we need to see the next two.
346* Worst case is when we see a space, and wonder if a CRLF is comming 445* Worst case is when we see a space, and wonder if a CRLF is comming
347\*-------------------------------------------------------------------------*/ 446\*-------------------------------------------------------------------------*/
447#if 0
348/*-------------------------------------------------------------------------*\ 448/*-------------------------------------------------------------------------*\
349* Split quoted-printable characters into classes 449* Split quoted-printable characters into classes
350* Precompute reverse map for encoding 450* Precompute reverse map for encoding
351\*-------------------------------------------------------------------------*/ 451\*-------------------------------------------------------------------------*/
352static void qpsetup(UC *cl, UC *unbase) 452static void qpsetup(UC *cl, UC *unbase)
353{ 453{
454
354 int i; 455 int i;
355 for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; 456 for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
356 for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; 457 for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
@@ -367,7 +468,37 @@ static void qpsetup(UC *cl, UC *unbase)
367 unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; 468 unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
368 unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; 469 unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
369 unbase['f'] = 15; 470 unbase['f'] = 15;
471
472printf("static UC qpclass[] = {");
473 for (int i = 0; i < 256; i++) {
474 if (i % 6 == 0) {
475 printf("\n ");
476 }
477 switch(cl[i]) {
478 case QP_QUOTED:
479 printf("QP_QUOTED, ");
480 break;
481 case QP_PLAIN:
482 printf("QP_PLAIN, ");
483 break;
484 case QP_CR:
485 printf("QP_CR, ");
486 break;
487 case QP_IF_LAST:
488 printf("QP_IF_LAST, ");
489 break;
490 }
491 }
492printf("\n};\n");
493
494printf("static const UC qpunbase[] = {");
495 for (int i = 0; i < 256; i++) {
496 int c = qpunbase[i];
497 printf("%d, ", c);
498 }
499printf("\";\n");
370} 500}
501#endif
371 502
372/*-------------------------------------------------------------------------*\ 503/*-------------------------------------------------------------------------*\
373* Output one character in form =XX 504* Output one character in form =XX
@@ -447,7 +578,6 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
447\*-------------------------------------------------------------------------*/ 578\*-------------------------------------------------------------------------*/
448static int mime_global_qp(lua_State *L) 579static int mime_global_qp(lua_State *L)
449{ 580{
450
451 size_t asize = 0, isize = 0; 581 size_t asize = 0, isize = 0;
452 UC atom[3]; 582 UC atom[3];
453 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); 583 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
@@ -654,7 +784,7 @@ static int eolprocess(int c, int last, const char *marker,
654\*-------------------------------------------------------------------------*/ 784\*-------------------------------------------------------------------------*/
655static int mime_global_eol(lua_State *L) 785static int mime_global_eol(lua_State *L)
656{ 786{
657 int ctx = luaL_checkinteger(L, 1); 787 int ctx = (int) luaL_checkinteger(L, 1);
658 size_t isize = 0; 788 size_t isize = 0;
659 const char *input = luaL_optlstring(L, 2, NULL, &isize); 789 const char *input = luaL_optlstring(L, 2, NULL, &isize);
660 const char *last = input + isize; 790 const char *last = input + isize;
@@ -689,6 +819,7 @@ static size_t dot(int c, size_t state, luaL_Buffer *buffer)
689 case '.': 819 case '.':
690 if (state == 2) 820 if (state == 2)
691 luaL_addchar(buffer, '.'); 821 luaL_addchar(buffer, '.');
822 /* Falls through. */
692 default: 823 default:
693 return 0; 824 return 0;
694 } 825 }
diff --git a/src/mime.h b/src/mime.h
index 99968a5..4d938f4 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -8,7 +8,7 @@
8* and formatting conforming to RFC 2045. It is used by mime.lua, which 8* and formatting conforming to RFC 2045. It is used by mime.lua, which
9* provide a higher level interface to this functionality. 9* provide a higher level interface to this functionality.
10\*=========================================================================*/ 10\*=========================================================================*/
11#include "lua.h" 11#include "luasocket.h"
12 12
13/*-------------------------------------------------------------------------*\ 13/*-------------------------------------------------------------------------*\
14* Current MIME library version 14* Current MIME library version
@@ -17,13 +17,6 @@
17#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab" 17#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab"
18#define MIME_AUTHORS "Diego Nehab" 18#define MIME_AUTHORS "Diego Nehab"
19 19
20/*-------------------------------------------------------------------------*\ 20LUASOCKET_API int luaopen_mime_core(lua_State *L);
21* This macro prefixes all exported API functions
22\*-------------------------------------------------------------------------*/
23#ifndef MIME_API
24#define MIME_API extern
25#endif
26
27MIME_API int luaopen_mime_core(lua_State *L);
28 21
29#endif /* MIME_H */ 22#endif /* MIME_H */
diff --git a/src/mime.lua b/src/mime.lua
index 642cd9c..93539de 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -10,8 +10,6 @@
10local base = _G 10local base = _G
11local ltn12 = require("ltn12") 11local ltn12 = require("ltn12")
12local mime = require("mime.core") 12local mime = require("mime.core")
13local io = require("io")
14local string = require("string")
15local _M = mime 13local _M = mime
16 14
17-- encode, decode and wrap algorithm tables 15-- encode, decode and wrap algorithm tables
@@ -19,7 +17,7 @@ local encodet, decodet, wrapt = {},{},{}
19 17
20_M.encodet = encodet 18_M.encodet = encodet
21_M.decodet = decodet 19_M.decodet = decodet
22_M.wrapt = wrapt 20_M.wrapt = wrapt
23 21
24-- creates a function that chooses a filter by name from a given table 22-- creates a function that chooses a filter by name from a given table
25local function choose(table) 23local function choose(table)
@@ -28,7 +26,7 @@ local function choose(table)
28 name, opt1, opt2 = "default", name, opt1 26 name, opt1, opt2 = "default", name, opt1
29 end 27 end
30 local f = table[name or "nil"] 28 local f = table[name or "nil"]
31 if not f then 29 if not f then
32 base.error("unknown key (" .. base.tostring(name) .. ")", 3) 30 base.error("unknown key (" .. base.tostring(name) .. ")", 3)
33 else return f(opt1, opt2) end 31 else return f(opt1, opt2) end
34 end 32 end
@@ -53,13 +51,6 @@ decodet['quoted-printable'] = function()
53 return ltn12.filter.cycle(_M.unqp, "") 51 return ltn12.filter.cycle(_M.unqp, "")
54end 52end
55 53
56local function format(chunk)
57 if chunk then
58 if chunk == "" then return "''"
59 else return string.len(chunk) end
60 else return "nil" end
61end
62
63-- define the line-wrap filters 54-- define the line-wrap filters
64wrapt['text'] = function(length) 55wrapt['text'] = function(length)
65 length = length or 76 56 length = length or 76
@@ -87,4 +78,4 @@ function _M.stuff()
87 return ltn12.filter.cycle(_M.dot, 2) 78 return ltn12.filter.cycle(_M.dot, 2)
88end 79end
89 80
90return _M \ No newline at end of file 81return _M
diff --git a/src/options.c b/src/options.c
index 20f4c28..9dea6bd 100644
--- a/src/options.c
+++ b/src/options.c
@@ -2,14 +2,11 @@
2* Common option interface 2* Common option interface
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lauxlib.h"
8
9#include "auxiliar.h" 6#include "auxiliar.h"
10#include "options.h" 7#include "options.h"
11#include "inet.h" 8#include "inet.h"
12 9#include <string.h>
13 10
14/*=========================================================================*\ 11/*=========================================================================*\
15* Internal functions prototypes 12* Internal functions prototypes
@@ -37,7 +34,7 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
37 while (opt->name && strcmp(name, opt->name)) 34 while (opt->name && strcmp(name, opt->name))
38 opt++; 35 opt++;
39 if (!opt->func) { 36 if (!opt->func) {
40 char msg[45]; 37 char msg[57];
41 sprintf(msg, "unsupported option `%.35s'", name); 38 sprintf(msg, "unsupported option `%.35s'", name);
42 luaL_argerror(L, 2, msg); 39 luaL_argerror(L, 2, msg);
43 } 40 }
@@ -50,13 +47,41 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
50 while (opt->name && strcmp(name, opt->name)) 47 while (opt->name && strcmp(name, opt->name))
51 opt++; 48 opt++;
52 if (!opt->func) { 49 if (!opt->func) {
53 char msg[45]; 50 char msg[57];
54 sprintf(msg, "unsupported option `%.35s'", name); 51 sprintf(msg, "unsupported option `%.35s'", name);
55 luaL_argerror(L, 2, msg); 52 luaL_argerror(L, 2, msg);
56 } 53 }
57 return opt->func(L, ps); 54 return opt->func(L, ps);
58} 55}
59 56
57/*------------------------------------------------------*/
58/* binds socket to network interface */
59int opt_set_bindtodevice(lua_State *L, p_socket ps)
60{
61#ifndef SO_BINDTODEVICE
62 return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
63#else
64 const char *dev = luaL_checkstring(L, 3);
65 return opt_set(L, ps, SOL_SOCKET, SO_BINDTODEVICE, (char*)dev, strlen(dev)+1);
66#endif
67}
68
69int opt_get_bindtodevice(lua_State *L, p_socket ps)
70{
71#ifndef SO_BINDTODEVICE
72 return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system");
73#else
74 char dev[IFNAMSIZ];
75 int len = sizeof(dev);
76 int err = opt_get(L, ps, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len);
77 if (err)
78 return err;
79 lua_pushstring(L, dev);
80 return 1;
81#endif
82}
83
84/*------------------------------------------------------*/
60/* enables reuse of local address */ 85/* enables reuse of local address */
61int opt_set_reuseaddr(lua_State *L, p_socket ps) 86int opt_set_reuseaddr(lua_State *L, p_socket ps)
62{ 87{
@@ -68,6 +93,7 @@ int opt_get_reuseaddr(lua_State *L, p_socket ps)
68 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); 93 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
69} 94}
70 95
96/*------------------------------------------------------*/
71/* enables reuse of local port */ 97/* enables reuse of local port */
72int opt_set_reuseport(lua_State *L, p_socket ps) 98int opt_set_reuseport(lua_State *L, p_socket ps)
73{ 99{
@@ -79,7 +105,8 @@ int opt_get_reuseport(lua_State *L, p_socket ps)
79 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); 105 return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
80} 106}
81 107
82/* disables the Naggle algorithm */ 108/*------------------------------------------------------*/
109/* disables the Nagle algorithm */
83int opt_set_tcp_nodelay(lua_State *L, p_socket ps) 110int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
84{ 111{
85 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 112 return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
@@ -90,6 +117,52 @@ int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
90 return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 117 return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
91} 118}
92 119
120/*------------------------------------------------------*/
121#ifdef TCP_KEEPIDLE
122
123int opt_get_tcp_keepidle(lua_State *L, p_socket ps)
124{
125 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
126}
127
128int opt_set_tcp_keepidle(lua_State *L, p_socket ps)
129{
130 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE);
131}
132
133#endif
134
135/*------------------------------------------------------*/
136#ifdef TCP_KEEPCNT
137
138int opt_get_tcp_keepcnt(lua_State *L, p_socket ps)
139{
140 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
141}
142
143int opt_set_tcp_keepcnt(lua_State *L, p_socket ps)
144{
145 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT);
146}
147
148#endif
149
150/*------------------------------------------------------*/
151#ifdef TCP_KEEPINTVL
152
153int opt_get_tcp_keepintvl(lua_State *L, p_socket ps)
154{
155 return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
156}
157
158int opt_set_tcp_keepintvl(lua_State *L, p_socket ps)
159{
160 return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL);
161}
162
163#endif
164
165/*------------------------------------------------------*/
93int opt_set_keepalive(lua_State *L, p_socket ps) 166int opt_set_keepalive(lua_State *L, p_socket ps)
94{ 167{
95 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 168 return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
@@ -100,6 +173,7 @@ int opt_get_keepalive(lua_State *L, p_socket ps)
100 return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 173 return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
101} 174}
102 175
176/*------------------------------------------------------*/
103int opt_set_dontroute(lua_State *L, p_socket ps) 177int opt_set_dontroute(lua_State *L, p_socket ps)
104{ 178{
105 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); 179 return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
@@ -110,6 +184,7 @@ int opt_get_dontroute(lua_State *L, p_socket ps)
110 return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); 184 return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
111} 185}
112 186
187/*------------------------------------------------------*/
113int opt_set_broadcast(lua_State *L, p_socket ps) 188int opt_set_broadcast(lua_State *L, p_socket ps)
114{ 189{
115 return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); 190 return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
@@ -120,6 +195,54 @@ int opt_get_broadcast(lua_State *L, p_socket ps)
120 return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); 195 return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
121} 196}
122 197
198/*------------------------------------------------------*/
199int opt_set_recv_buf_size(lua_State *L, p_socket ps)
200{
201 return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF);
202}
203
204int opt_get_recv_buf_size(lua_State *L, p_socket ps)
205{
206 return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF);
207}
208
209/*------------------------------------------------------*/
210int opt_get_send_buf_size(lua_State *L, p_socket ps)
211{
212 return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF);
213}
214
215int opt_set_send_buf_size(lua_State *L, p_socket ps)
216{
217 return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF);
218}
219
220/*------------------------------------------------------*/
221
222#ifdef TCP_FASTOPEN
223int opt_set_tcp_fastopen(lua_State *L, p_socket ps)
224{
225 return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN);
226}
227#endif
228
229#ifdef TCP_FASTOPEN_CONNECT
230int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps)
231{
232 return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT);
233}
234#endif
235
236/*------------------------------------------------------*/
237
238#ifdef TCP_DEFER_ACCEPT
239int opt_set_tcp_defer_accept(lua_State *L, p_socket ps)
240{
241 return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT);
242}
243#endif
244
245/*------------------------------------------------------*/
123int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) 246int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
124{ 247{
125 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); 248 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
@@ -130,6 +253,7 @@ int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
130 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); 253 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
131} 254}
132 255
256/*------------------------------------------------------*/
133int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) 257int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
134{ 258{
135 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); 259 return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
@@ -140,6 +264,7 @@ int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
140 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); 264 return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
141} 265}
142 266
267/*------------------------------------------------------*/
143int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) 268int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
144{ 269{
145 return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); 270 return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
@@ -150,6 +275,7 @@ int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
150 return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); 275 return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
151} 276}
152 277
278/*------------------------------------------------------*/
153int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) 279int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
154{ 280{
155 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); 281 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
@@ -160,6 +286,7 @@ int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
160 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); 286 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
161} 287}
162 288
289/*------------------------------------------------------*/
163int opt_set_linger(lua_State *L, p_socket ps) 290int opt_set_linger(lua_State *L, p_socket ps)
164{ 291{
165 struct linger li; /* obj, name, table */ 292 struct linger li; /* obj, name, table */
@@ -192,11 +319,13 @@ int opt_get_linger(lua_State *L, p_socket ps)
192 return 1; 319 return 1;
193} 320}
194 321
322/*------------------------------------------------------*/
195int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) 323int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
196{ 324{
197 return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); 325 return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
198} 326}
199 327
328/*------------------------------------------------------*/
200int opt_set_ip_multicast_if(lua_State *L, p_socket ps) 329int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
201{ 330{
202 const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ 331 const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
@@ -221,6 +350,7 @@ int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
221 return 1; 350 return 1;
222} 351}
223 352
353/*------------------------------------------------------*/
224int opt_set_ip_add_membership(lua_State *L, p_socket ps) 354int opt_set_ip_add_membership(lua_State *L, p_socket ps)
225{ 355{
226 return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); 356 return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
@@ -231,6 +361,7 @@ int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
231 return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); 361 return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
232} 362}
233 363
364/*------------------------------------------------------*/
234int opt_set_ip6_add_membership(lua_State *L, p_socket ps) 365int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
235{ 366{
236 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); 367 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
@@ -241,6 +372,7 @@ int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
241 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); 372 return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
242} 373}
243 374
375/*------------------------------------------------------*/
244int opt_get_ip6_v6only(lua_State *L, p_socket ps) 376int opt_get_ip6_v6only(lua_State *L, p_socket ps)
245{ 377{
246 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); 378 return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
@@ -251,6 +383,20 @@ int opt_set_ip6_v6only(lua_State *L, p_socket ps)
251 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); 383 return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
252} 384}
253 385
386/*------------------------------------------------------*/
387int opt_get_error(lua_State *L, p_socket ps)
388{
389 int val = 0;
390 socklen_t len = sizeof(val);
391 if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
392 lua_pushnil(L);
393 lua_pushstring(L, "getsockopt failed");
394 return 2;
395 }
396 lua_pushstring(L, socket_strerror(val));
397 return 1;
398}
399
254/*=========================================================================*\ 400/*=========================================================================*\
255* Auxiliar functions 401* Auxiliar functions
256\*=========================================================================*/ 402\*=========================================================================*/
@@ -337,19 +483,6 @@ static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
337 return 1; 483 return 1;
338} 484}
339 485
340int opt_get_error(lua_State *L, p_socket ps)
341{
342 int val = 0;
343 socklen_t len = sizeof(val);
344 if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
345 lua_pushnil(L);
346 lua_pushstring(L, "getsockopt failed");
347 return 2;
348 }
349 lua_pushstring(L, socket_strerror(val));
350 return 1;
351}
352
353static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) 486static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
354{ 487{
355 int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ 488 int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
diff --git a/src/options.h b/src/options.h
index ad1b00d..26d6f02 100644
--- a/src/options.h
+++ b/src/options.h
@@ -8,7 +8,7 @@
8* modules UDP and TCP. 8* modules UDP and TCP.
9\*=========================================================================*/ 9\*=========================================================================*/
10 10
11#include "lua.h" 11#include "luasocket.h"
12#include "socket.h" 12#include "socket.h"
13 13
14/* option registry */ 14/* option registry */
@@ -18,45 +18,99 @@ typedef struct t_opt {
18} t_opt; 18} t_opt;
19typedef t_opt *p_opt; 19typedef t_opt *p_opt;
20 20
21/* supported options for setoption */ 21#ifndef _WIN32
22int opt_set_dontroute(lua_State *L, p_socket ps); 22#pragma GCC visibility push(hidden)
23int opt_set_broadcast(lua_State *L, p_socket ps); 23#endif
24
25int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
26int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
27
24int opt_set_reuseaddr(lua_State *L, p_socket ps); 28int opt_set_reuseaddr(lua_State *L, p_socket ps);
29int opt_get_reuseaddr(lua_State *L, p_socket ps);
30
31int opt_set_reuseport(lua_State *L, p_socket ps);
32int opt_get_reuseport(lua_State *L, p_socket ps);
33
25int opt_set_tcp_nodelay(lua_State *L, p_socket ps); 34int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
35int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
36
37#ifdef TCP_KEEPIDLE
38int opt_set_tcp_keepidle(lua_State *L, p_socket ps);
39int opt_get_tcp_keepidle(lua_State *L, p_socket ps);
40#endif
41
42#ifdef TCP_KEEPCNT
43int opt_set_tcp_keepcnt(lua_State *L, p_socket ps);
44int opt_get_tcp_keepcnt(lua_State *L, p_socket ps);
45#endif
46
47#ifdef TCP_KEEPINTVL
48int opt_set_tcp_keepintvl(lua_State *L, p_socket ps);
49int opt_get_tcp_keepintvl(lua_State *L, p_socket ps);
50#endif
51
52#ifdef TCP_DEFER_ACCEPT
53int opt_set_tcp_defer_accept(lua_State *L, p_socket ps);
54#endif
55
56int opt_set_bindtodevice(lua_State *L, p_socket ps);
57int opt_get_bindtodevice(lua_State *L, p_socket ps);
58
26int opt_set_keepalive(lua_State *L, p_socket ps); 59int opt_set_keepalive(lua_State *L, p_socket ps);
60int opt_get_keepalive(lua_State *L, p_socket ps);
61
62int opt_set_dontroute(lua_State *L, p_socket ps);
63int opt_get_dontroute(lua_State *L, p_socket ps);
64
65int opt_set_broadcast(lua_State *L, p_socket ps);
66int opt_get_broadcast(lua_State *L, p_socket ps);
67
68int opt_set_recv_buf_size(lua_State *L, p_socket ps);
69int opt_get_recv_buf_size(lua_State *L, p_socket ps);
70
71int opt_set_send_buf_size(lua_State *L, p_socket ps);
72int opt_get_send_buf_size(lua_State *L, p_socket ps);
73
74#ifdef TCP_FASTOPEN
75int opt_set_tcp_fastopen(lua_State *L, p_socket ps);
76#endif
77#ifdef TCP_FASTOPEN_CONNECT
78int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps);
79#endif
80
81int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
82int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
83
84int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
85int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
86
87int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
88int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
89
90int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
91int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
92
27int opt_set_linger(lua_State *L, p_socket ps); 93int opt_set_linger(lua_State *L, p_socket ps);
28int opt_set_reuseaddr(lua_State *L, p_socket ps); 94int opt_get_linger(lua_State *L, p_socket ps);
29int opt_set_reuseport(lua_State *L, p_socket ps); 95
30int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
31int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); 96int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
32int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); 97
98int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
99int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
100
33int opt_set_ip_add_membership(lua_State *L, p_socket ps); 101int opt_set_ip_add_membership(lua_State *L, p_socket ps);
34int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); 102int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
35int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); 103
36int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
37int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
38int opt_set_ip6_add_membership(lua_State *L, p_socket ps); 104int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
39int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); 105int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
106
40int opt_set_ip6_v6only(lua_State *L, p_socket ps); 107int opt_set_ip6_v6only(lua_State *L, p_socket ps);
108int opt_get_ip6_v6only(lua_State *L, p_socket ps);
41 109
42/* supported options for getoption */
43int opt_get_dontroute(lua_State *L, p_socket ps);
44int opt_get_broadcast(lua_State *L, p_socket ps);
45int opt_get_reuseaddr(lua_State *L, p_socket ps);
46int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
47int opt_get_keepalive(lua_State *L, p_socket ps);
48int opt_get_linger(lua_State *L, p_socket ps);
49int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
50int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
51int opt_get_error(lua_State *L, p_socket ps); 110int opt_get_error(lua_State *L, p_socket ps);
52int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
53int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
54int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
55int opt_get_ip6_v6only(lua_State *L, p_socket ps);
56int opt_get_reuseport(lua_State *L, p_socket ps);
57 111
58/* invokes the appropriate option handler */ 112#ifndef _WIN32
59int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); 113#pragma GCC visibility pop
60int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); 114#endif
61 115
62#endif 116#endif
diff --git a/src/select.c b/src/select.c
index d14c40a..bb47c45 100644
--- a/src/select.c
+++ b/src/select.c
@@ -2,16 +2,14 @@
2* Select implementation 2* Select implementation
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10 6
11#include "socket.h" 7#include "socket.h"
12#include "timeout.h" 8#include "timeout.h"
13#include "select.h" 9#include "select.h"
14 10
11#include <string.h>
12
15/*=========================================================================*\ 13/*=========================================================================*\
16* Internal function prototypes. 14* Internal function prototypes.
17\*=========================================================================*/ 15\*=========================================================================*/
@@ -31,15 +29,15 @@ static luaL_Reg func[] = {
31 {NULL, NULL} 29 {NULL, NULL}
32}; 30};
33 31
34/*=========================================================================*\
35* Exported functions
36\*=========================================================================*/
37/*-------------------------------------------------------------------------*\ 32/*-------------------------------------------------------------------------*\
38* Initializes module 33* Initializes module
39\*-------------------------------------------------------------------------*/ 34\*-------------------------------------------------------------------------*/
40int select_open(lua_State *L) { 35int select_open(lua_State *L) {
41 lua_pushstring(L, "_SETSIZE"); 36 lua_pushstring(L, "_SETSIZE");
42 lua_pushnumber(L, FD_SETSIZE); 37 lua_pushinteger(L, FD_SETSIZE);
38 lua_rawset(L, -3);
39 lua_pushstring(L, "_SOCKETINVALID");
40 lua_pushinteger(L, SOCKET_INVALID);
43 lua_rawset(L, -3); 41 lua_rawset(L, -3);
44 luaL_setfuncs(L, func, 0); 42 luaL_setfuncs(L, func, 0);
45 return 0; 43 return 0;
@@ -214,4 +212,3 @@ static void make_assoc(lua_State *L, int tab) {
214 i = i+1; 212 i = i+1;
215 } 213 }
216} 214}
217
diff --git a/src/select.h b/src/select.h
index 8750200..5d45fe7 100644
--- a/src/select.h
+++ b/src/select.h
@@ -10,6 +10,14 @@
10* true if there is data ready for reading (required for buffered input). 10* true if there is data ready for reading (required for buffered input).
11\*=========================================================================*/ 11\*=========================================================================*/
12 12
13#ifndef _WIN32
14#pragma GCC visibility push(hidden)
15#endif
16
13int select_open(lua_State *L); 17int select_open(lua_State *L);
14 18
19#ifndef _WIN32
20#pragma GCC visibility pop
21#endif
22
15#endif /* SELECT_H */ 23#endif /* SELECT_H */
diff --git a/src/serial.c b/src/serial.c
index 7bdb21c..21485d3 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -2,15 +2,14 @@
2* Serial stream 2* Serial stream
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9 6
10#include "auxiliar.h" 7#include "auxiliar.h"
11#include "socket.h" 8#include "socket.h"
12#include "options.h" 9#include "options.h"
13#include "unix.h" 10#include "unix.h"
11
12#include <string.h>
14#include <sys/un.h> 13#include <sys/un.h>
15 14
16/* 15/*
diff --git a/src/socket.h b/src/socket.h
index 63573de..2555bab 100644..100755
--- a/src/socket.h
+++ b/src/socket.h
@@ -16,8 +16,10 @@
16\*=========================================================================*/ 16\*=========================================================================*/
17#ifdef _WIN32 17#ifdef _WIN32
18#include "wsocket.h" 18#include "wsocket.h"
19#define LUA_GAI_STRERROR gai_strerrorA
19#else 20#else
20#include "usocket.h" 21#include "usocket.h"
22#define LUA_GAI_STRERROR gai_strerror
21#endif 23#endif
22 24
23/*=========================================================================*\ 25/*=========================================================================*\
@@ -28,51 +30,46 @@
28\*=========================================================================*/ 30\*=========================================================================*/
29#include "timeout.h" 31#include "timeout.h"
30 32
31/* we are lazy... */ 33/* convenient shorthand */
32typedef struct sockaddr SA; 34typedef struct sockaddr SA;
33 35
34/*=========================================================================*\ 36/*=========================================================================*\
35* Functions bellow implement a comfortable platform independent 37* Functions bellow implement a comfortable platform independent
36* interface to sockets 38* interface to sockets
37\*=========================================================================*/ 39\*=========================================================================*/
38int socket_open(void);
39int socket_close(void);
40void socket_destroy(p_socket ps);
41void socket_shutdown(p_socket ps, int how);
42int socket_sendto(p_socket ps, const char *data, size_t count,
43 size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
44int socket_recvfrom(p_socket ps, char *data, size_t count,
45 size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
46 40
47void socket_setnonblocking(p_socket ps); 41#ifndef _WIN32
48void socket_setblocking(p_socket ps); 42#pragma GCC visibility push(hidden)
43#endif
49 44
50int socket_waitfd(p_socket ps, int sw, p_timeout tm); 45int socket_waitfd(p_socket ps, int sw, p_timeout tm);
51int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 46int socket_open(void);
52 p_timeout tm); 47int socket_close(void);
53 48void socket_destroy(p_socket ps);
54int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); 49int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_timeout tm);
55int socket_create(p_socket ps, int domain, int type, int protocol); 50int socket_create(p_socket ps, int domain, int type, int protocol);
56int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); 51int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
57int socket_listen(p_socket ps, int backlog); 52int socket_listen(p_socket ps, int backlog);
58int socket_accept(p_socket ps, p_socket pa, SA *addr, 53void socket_shutdown(p_socket ps, int how);
59 socklen_t *addr_len, p_timeout tm); 54int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
60 55int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *addr_len, p_timeout tm);
61const char *socket_hoststrerror(int err); 56int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
62const char *socket_gaistrerror(int err); 57int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
63const char *socket_strerror(int err);
64
65/* these are perfect to use with the io abstraction module
66 and the buffered input module */
67int socket_send(p_socket ps, const char *data, size_t count,
68 size_t *sent, p_timeout tm);
69int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 58int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
70int socket_write(p_socket ps, const char *data, size_t count, 59int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
71 size_t *sent, p_timeout tm); 60int socket_write(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm);
72int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 61int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
73const char *socket_ioerror(p_socket ps, int err); 62void socket_setblocking(p_socket ps);
74 63void socket_setnonblocking(p_socket ps);
75int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); 64int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
76int socket_gethostbyname(const char *addr, struct hostent **hp); 65int socket_gethostbyname(const char *addr, struct hostent **hp);
66const char *socket_hoststrerror(int err);
67const char *socket_strerror(int err);
68const char *socket_ioerror(p_socket ps, int err);
69const char *socket_gaistrerror(int err);
70
71#ifndef _WIN32
72#pragma GCC visibility pop
73#endif
77 74
78#endif /* SOCKET_H */ 75#endif /* SOCKET_H */
diff --git a/src/tcp.c b/src/tcp.c
index 7bf1af5..f001206 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -2,11 +2,7 @@
2* TCP object 2* TCP object
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10 6
11#include "auxiliar.h" 7#include "auxiliar.h"
12#include "socket.h" 8#include "socket.h"
@@ -14,6 +10,8 @@
14#include "options.h" 10#include "options.h"
15#include "tcp.h" 11#include "tcp.h"
16 12
13#include <string.h>
14
17/*=========================================================================*\ 15/*=========================================================================*\
18* Internal function prototypes 16* Internal function prototypes
19\*=========================================================================*/ 17\*=========================================================================*/
@@ -36,6 +34,7 @@ static int meth_accept(lua_State *L);
36static int meth_close(lua_State *L); 34static int meth_close(lua_State *L);
37static int meth_getoption(lua_State *L); 35static int meth_getoption(lua_State *L);
38static int meth_setoption(lua_State *L); 36static int meth_setoption(lua_State *L);
37static int meth_gettimeout(lua_State *L);
39static int meth_settimeout(lua_State *L); 38static int meth_settimeout(lua_State *L);
40static int meth_getfd(lua_State *L); 39static int meth_getfd(lua_State *L);
41static int meth_setfd(lua_State *L); 40static int meth_setfd(lua_State *L);
@@ -65,26 +64,62 @@ static luaL_Reg tcp_methods[] = {
65 {"setpeername", meth_connect}, 64 {"setpeername", meth_connect},
66 {"setsockname", meth_bind}, 65 {"setsockname", meth_bind},
67 {"settimeout", meth_settimeout}, 66 {"settimeout", meth_settimeout},
67 {"gettimeout", meth_gettimeout},
68 {"shutdown", meth_shutdown}, 68 {"shutdown", meth_shutdown},
69 {NULL, NULL} 69 {NULL, NULL}
70}; 70};
71 71
72/* socket option handlers */ 72/* socket option handlers */
73static t_opt optget[] = { 73static t_opt optget[] = {
74 {"bindtodevice", opt_get_bindtodevice},
74 {"keepalive", opt_get_keepalive}, 75 {"keepalive", opt_get_keepalive},
75 {"reuseaddr", opt_get_reuseaddr}, 76 {"reuseaddr", opt_get_reuseaddr},
77 {"reuseport", opt_get_reuseport},
76 {"tcp-nodelay", opt_get_tcp_nodelay}, 78 {"tcp-nodelay", opt_get_tcp_nodelay},
79#ifdef TCP_KEEPIDLE
80 {"tcp-keepidle", opt_get_tcp_keepidle},
81#endif
82#ifdef TCP_KEEPCNT
83 {"tcp-keepcnt", opt_get_tcp_keepcnt},
84#endif
85#ifdef TCP_KEEPINTVL
86 {"tcp-keepintvl", opt_get_tcp_keepintvl},
87#endif
77 {"linger", opt_get_linger}, 88 {"linger", opt_get_linger},
78 {"error", opt_get_error}, 89 {"error", opt_get_error},
90 {"recv-buffer-size", opt_get_recv_buf_size},
91 {"send-buffer-size", opt_get_send_buf_size},
79 {NULL, NULL} 92 {NULL, NULL}
80}; 93};
81 94
82static t_opt optset[] = { 95static t_opt optset[] = {
96 {"bindtodevice", opt_set_bindtodevice},
83 {"keepalive", opt_set_keepalive}, 97 {"keepalive", opt_set_keepalive},
84 {"reuseaddr", opt_set_reuseaddr}, 98 {"reuseaddr", opt_set_reuseaddr},
99 {"reuseport", opt_set_reuseport},
85 {"tcp-nodelay", opt_set_tcp_nodelay}, 100 {"tcp-nodelay", opt_set_tcp_nodelay},
101#ifdef TCP_KEEPIDLE
102 {"tcp-keepidle", opt_set_tcp_keepidle},
103#endif
104#ifdef TCP_KEEPCNT
105 {"tcp-keepcnt", opt_set_tcp_keepcnt},
106#endif
107#ifdef TCP_KEEPINTVL
108 {"tcp-keepintvl", opt_set_tcp_keepintvl},
109#endif
86 {"ipv6-v6only", opt_set_ip6_v6only}, 110 {"ipv6-v6only", opt_set_ip6_v6only},
87 {"linger", opt_set_linger}, 111 {"linger", opt_set_linger},
112 {"recv-buffer-size", opt_set_recv_buf_size},
113 {"send-buffer-size", opt_set_send_buf_size},
114#ifdef TCP_DEFER_ACCEPT
115 {"tcp-defer-accept", opt_set_tcp_defer_accept},
116#endif
117#ifdef TCP_FASTOPEN
118 {"tcp-fastopen", opt_set_tcp_fastopen},
119#endif
120#ifdef TCP_FASTOPEN_CONNECT
121 {"tcp-fastopen-connect", opt_set_tcp_fastopen_connect},
122#endif
88 {NULL, NULL} 123 {NULL, NULL}
89}; 124};
90 125
@@ -348,6 +383,12 @@ static int meth_settimeout(lua_State *L)
348 return timeout_meth_settimeout(L, &tcp->tm); 383 return timeout_meth_settimeout(L, &tcp->tm);
349} 384}
350 385
386static int meth_gettimeout(lua_State *L)
387{
388 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
389 return timeout_meth_gettimeout(L, &tcp->tm);
390}
391
351/*=========================================================================*\ 392/*=========================================================================*\
352* Library functions 393* Library functions
353\*=========================================================================*/ 394\*=========================================================================*/
@@ -415,7 +456,7 @@ static int global_connect(lua_State *L) {
415 bindhints.ai_family = family; 456 bindhints.ai_family = family;
416 bindhints.ai_flags = AI_PASSIVE; 457 bindhints.ai_flags = AI_PASSIVE;
417 if (localaddr) { 458 if (localaddr) {
418 err = inet_trybind(&tcp->sock, &tcp->family, localaddr, 459 err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
419 localserv, &bindhints); 460 localserv, &bindhints);
420 if (err) { 461 if (err) {
421 lua_pushnil(L); 462 lua_pushnil(L);
@@ -427,7 +468,7 @@ static int global_connect(lua_State *L) {
427 memset(&connecthints, 0, sizeof(connecthints)); 468 memset(&connecthints, 0, sizeof(connecthints));
428 connecthints.ai_socktype = SOCK_STREAM; 469 connecthints.ai_socktype = SOCK_STREAM;
429 /* make sure we try to connect only to the same family */ 470 /* make sure we try to connect only to the same family */
430 connecthints.ai_family = tcp->family; 471 connecthints.ai_family = tcp->family;
431 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, 472 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
432 &tcp->tm, &connecthints); 473 &tcp->tm, &connecthints);
433 if (err) { 474 if (err) {
diff --git a/src/tcp.h b/src/tcp.h
index eded620..9b282ef 100644
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -14,7 +14,7 @@
14* tcp objects either connected to some address or returned by the accept 14* tcp objects either connected to some address or returned by the accept
15* method of a server object. 15* method of a server object.
16\*=========================================================================*/ 16\*=========================================================================*/
17#include "lua.h" 17#include "luasocket.h"
18 18
19#include "buffer.h" 19#include "buffer.h"
20#include "timeout.h" 20#include "timeout.h"
@@ -30,6 +30,14 @@ typedef struct t_tcp_ {
30 30
31typedef t_tcp *p_tcp; 31typedef t_tcp *p_tcp;
32 32
33#ifndef _WIN32
34#pragma GCC visibility push(hidden)
35#endif
36
33int tcp_open(lua_State *L); 37int tcp_open(lua_State *L);
34 38
39#ifndef _WIN32
40#pragma GCC visibility pop
41#endif
42
35#endif /* TCP_H */ 43#endif /* TCP_H */
diff --git a/src/timeout.c b/src/timeout.c
index 087d033..2bdc069 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -2,17 +2,15 @@
2* Timeout management functions 2* Timeout management functions
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <stdio.h> 5#include "luasocket.h"
6#include <limits.h>
7#include <float.h>
8
9#include "lua.h"
10#include "lauxlib.h"
11#include "compat.h"
12 6
13#include "auxiliar.h" 7#include "auxiliar.h"
14#include "timeout.h" 8#include "timeout.h"
15 9
10#include <stdio.h>
11#include <limits.h>
12#include <float.h>
13
16#ifdef _WIN32 14#ifdef _WIN32
17#include <windows.h> 15#include <windows.h>
18#else 16#else
@@ -173,6 +171,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
173 return 1; 171 return 1;
174} 172}
175 173
174/*-------------------------------------------------------------------------*\
175* Gets timeout values for IO operations
176* Lua Output: block, total
177\*-------------------------------------------------------------------------*/
178int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
179 lua_pushnumber(L, tm->block);
180 lua_pushnumber(L, tm->total);
181 return 2;
182}
183
176/*=========================================================================*\ 184/*=========================================================================*\
177* Test support functions 185* Test support functions
178\*=========================================================================*/ 186\*=========================================================================*/
diff --git a/src/timeout.h b/src/timeout.h
index 6715ca7..9e5250d 100644
--- a/src/timeout.h
+++ b/src/timeout.h
@@ -4,7 +4,7 @@
4* Timeout management functions 4* Timeout management functions
5* LuaSocket toolkit 5* LuaSocket toolkit
6\*=========================================================================*/ 6\*=========================================================================*/
7#include "lua.h" 7#include "luasocket.h"
8 8
9/* timeout control structure */ 9/* timeout control structure */
10typedef struct t_timeout_ { 10typedef struct t_timeout_ {
@@ -14,14 +14,26 @@ typedef struct t_timeout_ {
14} t_timeout; 14} t_timeout;
15typedef t_timeout *p_timeout; 15typedef t_timeout *p_timeout;
16 16
17int timeout_open(lua_State *L); 17#ifndef _WIN32
18#pragma GCC visibility push(hidden)
19#endif
20
18void timeout_init(p_timeout tm, double block, double total); 21void timeout_init(p_timeout tm, double block, double total);
19double timeout_get(p_timeout tm); 22double timeout_get(p_timeout tm);
23double timeout_getstart(p_timeout tm);
20double timeout_getretry(p_timeout tm); 24double timeout_getretry(p_timeout tm);
21p_timeout timeout_markstart(p_timeout tm); 25p_timeout timeout_markstart(p_timeout tm);
22double timeout_getstart(p_timeout tm); 26
23double timeout_gettime(void); 27double timeout_gettime(void);
28
29int timeout_open(lua_State *L);
30
24int timeout_meth_settimeout(lua_State *L, p_timeout tm); 31int timeout_meth_settimeout(lua_State *L, p_timeout tm);
32int timeout_meth_gettimeout(lua_State *L, p_timeout tm);
33
34#ifndef _WIN32
35#pragma GCC visibility pop
36#endif
25 37
26#define timeout_iszero(tm) ((tm)->block == 0.0) 38#define timeout_iszero(tm) ((tm)->block == 0.0)
27 39
diff --git a/src/tp.lua b/src/tp.lua
index cbeff56..b8ebc56 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -46,6 +46,14 @@ end
46-- metatable for sock object 46-- metatable for sock object
47local metat = { __index = {} } 47local metat = { __index = {} }
48 48
49function metat.__index:getpeername()
50 return self.c:getpeername()
51end
52
53function metat.__index:getsockname()
54 return self.c:getpeername()
55end
56
49function metat.__index:check(ok) 57function metat.__index:check(ok)
50 local code, reply = get_reply(self.c) 58 local code, reply = get_reply(self.c)
51 if not code then return nil, reply end 59 if not code then return nil, reply end
@@ -74,7 +82,7 @@ function metat.__index:command(cmd, arg)
74end 82end
75 83
76function metat.__index:sink(snk, pat) 84function metat.__index:sink(snk, pat)
77 local chunk, err = c:receive(pat) 85 local chunk, err = self.c:receive(pat)
78 return snk(chunk, err) 86 return snk(chunk, err)
79end 87end
80 88
@@ -123,4 +131,4 @@ function _M.connect(host, port, timeout, create)
123 return base.setmetatable({c = c}, metat) 131 return base.setmetatable({c = c}, metat)
124end 132end
125 133
126return _M \ No newline at end of file 134return _M
diff --git a/src/udp.c b/src/udp.c
index 17d932a..712ad50 100644..100755
--- a/src/udp.c
+++ b/src/udp.c
@@ -2,12 +2,7 @@
2* UDP object 2* UDP object
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6#include <stdlib.h>
7
8#include "lua.h"
9#include "lauxlib.h"
10#include "compat.h"
11 6
12#include "auxiliar.h" 7#include "auxiliar.h"
13#include "socket.h" 8#include "socket.h"
@@ -15,6 +10,9 @@
15#include "options.h" 10#include "options.h"
16#include "udp.h" 11#include "udp.h"
17 12
13#include <string.h>
14#include <stdlib.h>
15
18/* min and max macros */ 16/* min and max macros */
19#ifndef MIN 17#ifndef MIN
20#define MIN(x, y) ((x) < (y) ? x : y) 18#define MIN(x, y) ((x) < (y) ? x : y)
@@ -36,6 +34,7 @@ static int meth_receivefrom(lua_State *L);
36static int meth_getfamily(lua_State *L); 34static int meth_getfamily(lua_State *L);
37static int meth_getsockname(lua_State *L); 35static int meth_getsockname(lua_State *L);
38static int meth_getpeername(lua_State *L); 36static int meth_getpeername(lua_State *L);
37static int meth_gettimeout(lua_State *L);
39static int meth_setsockname(lua_State *L); 38static int meth_setsockname(lua_State *L);
40static int meth_setpeername(lua_State *L); 39static int meth_setpeername(lua_State *L);
41static int meth_close(lua_State *L); 40static int meth_close(lua_State *L);
@@ -66,6 +65,7 @@ static luaL_Reg udp_methods[] = {
66 {"setpeername", meth_setpeername}, 65 {"setpeername", meth_setpeername},
67 {"setsockname", meth_setsockname}, 66 {"setsockname", meth_setsockname},
68 {"settimeout", meth_settimeout}, 67 {"settimeout", meth_settimeout},
68 {"gettimeout", meth_gettimeout},
69 {NULL, NULL} 69 {NULL, NULL}
70}; 70};
71 71
@@ -86,6 +86,8 @@ static t_opt optset[] = {
86 {"ipv6-add-membership", opt_set_ip6_add_membership}, 86 {"ipv6-add-membership", opt_set_ip6_add_membership},
87 {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, 87 {"ipv6-drop-membership", opt_set_ip6_drop_membersip},
88 {"ipv6-v6only", opt_set_ip6_v6only}, 88 {"ipv6-v6only", opt_set_ip6_v6only},
89 {"recv-buffer-size", opt_set_recv_buf_size},
90 {"send-buffer-size", opt_set_send_buf_size},
89 {NULL, NULL} 91 {NULL, NULL}
90}; 92};
91 93
@@ -102,6 +104,8 @@ static t_opt optget[] = {
102 {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, 104 {"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
103 {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, 105 {"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
104 {"ipv6-v6only", opt_get_ip6_v6only}, 106 {"ipv6-v6only", opt_get_ip6_v6only},
107 {"recv-buffer-size", opt_get_recv_buf_size},
108 {"send-buffer-size", opt_get_send_buf_size},
105 {NULL, NULL} 109 {NULL, NULL}
106}; 110};
107 111
@@ -116,8 +120,7 @@ static luaL_Reg func[] = {
116/*-------------------------------------------------------------------------*\ 120/*-------------------------------------------------------------------------*\
117* Initializes module 121* Initializes module
118\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
119int udp_open(lua_State *L) 123int udp_open(lua_State *L) {
120{
121 /* create classes */ 124 /* create classes */
122 auxiliar_newclass(L, "udp{connected}", udp_methods); 125 auxiliar_newclass(L, "udp{connected}", udp_methods);
123 auxiliar_newclass(L, "udp{unconnected}", udp_methods); 126 auxiliar_newclass(L, "udp{unconnected}", udp_methods);
@@ -128,6 +131,10 @@ int udp_open(lua_State *L)
128 auxiliar_add2group(L, "udp{unconnected}", "select{able}"); 131 auxiliar_add2group(L, "udp{unconnected}", "select{able}");
129 /* define library functions */ 132 /* define library functions */
130 luaL_setfuncs(L, func, 0); 133 luaL_setfuncs(L, func, 0);
134 /* export default UDP size */
135 lua_pushliteral(L, "_DATAGRAMSIZE");
136 lua_pushinteger(L, UDP_DATAGRAMSIZE);
137 lua_rawset(L, -3);
131 return 0; 138 return 0;
132} 139}
133 140
@@ -177,13 +184,37 @@ static int meth_sendto(lua_State *L) {
177 memset(&aihint, 0, sizeof(aihint)); 184 memset(&aihint, 0, sizeof(aihint));
178 aihint.ai_family = udp->family; 185 aihint.ai_family = udp->family;
179 aihint.ai_socktype = SOCK_DGRAM; 186 aihint.ai_socktype = SOCK_DGRAM;
180 aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; 187 aihint.ai_flags = AI_NUMERICHOST;
188#ifdef AI_NUMERICSERV
189 aihint.ai_flags |= AI_NUMERICSERV;
190#endif
181 err = getaddrinfo(ip, port, &aihint, &ai); 191 err = getaddrinfo(ip, port, &aihint, &ai);
182 if (err) { 192 if (err) {
183 lua_pushnil(L); 193 lua_pushnil(L);
184 lua_pushstring(L, gai_strerror(err)); 194 lua_pushstring(L, LUA_GAI_STRERROR(err));
185 return 2; 195 return 2;
186 } 196 }
197
198 /* create socket if on first sendto if AF_UNSPEC was set */
199 if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) {
200 struct addrinfo *ap;
201 const char *errstr = NULL;
202 for (ap = ai; ap != NULL; ap = ap->ai_next) {
203 errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0);
204 if (errstr == NULL) {
205 socket_setnonblocking(&udp->sock);
206 udp->family = ap->ai_family;
207 break;
208 }
209 }
210 if (errstr != NULL) {
211 lua_pushnil(L);
212 lua_pushstring(L, errstr);
213 freeaddrinfo(ai);
214 return 2;
215 }
216 }
217
187 timeout_markstart(tm); 218 timeout_markstart(tm);
188 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, 219 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
189 (socklen_t) ai->ai_addrlen, tm); 220 (socklen_t) ai->ai_addrlen, tm);
@@ -202,69 +233,78 @@ static int meth_sendto(lua_State *L) {
202\*-------------------------------------------------------------------------*/ 233\*-------------------------------------------------------------------------*/
203static int meth_receive(lua_State *L) { 234static int meth_receive(lua_State *L) {
204 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 235 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
205 char buffer[UDP_DATAGRAMSIZE]; 236 char buf[UDP_DATAGRAMSIZE];
206 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 237 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
238 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
207 int err; 239 int err;
208 p_timeout tm = &udp->tm; 240 p_timeout tm = &udp->tm;
209 count = MIN(count, sizeof(buffer));
210 timeout_markstart(tm); 241 timeout_markstart(tm);
211 err = socket_recv(&udp->sock, buffer, count, &got, tm); 242 if (!dgram) {
243 lua_pushnil(L);
244 lua_pushliteral(L, "out of memory");
245 return 2;
246 }
247 err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
212 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ 248 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
213 if (err == IO_CLOSED) 249 if (err != IO_DONE && err != IO_CLOSED) {
214 err = IO_DONE;
215 if (err != IO_DONE) {
216 lua_pushnil(L); 250 lua_pushnil(L);
217 lua_pushstring(L, udp_strerror(err)); 251 lua_pushstring(L, udp_strerror(err));
252 if (wanted > sizeof(buf)) free(dgram);
218 return 2; 253 return 2;
219 } 254 }
220 lua_pushlstring(L, buffer, got); 255 lua_pushlstring(L, dgram, got);
256 if (wanted > sizeof(buf)) free(dgram);
221 return 1; 257 return 1;
222} 258}
223 259
224/*-------------------------------------------------------------------------*\ 260/*-------------------------------------------------------------------------*\
225* Receives data and sender from a UDP socket 261* Receives data and sender from a UDP socket
226\*-------------------------------------------------------------------------*/ 262\*-------------------------------------------------------------------------*/
227static int meth_receivefrom(lua_State *L) 263static int meth_receivefrom(lua_State *L) {
228{
229 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); 264 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
230 char buffer[UDP_DATAGRAMSIZE]; 265 char buf[UDP_DATAGRAMSIZE];
231 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 266 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
232 int err; 267 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
233 p_timeout tm = &udp->tm;
234 struct sockaddr_storage addr; 268 struct sockaddr_storage addr;
235 socklen_t addr_len = sizeof(addr); 269 socklen_t addr_len = sizeof(addr);
236 char addrstr[INET6_ADDRSTRLEN]; 270 char addrstr[INET6_ADDRSTRLEN];
237 char portstr[6]; 271 char portstr[6];
272 int err;
273 p_timeout tm = &udp->tm;
238 timeout_markstart(tm); 274 timeout_markstart(tm);
239 count = MIN(count, sizeof(buffer)); 275 if (!dgram) {
240 err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, 276 lua_pushnil(L);
277 lua_pushliteral(L, "out of memory");
278 return 2;
279 }
280 err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
241 &addr_len, tm); 281 &addr_len, tm);
242 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ 282 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
243 if (err == IO_CLOSED) 283 if (err != IO_DONE && err != IO_CLOSED) {
244 err = IO_DONE;
245 if (err != IO_DONE) {
246 lua_pushnil(L); 284 lua_pushnil(L);
247 lua_pushstring(L, udp_strerror(err)); 285 lua_pushstring(L, udp_strerror(err));
286 if (wanted > sizeof(buf)) free(dgram);
248 return 2; 287 return 2;
249 } 288 }
250 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, 289 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
251 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); 290 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
252 if (err) { 291 if (err) {
253 lua_pushnil(L); 292 lua_pushnil(L);
254 lua_pushstring(L, gai_strerror(err)); 293 lua_pushstring(L, LUA_GAI_STRERROR(err));
294 if (wanted > sizeof(buf)) free(dgram);
255 return 2; 295 return 2;
256 } 296 }
257 lua_pushlstring(L, buffer, got); 297 lua_pushlstring(L, dgram, got);
258 lua_pushstring(L, addrstr); 298 lua_pushstring(L, addrstr);
259 lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); 299 lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
300 if (wanted > sizeof(buf)) free(dgram);
260 return 3; 301 return 3;
261} 302}
262 303
263/*-------------------------------------------------------------------------*\ 304/*-------------------------------------------------------------------------*\
264* Returns family as string 305* Returns family as string
265\*-------------------------------------------------------------------------*/ 306\*-------------------------------------------------------------------------*/
266static int meth_getfamily(lua_State *L) 307static int meth_getfamily(lua_State *L) {
267{
268 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 308 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
269 if (udp->family == AF_INET6) { 309 if (udp->family == AF_INET6) {
270 lua_pushliteral(L, "inet6"); 310 lua_pushliteral(L, "inet6");
@@ -335,6 +375,11 @@ static int meth_settimeout(lua_State *L) {
335 return timeout_meth_settimeout(L, &udp->tm); 375 return timeout_meth_settimeout(L, &udp->tm);
336} 376}
337 377
378static int meth_gettimeout(lua_State *L) {
379 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
380 return timeout_meth_gettimeout(L, &udp->tm);
381}
382
338/*-------------------------------------------------------------------------*\ 383/*-------------------------------------------------------------------------*\
339* Turns a master udp object into a client object. 384* Turns a master udp object into a client object.
340\*-------------------------------------------------------------------------*/ 385\*-------------------------------------------------------------------------*/
diff --git a/src/udp.h b/src/udp.h
index 2b831a5..07d5247 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -8,16 +8,15 @@
8* (AF_INET, SOCK_DGRAM). 8* (AF_INET, SOCK_DGRAM).
9* 9*
10* Two classes are defined: connected and unconnected. UDP objects are 10* Two classes are defined: connected and unconnected. UDP objects are
11* originally unconnected. They can be "connected" to a given address 11* originally unconnected. They can be "connected" to a given address
12* with a call to the setpeername function. The same function can be used to 12* with a call to the setpeername function. The same function can be used to
13* break the connection. 13* break the connection.
14\*=========================================================================*/ 14\*=========================================================================*/
15#include "lua.h" 15#include "luasocket.h"
16 16
17#include "timeout.h" 17#include "timeout.h"
18#include "socket.h" 18#include "socket.h"
19 19
20/* can't be larger than wsocket.c MAXCHUNK!!! */
21#define UDP_DATAGRAMSIZE 8192 20#define UDP_DATAGRAMSIZE 8192
22 21
23typedef struct t_udp_ { 22typedef struct t_udp_ {
@@ -27,6 +26,14 @@ typedef struct t_udp_ {
27} t_udp; 26} t_udp;
28typedef t_udp *p_udp; 27typedef t_udp *p_udp;
29 28
29#ifndef _WIN32
30#pragma GCC visibility push(hidden)
31#endif
32
30int udp_open(lua_State *L); 33int udp_open(lua_State *L);
31 34
35#ifndef _WIN32
36#pragma GCC visibility pop
37#endif
38
32#endif /* UDP_H */ 39#endif /* UDP_H */
diff --git a/src/unix.c b/src/unix.c
index 5bc3148..268d8b2 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -2,329 +2,68 @@
2* Unix domain socket 2* Unix domain socket
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h> 5#include "luasocket.h"
6 6
7#include "lua.h" 7#include "unixstream.h"
8#include "lauxlib.h" 8#include "unixdgram.h"
9
10#include "auxiliar.h"
11#include "socket.h"
12#include "options.h"
13#include "unix.h"
14#include <sys/un.h>
15
16/*=========================================================================*\
17* Internal function prototypes
18\*=========================================================================*/
19static int global_create(lua_State *L);
20static int meth_connect(lua_State *L);
21static int meth_listen(lua_State *L);
22static int meth_bind(lua_State *L);
23static int meth_send(lua_State *L);
24static int meth_shutdown(lua_State *L);
25static int meth_receive(lua_State *L);
26static int meth_accept(lua_State *L);
27static int meth_close(lua_State *L);
28static int meth_setoption(lua_State *L);
29static int meth_settimeout(lua_State *L);
30static int meth_getfd(lua_State *L);
31static int meth_setfd(lua_State *L);
32static int meth_dirty(lua_State *L);
33static int meth_getstats(lua_State *L);
34static int meth_setstats(lua_State *L);
35
36static const char *unix_tryconnect(p_unix un, const char *path);
37static const char *unix_trybind(p_unix un, const char *path);
38
39/* unix object methods */
40static luaL_Reg unix_methods[] = {
41 {"__gc", meth_close},
42 {"__tostring", auxiliar_tostring},
43 {"accept", meth_accept},
44 {"bind", meth_bind},
45 {"close", meth_close},
46 {"connect", meth_connect},
47 {"dirty", meth_dirty},
48 {"getfd", meth_getfd},
49 {"getstats", meth_getstats},
50 {"setstats", meth_setstats},
51 {"listen", meth_listen},
52 {"receive", meth_receive},
53 {"send", meth_send},
54 {"setfd", meth_setfd},
55 {"setoption", meth_setoption},
56 {"setpeername", meth_connect},
57 {"setsockname", meth_bind},
58 {"settimeout", meth_settimeout},
59 {"shutdown", meth_shutdown},
60 {NULL, NULL}
61};
62
63/* socket option handlers */
64static t_opt optset[] = {
65 {"keepalive", opt_set_keepalive},
66 {"reuseaddr", opt_set_reuseaddr},
67 {"linger", opt_set_linger},
68 {NULL, NULL}
69};
70 9
71/*-------------------------------------------------------------------------*\ 10/*-------------------------------------------------------------------------*\
72* Initializes module 11* Modules and functions
73\*-------------------------------------------------------------------------*/ 12\*-------------------------------------------------------------------------*/
74int luaopen_socket_unix(lua_State *L) { 13static const luaL_Reg mod[] = {
75 /* create classes */ 14 {"stream", unixstream_open},
76 auxiliar_newclass(L, "unix{master}", unix_methods); 15 {"dgram", unixdgram_open},
77 auxiliar_newclass(L, "unix{client}", unix_methods); 16 {NULL, NULL}
78 auxiliar_newclass(L, "unix{server}", unix_methods); 17};
79 /* create class groups */
80 auxiliar_add2group(L, "unix{master}", "unix{any}");
81 auxiliar_add2group(L, "unix{client}", "unix{any}");
82 auxiliar_add2group(L, "unix{server}", "unix{any}");
83 /* return the function instead of the 'socket' table */
84 lua_pushcfunction(L, global_create);
85 return 1;
86}
87
88/*=========================================================================*\
89* Lua methods
90\*=========================================================================*/
91/*-------------------------------------------------------------------------*\
92* Just call buffered IO methods
93\*-------------------------------------------------------------------------*/
94static int meth_send(lua_State *L) {
95 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
96 return buffer_meth_send(L, &un->buf);
97}
98
99static int meth_receive(lua_State *L) {
100 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
101 return buffer_meth_receive(L, &un->buf);
102}
103
104static int meth_getstats(lua_State *L) {
105 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
106 return buffer_meth_getstats(L, &un->buf);
107}
108
109static int meth_setstats(lua_State *L) {
110 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
111 return buffer_meth_setstats(L, &un->buf);
112}
113
114/*-------------------------------------------------------------------------*\
115* Just call option handler
116\*-------------------------------------------------------------------------*/
117static int meth_setoption(lua_State *L) {
118 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
119 return opt_meth_setoption(L, optset, &un->sock);
120}
121
122/*-------------------------------------------------------------------------*\
123* Select support methods
124\*-------------------------------------------------------------------------*/
125static int meth_getfd(lua_State *L) {
126 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
127 lua_pushnumber(L, (int) un->sock);
128 return 1;
129}
130
131/* this is very dangerous, but can be handy for those that are brave enough */
132static int meth_setfd(lua_State *L) {
133 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
134 un->sock = (t_socket) luaL_checknumber(L, 2);
135 return 0;
136}
137 18
138static int meth_dirty(lua_State *L) { 19static void add_alias(lua_State *L, int index, const char *name, const char *target)
139 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); 20{
140 lua_pushboolean(L, !buffer_isempty(&un->buf)); 21 lua_getfield(L, index, target);
141 return 1; 22 lua_setfield(L, index, name);
142} 23}
143 24
144/*-------------------------------------------------------------------------*\ 25static int compat_socket_unix_call(lua_State *L)
145* Waits for and returns a client object attempting connection to the 26{
146* server object 27 /* Look up socket.unix.stream in the socket.unix table (which is the first
147\*-------------------------------------------------------------------------*/ 28 * argument). */
148static int meth_accept(lua_State *L) { 29 lua_getfield(L, 1, "stream");
149 p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
150 p_timeout tm = timeout_markstart(&server->tm);
151 t_socket sock;
152 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
153 /* if successful, push client socket */
154 if (err == IO_DONE) {
155 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
156 auxiliar_setclass(L, "unix{client}", -1);
157 /* initialize structure fields */
158 socket_setnonblocking(&sock);
159 clnt->sock = sock;
160 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
161 (p_error) socket_ioerror, &clnt->sock);
162 timeout_init(&clnt->tm, -1, -1);
163 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
164 return 1;
165 } else {
166 lua_pushnil(L);
167 lua_pushstring(L, socket_strerror(err));
168 return 2;
169 }
170}
171 30
172/*-------------------------------------------------------------------------*\ 31 /* Replace the stack entry for the socket.unix table with the
173* Binds an object to an address 32 * socket.unix.stream function. */
174\*-------------------------------------------------------------------------*/ 33 lua_replace(L, 1);
175static const char *unix_trybind(p_unix un, const char *path) {
176 struct sockaddr_un local;
177 size_t len = strlen(path);
178 int err;
179 if (len >= sizeof(local.sun_path)) return "path too long";
180 memset(&local, 0, sizeof(local));
181 strcpy(local.sun_path, path);
182 local.sun_family = AF_UNIX;
183#ifdef UNIX_HAS_SUN_LEN
184 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
185 + len + 1;
186 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
187 34
188#else 35 /* Call socket.unix.stream, passing along any arguments. */
189 err = socket_bind(&un->sock, (SA *) &local, 36 int n = lua_gettop(L);
190 sizeof(local.sun_family) + len); 37 lua_call(L, n-1, LUA_MULTRET);
191#endif
192 if (err != IO_DONE) socket_destroy(&un->sock);
193 return socket_strerror(err);
194}
195 38
196static int meth_bind(lua_State *L) { 39 /* Pass along the return values from socket.unix.stream. */
197 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); 40 n = lua_gettop(L);
198 const char *path = luaL_checkstring(L, 2); 41 return n;
199 const char *err = unix_trybind(un, path);
200 if (err) {
201 lua_pushnil(L);
202 lua_pushstring(L, err);
203 return 2;
204 }
205 lua_pushnumber(L, 1);
206 return 1;
207} 42}
208 43
209/*-------------------------------------------------------------------------*\ 44/*-------------------------------------------------------------------------*\
210* Turns a master unix object into a client object. 45* Initializes module
211\*-------------------------------------------------------------------------*/ 46\*-------------------------------------------------------------------------*/
212static const char *unix_tryconnect(p_unix un, const char *path) 47LUASOCKET_API int luaopen_socket_unix(lua_State *L)
213{ 48{
214 struct sockaddr_un remote; 49 int i;
215 int err; 50 lua_newtable(L);
216 size_t len = strlen(path); 51 int socket_unix_table = lua_gettop(L);
217 if (len >= sizeof(remote.sun_path)) return "path too long";
218 memset(&remote, 0, sizeof(remote));
219 strcpy(remote.sun_path, path);
220 remote.sun_family = AF_UNIX;
221 timeout_markstart(&un->tm);
222#ifdef UNIX_HAS_SUN_LEN
223 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
224 + len + 1;
225 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
226#else
227 err = socket_connect(&un->sock, (SA *) &remote,
228 sizeof(remote.sun_family) + len, &un->tm);
229#endif
230 if (err != IO_DONE) socket_destroy(&un->sock);
231 return socket_strerror(err);
232}
233 52
234static int meth_connect(lua_State *L) 53 for (i = 0; mod[i].name; i++)
235{ 54 mod[i].func(L);
236 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
237 const char *path = luaL_checkstring(L, 2);
238 const char *err = unix_tryconnect(un, path);
239 if (err) {
240 lua_pushnil(L);
241 lua_pushstring(L, err);
242 return 2;
243 }
244 /* turn master object into a client object */
245 auxiliar_setclass(L, "unix{client}", 1);
246 lua_pushnumber(L, 1);
247 return 1;
248}
249 55
250/*-------------------------------------------------------------------------*\ 56 /* Add backwards compatibility aliases "tcp" and "udp" for the "stream" and
251* Closes socket used by object 57 * "dgram" functions. */
252\*-------------------------------------------------------------------------*/ 58 add_alias(L, socket_unix_table, "tcp", "stream");
253static int meth_close(lua_State *L) 59 add_alias(L, socket_unix_table, "udp", "dgram");
254{
255 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
256 socket_destroy(&un->sock);
257 lua_pushnumber(L, 1);
258 return 1;
259}
260 60
261/*-------------------------------------------------------------------------*\ 61 /* Add a backwards compatibility function and a metatable setup to call it
262* Puts the sockt in listen mode 62 * for the old socket.unix() interface. */
263\*-------------------------------------------------------------------------*/ 63 lua_pushcfunction(L, compat_socket_unix_call);
264static int meth_listen(lua_State *L) 64 lua_setfield(L, socket_unix_table, "__call");
265{ 65 lua_pushvalue(L, socket_unix_table);
266 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); 66 lua_setmetatable(L, socket_unix_table);
267 int backlog = (int) luaL_optnumber(L, 2, 32);
268 int err = socket_listen(&un->sock, backlog);
269 if (err != IO_DONE) {
270 lua_pushnil(L);
271 lua_pushstring(L, socket_strerror(err));
272 return 2;
273 }
274 /* turn master object into a server object */
275 auxiliar_setclass(L, "unix{server}", 1);
276 lua_pushnumber(L, 1);
277 return 1;
278}
279 67
280/*-------------------------------------------------------------------------*\
281* Shuts the connection down partially
282\*-------------------------------------------------------------------------*/
283static int meth_shutdown(lua_State *L)
284{
285 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
286 static const char* methods[] = { "receive", "send", "both", NULL };
287 p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
288 int how = luaL_checkoption(L, 2, "both", methods);
289 socket_shutdown(&tcp->sock, how);
290 lua_pushnumber(L, 1);
291 return 1; 68 return 1;
292} 69}
293
294/*-------------------------------------------------------------------------*\
295* Just call tm methods
296\*-------------------------------------------------------------------------*/
297static int meth_settimeout(lua_State *L) {
298 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
299 return timeout_meth_settimeout(L, &un->tm);
300}
301
302/*=========================================================================*\
303* Library functions
304\*=========================================================================*/
305/*-------------------------------------------------------------------------*\
306* Creates a master unix object
307\*-------------------------------------------------------------------------*/
308static int global_create(lua_State *L) {
309 t_socket sock;
310 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
311 /* try to allocate a system socket */
312 if (err == IO_DONE) {
313 /* allocate unix object */
314 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
315 /* set its type as master object */
316 auxiliar_setclass(L, "unix{master}", -1);
317 /* initialize remaining structure fields */
318 socket_setnonblocking(&sock);
319 un->sock = sock;
320 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
321 (p_error) socket_ioerror, &un->sock);
322 timeout_init(&un->tm, -1, -1);
323 buffer_init(&un->buf, &un->io, &un->tm);
324 return 1;
325 } else {
326 lua_pushnil(L);
327 lua_pushstring(L, socket_strerror(err));
328 return 2;
329 }
330}
diff --git a/src/unix.h b/src/unix.h
index 8cc7a79..c203561 100644
--- a/src/unix.h
+++ b/src/unix.h
@@ -7,16 +7,12 @@
7* This module is just an example of how to extend LuaSocket with a new 7* This module is just an example of how to extend LuaSocket with a new
8* domain. 8* domain.
9\*=========================================================================*/ 9\*=========================================================================*/
10#include "lua.h" 10#include "luasocket.h"
11 11
12#include "buffer.h" 12#include "buffer.h"
13#include "timeout.h" 13#include "timeout.h"
14#include "socket.h" 14#include "socket.h"
15 15
16#ifndef UNIX_API
17#define UNIX_API extern
18#endif
19
20typedef struct t_unix_ { 16typedef struct t_unix_ {
21 t_socket sock; 17 t_socket sock;
22 t_io io; 18 t_io io;
@@ -25,6 +21,6 @@ typedef struct t_unix_ {
25} t_unix; 21} t_unix;
26typedef t_unix *p_unix; 22typedef t_unix *p_unix;
27 23
28UNIX_API int luaopen_socket_unix(lua_State *L); 24LUASOCKET_API int luaopen_socket_unix(lua_State *L);
29 25
30#endif /* UNIX_H */ 26#endif /* UNIX_H */
diff --git a/src/unixdgram.c b/src/unixdgram.c
new file mode 100644
index 0000000..69093d7
--- /dev/null
+++ b/src/unixdgram.c
@@ -0,0 +1,405 @@
1/*=========================================================================*\
2* Unix domain socket dgram submodule
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6
7#include "auxiliar.h"
8#include "socket.h"
9#include "options.h"
10#include "unix.h"
11
12#include <string.h>
13#include <stdlib.h>
14
15#include <sys/un.h>
16
17#define UNIXDGRAM_DATAGRAMSIZE 8192
18
19/* provide a SUN_LEN macro if sys/un.h doesn't (e.g. Android) */
20#ifndef SUN_LEN
21#define SUN_LEN(ptr) \
22 ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
23 + strlen ((ptr)->sun_path))
24#endif
25
26/*=========================================================================*\
27* Internal function prototypes
28\*=========================================================================*/
29static int global_create(lua_State *L);
30static int meth_connect(lua_State *L);
31static int meth_bind(lua_State *L);
32static int meth_send(lua_State *L);
33static int meth_receive(lua_State *L);
34static int meth_close(lua_State *L);
35static int meth_setoption(lua_State *L);
36static int meth_settimeout(lua_State *L);
37static int meth_gettimeout(lua_State *L);
38static int meth_getfd(lua_State *L);
39static int meth_setfd(lua_State *L);
40static int meth_dirty(lua_State *L);
41static int meth_receivefrom(lua_State *L);
42static int meth_sendto(lua_State *L);
43static int meth_getsockname(lua_State *L);
44
45static const char *unixdgram_tryconnect(p_unix un, const char *path);
46static const char *unixdgram_trybind(p_unix un, const char *path);
47
48/* unixdgram object methods */
49static luaL_Reg unixdgram_methods[] = {
50 {"__gc", meth_close},
51 {"__tostring", auxiliar_tostring},
52 {"bind", meth_bind},
53 {"close", meth_close},
54 {"connect", meth_connect},
55 {"dirty", meth_dirty},
56 {"getfd", meth_getfd},
57 {"send", meth_send},
58 {"sendto", meth_sendto},
59 {"receive", meth_receive},
60 {"receivefrom", meth_receivefrom},
61 {"setfd", meth_setfd},
62 {"setoption", meth_setoption},
63 {"setpeername", meth_connect},
64 {"setsockname", meth_bind},
65 {"getsockname", meth_getsockname},
66 {"settimeout", meth_settimeout},
67 {"gettimeout", meth_gettimeout},
68 {NULL, NULL}
69};
70
71/* socket option handlers */
72static t_opt optset[] = {
73 {"reuseaddr", opt_set_reuseaddr},
74 {NULL, NULL}
75};
76
77/* functions in library namespace */
78static luaL_Reg func[] = {
79 {"dgram", global_create},
80 {NULL, NULL}
81};
82
83/*-------------------------------------------------------------------------*\
84* Initializes module
85\*-------------------------------------------------------------------------*/
86int unixdgram_open(lua_State *L)
87{
88 /* create classes */
89 auxiliar_newclass(L, "unixdgram{connected}", unixdgram_methods);
90 auxiliar_newclass(L, "unixdgram{unconnected}", unixdgram_methods);
91 /* create class groups */
92 auxiliar_add2group(L, "unixdgram{connected}", "unixdgram{any}");
93 auxiliar_add2group(L, "unixdgram{unconnected}", "unixdgram{any}");
94 auxiliar_add2group(L, "unixdgram{connected}", "select{able}");
95 auxiliar_add2group(L, "unixdgram{unconnected}", "select{able}");
96
97 luaL_setfuncs(L, func, 0);
98 return 0;
99}
100
101/*=========================================================================*\
102* Lua methods
103\*=========================================================================*/
104static const char *unixdgram_strerror(int err)
105{
106 /* a 'closed' error on an unconnected means the target address was not
107 * accepted by the transport layer */
108 if (err == IO_CLOSED) return "refused";
109 else return socket_strerror(err);
110}
111
112static int meth_send(lua_State *L)
113{
114 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{connected}", 1);
115 p_timeout tm = &un->tm;
116 size_t count, sent = 0;
117 int err;
118 const char *data = luaL_checklstring(L, 2, &count);
119 timeout_markstart(tm);
120 err = socket_send(&un->sock, data, count, &sent, tm);
121 if (err != IO_DONE) {
122 lua_pushnil(L);
123 lua_pushstring(L, unixdgram_strerror(err));
124 return 2;
125 }
126 lua_pushnumber(L, (lua_Number) sent);
127 return 1;
128}
129
130/*-------------------------------------------------------------------------*\
131* Send data through unconnected unixdgram socket
132\*-------------------------------------------------------------------------*/
133static int meth_sendto(lua_State *L)
134{
135 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
136 size_t count, sent = 0;
137 const char *data = luaL_checklstring(L, 2, &count);
138 const char *path = luaL_checkstring(L, 3);
139 p_timeout tm = &un->tm;
140 int err;
141 struct sockaddr_un remote;
142 size_t len = strlen(path);
143
144 if (len >= sizeof(remote.sun_path)) {
145 lua_pushnil(L);
146 lua_pushstring(L, "path too long");
147 return 2;
148 }
149
150 memset(&remote, 0, sizeof(remote));
151 strcpy(remote.sun_path, path);
152 remote.sun_family = AF_UNIX;
153 timeout_markstart(tm);
154#ifdef UNIX_HAS_SUN_LEN
155 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
156 + len + 1;
157 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm);
158#else
159 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote,
160 sizeof(remote.sun_family) + len, tm);
161#endif
162 if (err != IO_DONE) {
163 lua_pushnil(L);
164 lua_pushstring(L, unixdgram_strerror(err));
165 return 2;
166 }
167 lua_pushnumber(L, (lua_Number) sent);
168 return 1;
169}
170
171static int meth_receive(lua_State *L) {
172 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
173 char buf[UNIXDGRAM_DATAGRAMSIZE];
174 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
175 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
176 int err;
177 p_timeout tm = &un->tm;
178 timeout_markstart(tm);
179 if (!dgram) {
180 lua_pushnil(L);
181 lua_pushliteral(L, "out of memory");
182 return 2;
183 }
184 err = socket_recv(&un->sock, dgram, wanted, &got, tm);
185 /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
186 if (err != IO_DONE && err != IO_CLOSED) {
187 lua_pushnil(L);
188 lua_pushstring(L, unixdgram_strerror(err));
189 if (wanted > sizeof(buf)) free(dgram);
190 return 2;
191 }
192 lua_pushlstring(L, dgram, got);
193 if (wanted > sizeof(buf)) free(dgram);
194 return 1;
195}
196
197/*-------------------------------------------------------------------------*\
198* Receives data and sender from a DGRAM socket
199\*-------------------------------------------------------------------------*/
200static int meth_receivefrom(lua_State *L) {
201 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
202 char buf[UNIXDGRAM_DATAGRAMSIZE];
203 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
204 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
205 struct sockaddr_un addr;
206 socklen_t addr_len = sizeof(addr);
207 int err;
208 p_timeout tm = &un->tm;
209 timeout_markstart(tm);
210 if (!dgram) {
211 lua_pushnil(L);
212 lua_pushliteral(L, "out of memory");
213 return 2;
214 }
215 addr.sun_path[0] = '\0';
216 err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr,
217 &addr_len, tm);
218 /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */
219 if (err != IO_DONE && err != IO_CLOSED) {
220 lua_pushnil(L);
221 lua_pushstring(L, unixdgram_strerror(err));
222 if (wanted > sizeof(buf)) free(dgram);
223 return 2;
224 }
225
226 lua_pushlstring(L, dgram, got);
227 /* the path may be empty, when client send without bind */
228 lua_pushstring(L, addr.sun_path);
229 if (wanted > sizeof(buf)) free(dgram);
230 return 2;
231}
232
233/*-------------------------------------------------------------------------*\
234* Just call option handler
235\*-------------------------------------------------------------------------*/
236static int meth_setoption(lua_State *L) {
237 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
238 return opt_meth_setoption(L, optset, &un->sock);
239}
240
241/*-------------------------------------------------------------------------*\
242* Select support methods
243\*-------------------------------------------------------------------------*/
244static int meth_getfd(lua_State *L) {
245 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
246 lua_pushnumber(L, (int) un->sock);
247 return 1;
248}
249
250/* this is very dangerous, but can be handy for those that are brave enough */
251static int meth_setfd(lua_State *L) {
252 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
253 un->sock = (t_socket) luaL_checknumber(L, 2);
254 return 0;
255}
256
257static int meth_dirty(lua_State *L) {
258 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
259 (void) un;
260 lua_pushboolean(L, 0);
261 return 1;
262}
263
264/*-------------------------------------------------------------------------*\
265* Binds an object to an address
266\*-------------------------------------------------------------------------*/
267static const char *unixdgram_trybind(p_unix un, const char *path) {
268 struct sockaddr_un local;
269 size_t len = strlen(path);
270 if (len >= sizeof(local.sun_path)) return "path too long";
271 memset(&local, 0, sizeof(local));
272 strcpy(local.sun_path, path);
273 local.sun_family = AF_UNIX;
274 size_t addrlen = SUN_LEN(&local);
275#ifdef UNIX_HAS_SUN_LEN
276 local.sun_len = addrlen + 1;
277#endif
278 int err = socket_bind(&un->sock, (SA *) &local, addrlen);
279 if (err != IO_DONE) socket_destroy(&un->sock);
280 return socket_strerror(err);
281}
282
283static int meth_bind(lua_State *L)
284{
285 p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1);
286 const char *path = luaL_checkstring(L, 2);
287 const char *err = unixdgram_trybind(un, path);
288 if (err) {
289 lua_pushnil(L);
290 lua_pushstring(L, err);
291 return 2;
292 }
293 lua_pushnumber(L, 1);
294 return 1;
295}
296
297static int meth_getsockname(lua_State *L)
298{
299 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
300 struct sockaddr_un peer = {0};
301 socklen_t peer_len = sizeof(peer);
302
303 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
304 lua_pushnil(L);
305 lua_pushstring(L, socket_strerror(errno));
306 return 2;
307 }
308
309 lua_pushstring(L, peer.sun_path);
310 return 1;
311}
312
313/*-------------------------------------------------------------------------*\
314* Turns a master unixdgram object into a client object.
315\*-------------------------------------------------------------------------*/
316static const char *unixdgram_tryconnect(p_unix un, const char *path)
317{
318 struct sockaddr_un remote;
319 size_t len = strlen(path);
320 if (len >= sizeof(remote.sun_path)) return "path too long";
321 memset(&remote, 0, sizeof(remote));
322 strcpy(remote.sun_path, path);
323 remote.sun_family = AF_UNIX;
324 timeout_markstart(&un->tm);
325 size_t addrlen = SUN_LEN(&remote);
326#ifdef UNIX_HAS_SUN_LEN
327 remote.sun_len = addrlen + 1;
328#endif
329 int err = socket_connect(&un->sock, (SA *) &remote, addrlen, &un->tm);
330 if (err != IO_DONE) socket_destroy(&un->sock);
331 return socket_strerror(err);
332}
333
334static int meth_connect(lua_State *L)
335{
336 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
337 const char *path = luaL_checkstring(L, 2);
338 const char *err = unixdgram_tryconnect(un, path);
339 if (err) {
340 lua_pushnil(L);
341 lua_pushstring(L, err);
342 return 2;
343 }
344 /* turn unconnected object into a connected object */
345 auxiliar_setclass(L, "unixdgram{connected}", 1);
346 lua_pushnumber(L, 1);
347 return 1;
348}
349
350/*-------------------------------------------------------------------------*\
351* Closes socket used by object
352\*-------------------------------------------------------------------------*/
353static int meth_close(lua_State *L)
354{
355 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
356 socket_destroy(&un->sock);
357 lua_pushnumber(L, 1);
358 return 1;
359}
360
361/*-------------------------------------------------------------------------*\
362* Just call tm methods
363\*-------------------------------------------------------------------------*/
364static int meth_settimeout(lua_State *L)
365{
366 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
367 return timeout_meth_settimeout(L, &un->tm);
368}
369
370static int meth_gettimeout(lua_State *L)
371{
372 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1);
373 return timeout_meth_gettimeout(L, &un->tm);
374}
375
376/*=========================================================================*\
377* Library functions
378\*=========================================================================*/
379/*-------------------------------------------------------------------------*\
380* Creates a master unixdgram object
381\*-------------------------------------------------------------------------*/
382static int global_create(lua_State *L)
383{
384 t_socket sock;
385 int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0);
386 /* try to allocate a system socket */
387 if (err == IO_DONE) {
388 /* allocate unixdgram object */
389 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
390 /* set its type as master object */
391 auxiliar_setclass(L, "unixdgram{unconnected}", -1);
392 /* initialize remaining structure fields */
393 socket_setnonblocking(&sock);
394 un->sock = sock;
395 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
396 (p_error) socket_ioerror, &un->sock);
397 timeout_init(&un->tm, -1, -1);
398 buffer_init(&un->buf, &un->io, &un->tm);
399 return 1;
400 } else {
401 lua_pushnil(L);
402 lua_pushstring(L, socket_strerror(err));
403 return 2;
404 }
405}
diff --git a/src/unixdgram.h b/src/unixdgram.h
new file mode 100644
index 0000000..a1a0166
--- /dev/null
+++ b/src/unixdgram.h
@@ -0,0 +1,28 @@
1#ifndef UNIXDGRAM_H
2#define UNIXDGRAM_H
3/*=========================================================================*\
4* DGRAM object
5* LuaSocket toolkit
6*
7* The dgram.h module provides LuaSocket with support for DGRAM protocol
8* (AF_INET, SOCK_DGRAM).
9*
10* Two classes are defined: connected and unconnected. DGRAM objects are
11* originally unconnected. They can be "connected" to a given address
12* with a call to the setpeername function. The same function can be used to
13* break the connection.
14\*=========================================================================*/
15
16#include "unix.h"
17
18#ifndef _WIN32
19#pragma GCC visibility push(hidden)
20#endif
21
22int unixdgram_open(lua_State *L);
23
24#ifndef _WIN32
25#pragma GCC visibility pop
26#endif
27
28#endif /* UNIXDGRAM_H */
diff --git a/src/unixstream.c b/src/unixstream.c
new file mode 100644
index 0000000..02aced9
--- /dev/null
+++ b/src/unixstream.c
@@ -0,0 +1,355 @@
1/*=========================================================================*\
2* Unix domain socket stream sub module
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6
7#include "auxiliar.h"
8#include "socket.h"
9#include "options.h"
10#include "unixstream.h"
11
12#include <string.h>
13#include <sys/un.h>
14
15/*=========================================================================*\
16* Internal function prototypes
17\*=========================================================================*/
18static int global_create(lua_State *L);
19static int meth_connect(lua_State *L);
20static int meth_listen(lua_State *L);
21static int meth_bind(lua_State *L);
22static int meth_send(lua_State *L);
23static int meth_shutdown(lua_State *L);
24static int meth_receive(lua_State *L);
25static int meth_accept(lua_State *L);
26static int meth_close(lua_State *L);
27static int meth_setoption(lua_State *L);
28static int meth_settimeout(lua_State *L);
29static int meth_getfd(lua_State *L);
30static int meth_setfd(lua_State *L);
31static int meth_dirty(lua_State *L);
32static int meth_getstats(lua_State *L);
33static int meth_setstats(lua_State *L);
34static int meth_getsockname(lua_State *L);
35
36static const char *unixstream_tryconnect(p_unix un, const char *path);
37static const char *unixstream_trybind(p_unix un, const char *path);
38
39/* unixstream object methods */
40static luaL_Reg unixstream_methods[] = {
41 {"__gc", meth_close},
42 {"__tostring", auxiliar_tostring},
43 {"accept", meth_accept},
44 {"bind", meth_bind},
45 {"close", meth_close},
46 {"connect", meth_connect},
47 {"dirty", meth_dirty},
48 {"getfd", meth_getfd},
49 {"getstats", meth_getstats},
50 {"setstats", meth_setstats},
51 {"listen", meth_listen},
52 {"receive", meth_receive},
53 {"send", meth_send},
54 {"setfd", meth_setfd},
55 {"setoption", meth_setoption},
56 {"setpeername", meth_connect},
57 {"setsockname", meth_bind},
58 {"getsockname", meth_getsockname},
59 {"settimeout", meth_settimeout},
60 {"shutdown", meth_shutdown},
61 {NULL, NULL}
62};
63
64/* socket option handlers */
65static t_opt optset[] = {
66 {"keepalive", opt_set_keepalive},
67 {"reuseaddr", opt_set_reuseaddr},
68 {"linger", opt_set_linger},
69 {NULL, NULL}
70};
71
72/* functions in library namespace */
73static luaL_Reg func[] = {
74 {"stream", global_create},
75 {NULL, NULL}
76};
77
78/*-------------------------------------------------------------------------*\
79* Initializes module
80\*-------------------------------------------------------------------------*/
81int unixstream_open(lua_State *L)
82{
83 /* create classes */
84 auxiliar_newclass(L, "unixstream{master}", unixstream_methods);
85 auxiliar_newclass(L, "unixstream{client}", unixstream_methods);
86 auxiliar_newclass(L, "unixstream{server}", unixstream_methods);
87
88 /* create class groups */
89 auxiliar_add2group(L, "unixstream{master}", "unixstream{any}");
90 auxiliar_add2group(L, "unixstream{client}", "unixstream{any}");
91 auxiliar_add2group(L, "unixstream{server}", "unixstream{any}");
92
93 luaL_setfuncs(L, func, 0);
94 return 0;
95}
96
97/*=========================================================================*\
98* Lua methods
99\*=========================================================================*/
100/*-------------------------------------------------------------------------*\
101* Just call buffered IO methods
102\*-------------------------------------------------------------------------*/
103static int meth_send(lua_State *L) {
104 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
105 return buffer_meth_send(L, &un->buf);
106}
107
108static int meth_receive(lua_State *L) {
109 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
110 return buffer_meth_receive(L, &un->buf);
111}
112
113static int meth_getstats(lua_State *L) {
114 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
115 return buffer_meth_getstats(L, &un->buf);
116}
117
118static int meth_setstats(lua_State *L) {
119 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
120 return buffer_meth_setstats(L, &un->buf);
121}
122
123/*-------------------------------------------------------------------------*\
124* Just call option handler
125\*-------------------------------------------------------------------------*/
126static int meth_setoption(lua_State *L) {
127 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
128 return opt_meth_setoption(L, optset, &un->sock);
129}
130
131/*-------------------------------------------------------------------------*\
132* Select support methods
133\*-------------------------------------------------------------------------*/
134static int meth_getfd(lua_State *L) {
135 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
136 lua_pushnumber(L, (int) un->sock);
137 return 1;
138}
139
140/* this is very dangerous, but can be handy for those that are brave enough */
141static int meth_setfd(lua_State *L) {
142 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
143 un->sock = (t_socket) luaL_checknumber(L, 2);
144 return 0;
145}
146
147static int meth_dirty(lua_State *L) {
148 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
149 lua_pushboolean(L, !buffer_isempty(&un->buf));
150 return 1;
151}
152
153/*-------------------------------------------------------------------------*\
154* Waits for and returns a client object attempting connection to the
155* server object
156\*-------------------------------------------------------------------------*/
157static int meth_accept(lua_State *L) {
158 p_unix server = (p_unix) auxiliar_checkclass(L, "unixstream{server}", 1);
159 p_timeout tm = timeout_markstart(&server->tm);
160 t_socket sock;
161 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
162 /* if successful, push client socket */
163 if (err == IO_DONE) {
164 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
165 auxiliar_setclass(L, "unixstream{client}", -1);
166 /* initialize structure fields */
167 socket_setnonblocking(&sock);
168 clnt->sock = sock;
169 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
170 (p_error) socket_ioerror, &clnt->sock);
171 timeout_init(&clnt->tm, -1, -1);
172 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
173 return 1;
174 } else {
175 lua_pushnil(L);
176 lua_pushstring(L, socket_strerror(err));
177 return 2;
178 }
179}
180
181/*-------------------------------------------------------------------------*\
182* Binds an object to an address
183\*-------------------------------------------------------------------------*/
184static const char *unixstream_trybind(p_unix un, const char *path) {
185 struct sockaddr_un local;
186 size_t len = strlen(path);
187 int err;
188 if (len >= sizeof(local.sun_path)) return "path too long";
189 memset(&local, 0, sizeof(local));
190 strcpy(local.sun_path, path);
191 local.sun_family = AF_UNIX;
192#ifdef UNIX_HAS_SUN_LEN
193 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
194 + len + 1;
195 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
196
197#else
198 err = socket_bind(&un->sock, (SA *) &local,
199 sizeof(local.sun_family) + len);
200#endif
201 if (err != IO_DONE) socket_destroy(&un->sock);
202 return socket_strerror(err);
203}
204
205static int meth_bind(lua_State *L) {
206 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
207 const char *path = luaL_checkstring(L, 2);
208 const char *err = unixstream_trybind(un, path);
209 if (err) {
210 lua_pushnil(L);
211 lua_pushstring(L, err);
212 return 2;
213 }
214 lua_pushnumber(L, 1);
215 return 1;
216}
217
218static int meth_getsockname(lua_State *L)
219{
220 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
221 struct sockaddr_un peer = {0};
222 socklen_t peer_len = sizeof(peer);
223
224 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
225 lua_pushnil(L);
226 lua_pushstring(L, socket_strerror(errno));
227 return 2;
228 }
229
230 lua_pushstring(L, peer.sun_path);
231 return 1;
232}
233
234/*-------------------------------------------------------------------------*\
235* Turns a master unixstream object into a client object.
236\*-------------------------------------------------------------------------*/
237static const char *unixstream_tryconnect(p_unix un, const char *path)
238{
239 struct sockaddr_un remote;
240 int err;
241 size_t len = strlen(path);
242 if (len >= sizeof(remote.sun_path)) return "path too long";
243 memset(&remote, 0, sizeof(remote));
244 strcpy(remote.sun_path, path);
245 remote.sun_family = AF_UNIX;
246 timeout_markstart(&un->tm);
247#ifdef UNIX_HAS_SUN_LEN
248 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
249 + len + 1;
250 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
251#else
252 err = socket_connect(&un->sock, (SA *) &remote,
253 sizeof(remote.sun_family) + len, &un->tm);
254#endif
255 if (err != IO_DONE) socket_destroy(&un->sock);
256 return socket_strerror(err);
257}
258
259static int meth_connect(lua_State *L)
260{
261 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
262 const char *path = luaL_checkstring(L, 2);
263 const char *err = unixstream_tryconnect(un, path);
264 if (err) {
265 lua_pushnil(L);
266 lua_pushstring(L, err);
267 return 2;
268 }
269 /* turn master object into a client object */
270 auxiliar_setclass(L, "unixstream{client}", 1);
271 lua_pushnumber(L, 1);
272 return 1;
273}
274
275/*-------------------------------------------------------------------------*\
276* Closes socket used by object
277\*-------------------------------------------------------------------------*/
278static int meth_close(lua_State *L)
279{
280 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
281 socket_destroy(&un->sock);
282 lua_pushnumber(L, 1);
283 return 1;
284}
285
286/*-------------------------------------------------------------------------*\
287* Puts the sockt in listen mode
288\*-------------------------------------------------------------------------*/
289static int meth_listen(lua_State *L)
290{
291 p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1);
292 int backlog = (int) luaL_optnumber(L, 2, 32);
293 int err = socket_listen(&un->sock, backlog);
294 if (err != IO_DONE) {
295 lua_pushnil(L);
296 lua_pushstring(L, socket_strerror(err));
297 return 2;
298 }
299 /* turn master object into a server object */
300 auxiliar_setclass(L, "unixstream{server}", 1);
301 lua_pushnumber(L, 1);
302 return 1;
303}
304
305/*-------------------------------------------------------------------------*\
306* Shuts the connection down partially
307\*-------------------------------------------------------------------------*/
308static int meth_shutdown(lua_State *L)
309{
310 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
311 static const char* methods[] = { "receive", "send", "both", NULL };
312 p_unix stream = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1);
313 int how = luaL_checkoption(L, 2, "both", methods);
314 socket_shutdown(&stream->sock, how);
315 lua_pushnumber(L, 1);
316 return 1;
317}
318
319/*-------------------------------------------------------------------------*\
320* Just call tm methods
321\*-------------------------------------------------------------------------*/
322static int meth_settimeout(lua_State *L) {
323 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1);
324 return timeout_meth_settimeout(L, &un->tm);
325}
326
327/*=========================================================================*\
328* Library functions
329\*=========================================================================*/
330/*-------------------------------------------------------------------------*\
331* Creates a master unixstream object
332\*-------------------------------------------------------------------------*/
333static int global_create(lua_State *L) {
334 t_socket sock;
335 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
336 /* try to allocate a system socket */
337 if (err == IO_DONE) {
338 /* allocate unixstream object */
339 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
340 /* set its type as master object */
341 auxiliar_setclass(L, "unixstream{master}", -1);
342 /* initialize remaining structure fields */
343 socket_setnonblocking(&sock);
344 un->sock = sock;
345 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
346 (p_error) socket_ioerror, &un->sock);
347 timeout_init(&un->tm, -1, -1);
348 buffer_init(&un->buf, &un->io, &un->tm);
349 return 1;
350 } else {
351 lua_pushnil(L);
352 lua_pushstring(L, socket_strerror(err));
353 return 2;
354 }
355}
diff --git a/src/unixstream.h b/src/unixstream.h
new file mode 100644
index 0000000..7916aff
--- /dev/null
+++ b/src/unixstream.h
@@ -0,0 +1,29 @@
1#ifndef UNIXSTREAM_H
2#define UNIXSTREAM_H
3/*=========================================================================*\
4* UNIX STREAM object
5* LuaSocket toolkit
6*
7* The unixstream.h module is basicly a glue that puts together modules buffer.h,
8* timeout.h socket.h and inet.h to provide the LuaSocket UNIX STREAM (AF_UNIX,
9* SOCK_STREAM) support.
10*
11* Three classes are defined: master, client and server. The master class is
12* a newly created unixstream object, that has not been bound or connected. Server
13* objects are unixstream objects bound to some local address. Client objects are
14* unixstream objects either connected to some address or returned by the accept
15* method of a server object.
16\*=========================================================================*/
17#include "unix.h"
18
19#ifndef _WIN32
20#pragma GCC visibility push(hidden)
21#endif
22
23int unixstream_open(lua_State *L);
24
25#ifndef _WIN32
26#pragma GCC visibility pop
27#endif
28
29#endif /* UNIXSTREAM_H */
diff --git a/src/url.lua b/src/url.lua
index 7809535..8e0dc5c 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -49,7 +49,7 @@ local function make_set(t)
49 return s 49 return s
50end 50end
51 51
52-- these are allowed withing a path segment, along with alphanum 52-- these are allowed within a path segment, along with alphanum
53-- other characters must be escaped 53-- other characters must be escaped
54local segment_set = make_set { 54local segment_set = make_set {
55 "-", "_", ".", "!", "~", "*", "'", "(", 55 "-", "_", ".", "!", "~", "*", "'", "(",
@@ -59,16 +59,16 @@ local segment_set = make_set {
59local function protect_segment(s) 59local function protect_segment(s)
60 return string.gsub(s, "([^A-Za-z0-9_])", function (c) 60 return string.gsub(s, "([^A-Za-z0-9_])", function (c)
61 if segment_set[c] then return c 61 if segment_set[c] then return c
62 else return string.format("%%%02x", string.byte(c)) end 62 else return string.format("%%%02X", string.byte(c)) end
63 end) 63 end)
64end 64end
65 65
66----------------------------------------------------------------------------- 66-----------------------------------------------------------------------------
67-- Encodes a string into its escaped hexadecimal representation 67-- Unencodes a escaped hexadecimal string into its binary representation
68-- Input 68-- Input
69-- s: binary string to be encoded 69-- s: escaped hexadecimal string to be unencoded
70-- Returns 70-- Returns
71-- escaped representation of string binary 71-- unescaped binary representation of escaped hexadecimal binary
72----------------------------------------------------------------------------- 72-----------------------------------------------------------------------------
73function _M.unescape(s) 73function _M.unescape(s)
74 return (string.gsub(s, "%%(%x%x)", function(hex) 74 return (string.gsub(s, "%%(%x%x)", function(hex)
@@ -77,6 +77,34 @@ function _M.unescape(s)
77end 77end
78 78
79----------------------------------------------------------------------------- 79-----------------------------------------------------------------------------
80-- Removes '..' and '.' components appropriately from a path.
81-- Input
82-- path
83-- Returns
84-- dot-normalized path
85local function remove_dot_components(path)
86 local marker = string.char(1)
87 repeat
88 local was = path
89 path = path:gsub('//', '/'..marker..'/', 1)
90 until path == was
91 repeat
92 local was = path
93 path = path:gsub('/%./', '/', 1)
94 until path == was
95 repeat
96 local was = path
97 path = path:gsub('[^/]+/%.%./([^/]+)', '%1', 1)
98 until path == was
99 path = path:gsub('[^/]+/%.%./*$', '')
100 path = path:gsub('/%.%.$', '/')
101 path = path:gsub('/%.$', '/')
102 path = path:gsub('^/%.%./', '/')
103 path = path:gsub(marker, '')
104 return path
105end
106
107-----------------------------------------------------------------------------
80-- Builds a path from a base path and a relative path 108-- Builds a path from a base path and a relative path
81-- Input 109-- Input
82-- base_path 110-- base_path
@@ -85,23 +113,12 @@ end
85-- corresponding absolute path 113-- corresponding absolute path
86----------------------------------------------------------------------------- 114-----------------------------------------------------------------------------
87local function absolute_path(base_path, relative_path) 115local function absolute_path(base_path, relative_path)
88 if string.sub(relative_path, 1, 1) == "/" then return relative_path end 116 if string.sub(relative_path, 1, 1) == "/" then
89 local path = string.gsub(base_path, "[^/]*$", "") 117 return remove_dot_components(relative_path) end
90 path = path .. relative_path 118 base_path = base_path:gsub("[^/]*$", "")
91 path = string.gsub(path, "([^/]*%./)", function (s) 119 if not base_path:find'/$' then base_path = base_path .. '/' end
92 if s ~= "./" then return s else return "" end 120 local path = base_path .. relative_path
93 end) 121 path = remove_dot_components(path)
94 path = string.gsub(path, "/%.$", "/")
95 local reduced
96 while reduced ~= path do
97 reduced = path
98 path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
99 if s ~= "../../" then return "" else return s end
100 end)
101 end
102 path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
103 if s ~= "../.." then return "" else return s end
104 end)
105 return path 122 return path
106end 123end
107 124
@@ -131,11 +148,6 @@ function _M.parse(url, default)
131 if not url or url == "" then return nil, "invalid url" end 148 if not url or url == "" then return nil, "invalid url" end
132 -- remove whitespace 149 -- remove whitespace
133 -- url = string.gsub(url, "%s", "") 150 -- url = string.gsub(url, "%s", "")
134 -- get fragment
135 url = string.gsub(url, "#(.*)$", function(f)
136 parsed.fragment = f
137 return ""
138 end)
139 -- get scheme 151 -- get scheme
140 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", 152 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
141 function(s) parsed.scheme = s; return "" end) 153 function(s) parsed.scheme = s; return "" end)
@@ -144,6 +156,11 @@ function _M.parse(url, default)
144 parsed.authority = n 156 parsed.authority = n
145 return "" 157 return ""
146 end) 158 end)
159 -- get fragment
160 url = string.gsub(url, "#(.*)$", function(f)
161 parsed.fragment = f
162 return ""
163 end)
147 -- get query string 164 -- get query string
148 url = string.gsub(url, "%?(.*)", function(q) 165 url = string.gsub(url, "%?(.*)", function(q)
149 parsed.query = q 166 parsed.query = q
@@ -162,9 +179,9 @@ function _M.parse(url, default)
162 function(u) parsed.userinfo = u; return "" end) 179 function(u) parsed.userinfo = u; return "" end)
163 authority = string.gsub(authority, ":([^:%]]*)$", 180 authority = string.gsub(authority, ":([^:%]]*)$",
164 function(p) parsed.port = p; return "" end) 181 function(p) parsed.port = p; return "" end)
165 if authority ~= "" then 182 if authority ~= "" then
166 -- IPv6? 183 -- IPv6?
167 parsed.host = string.match(authority, "^%[(.+)%]$") or authority 184 parsed.host = string.match(authority, "^%[(.+)%]$") or authority
168 end 185 end
169 local userinfo = parsed.userinfo 186 local userinfo = parsed.userinfo
170 if not userinfo then return parsed end 187 if not userinfo then return parsed end
@@ -183,8 +200,9 @@ end
183-- a stringing with the corresponding URL 200-- a stringing with the corresponding URL
184----------------------------------------------------------------------------- 201-----------------------------------------------------------------------------
185function _M.build(parsed) 202function _M.build(parsed)
186 local ppath = _M.parse_path(parsed.path or "") 203 --local ppath = _M.parse_path(parsed.path or "")
187 local url = _M.build_path(ppath) 204 --local url = _M.build_path(ppath)
205 local url = parsed.path or ""
188 if parsed.params then url = url .. ";" .. parsed.params end 206 if parsed.params then url = url .. ";" .. parsed.params end
189 if parsed.query then url = url .. "?" .. parsed.query end 207 if parsed.query then url = url .. "?" .. parsed.query end
190 local authority = parsed.authority 208 local authority = parsed.authority
@@ -193,7 +211,7 @@ function _M.build(parsed)
193 if string.find(authority, ":") then -- IPv6? 211 if string.find(authority, ":") then -- IPv6?
194 authority = "[" .. authority .. "]" 212 authority = "[" .. authority .. "]"
195 end 213 end
196 if parsed.port then authority = authority .. ":" .. parsed.port end 214 if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end
197 local userinfo = parsed.userinfo 215 local userinfo = parsed.userinfo
198 if parsed.user then 216 if parsed.user then
199 userinfo = parsed.user 217 userinfo = parsed.user
@@ -219,16 +237,21 @@ end
219-- corresponding absolute url 237-- corresponding absolute url
220----------------------------------------------------------------------------- 238-----------------------------------------------------------------------------
221function _M.absolute(base_url, relative_url) 239function _M.absolute(base_url, relative_url)
240 local base_parsed
222 if base.type(base_url) == "table" then 241 if base.type(base_url) == "table" then
223 base_parsed = base_url 242 base_parsed = base_url
224 base_url = _M.build(base_parsed) 243 base_url = _M.build(base_parsed)
225 else 244 else
226 base_parsed = _M.parse(base_url) 245 base_parsed = _M.parse(base_url)
227 end 246 end
247 local result
228 local relative_parsed = _M.parse(relative_url) 248 local relative_parsed = _M.parse(relative_url)
229 if not base_parsed then return relative_url 249 if not base_parsed then
230 elseif not relative_parsed then return base_url 250 result = relative_url
231 elseif relative_parsed.scheme then return relative_url 251 elseif not relative_parsed then
252 result = base_url
253 elseif relative_parsed.scheme then
254 result = relative_url
232 else 255 else
233 relative_parsed.scheme = base_parsed.scheme 256 relative_parsed.scheme = base_parsed.scheme
234 if not relative_parsed.authority then 257 if not relative_parsed.authority then
@@ -241,13 +264,14 @@ function _M.absolute(base_url, relative_url)
241 relative_parsed.query = base_parsed.query 264 relative_parsed.query = base_parsed.query
242 end 265 end
243 end 266 end
244 else 267 else
245 relative_parsed.path = absolute_path(base_parsed.path or "", 268 relative_parsed.path = absolute_path(base_parsed.path or "",
246 relative_parsed.path) 269 relative_parsed.path)
247 end 270 end
248 end 271 end
249 return _M.build(relative_parsed) 272 result = _M.build(relative_parsed)
250 end 273 end
274 return remove_dot_components(result)
251end 275end
252 276
253----------------------------------------------------------------------------- 277-----------------------------------------------------------------------------
diff --git a/src/usocket.c b/src/usocket.c
index 8adc573..7965db6 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -6,12 +6,14 @@
6* The penalty of calling select to avoid busy-wait is only paid when 6* The penalty of calling select to avoid busy-wait is only paid when
7* the I/O call fail in the first place. 7* the I/O call fail in the first place.
8\*=========================================================================*/ 8\*=========================================================================*/
9#include <string.h> 9#include "luasocket.h"
10#include <signal.h>
11 10
12#include "socket.h" 11#include "socket.h"
13#include "pierror.h" 12#include "pierror.h"
14 13
14#include <string.h>
15#include <signal.h>
16
15/*-------------------------------------------------------------------------*\ 17/*-------------------------------------------------------------------------*\
16* Wait for readable/writable/connected socket with timeout 18* Wait for readable/writable/connected socket with timeout
17\*-------------------------------------------------------------------------*/ 19\*-------------------------------------------------------------------------*/
@@ -76,7 +78,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
76* Initializes module 78* Initializes module
77\*-------------------------------------------------------------------------*/ 79\*-------------------------------------------------------------------------*/
78int socket_open(void) { 80int socket_open(void) {
79 /* instals a handler to ignore sigpipe or it will crash us */ 81 /* installs a handler to ignore sigpipe or it will crash us */
80 signal(SIGPIPE, SIG_IGN); 82 signal(SIGPIPE, SIG_IGN);
81 return 1; 83 return 1;
82} 84}
@@ -234,7 +236,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
234 *sent = 0; 236 *sent = 0;
235 if (*ps == SOCKET_INVALID) return IO_CLOSED; 237 if (*ps == SOCKET_INVALID) return IO_CLOSED;
236 for ( ;; ) { 238 for ( ;; ) {
237 long put = (long) sendto(*ps, data, count, 0, addr, len); 239 long put = (long) sendto(*ps, data, count, 0, addr, len);
238 if (put >= 0) { 240 if (put >= 0) {
239 *sent = put; 241 *sent = put;
240 return IO_DONE; 242 return IO_DONE;
@@ -438,14 +440,15 @@ const char *socket_gaistrerror(int err) {
438 case EAI_FAMILY: return PIE_FAMILY; 440 case EAI_FAMILY: return PIE_FAMILY;
439 case EAI_MEMORY: return PIE_MEMORY; 441 case EAI_MEMORY: return PIE_MEMORY;
440 case EAI_NONAME: return PIE_NONAME; 442 case EAI_NONAME: return PIE_NONAME;
443#ifdef EAI_OVERFLOW
441 case EAI_OVERFLOW: return PIE_OVERFLOW; 444 case EAI_OVERFLOW: return PIE_OVERFLOW;
445#endif
442#ifdef EAI_PROTOCOL 446#ifdef EAI_PROTOCOL
443 case EAI_PROTOCOL: return PIE_PROTOCOL; 447 case EAI_PROTOCOL: return PIE_PROTOCOL;
444#endif 448#endif
445 case EAI_SERVICE: return PIE_SERVICE; 449 case EAI_SERVICE: return PIE_SERVICE;
446 case EAI_SOCKTYPE: return PIE_SOCKTYPE; 450 case EAI_SOCKTYPE: return PIE_SOCKTYPE;
447 case EAI_SYSTEM: return strerror(errno); 451 case EAI_SYSTEM: return strerror(errno);
448 default: return gai_strerror(err); 452 default: return LUA_GAI_STRERROR(err);
449 } 453 }
450} 454}
451
diff --git a/src/wsocket.c b/src/wsocket.c
index 8ecb0fc..6cb1e41 100644..100755
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -5,6 +5,8 @@
5* The penalty of calling select to avoid busy-wait is only paid when 5* The penalty of calling select to avoid busy-wait is only paid when
6* the I/O call fail in the first place. 6* the I/O call fail in the first place.
7\*=========================================================================*/ 7\*=========================================================================*/
8#include "luasocket.h"
9
8#include <string.h> 10#include <string.h>
9 11
10#include "socket.h" 12#include "socket.h"
@@ -131,11 +133,11 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
131 /* we wait until something happens */ 133 /* we wait until something happens */
132 err = socket_waitfd(ps, WAITFD_C, tm); 134 err = socket_waitfd(ps, WAITFD_C, tm);
133 if (err == IO_CLOSED) { 135 if (err == IO_CLOSED) {
134 int len = sizeof(err); 136 int elen = sizeof(err);
135 /* give windows time to set the error (yes, disgusting) */ 137 /* give windows time to set the error (yes, disgusting) */
136 Sleep(10); 138 Sleep(10);
137 /* find out why we failed */ 139 /* find out why we failed */
138 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); 140 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &elen);
139 /* we KNOW there was an error. if 'why' is 0, we will return 141 /* we KNOW there was an error. if 'why' is 0, we will return
140 * "unknown error", but it's not really our fault */ 142 * "unknown error", but it's not really our fault */
141 return err > 0? err: IO_UNKNOWN; 143 return err > 0? err: IO_UNKNOWN;
@@ -358,7 +360,7 @@ const char *socket_ioerror(p_socket ps, int err) {
358static const char *wstrerror(int err) { 360static const char *wstrerror(int err) {
359 switch (err) { 361 switch (err) {
360 case WSAEINTR: return "Interrupted function call"; 362 case WSAEINTR: return "Interrupted function call";
361 case WSAEACCES: return PIE_ACCESS; // "Permission denied"; 363 case WSAEACCES: return PIE_ACCESS; /* "Permission denied"; */
362 case WSAEFAULT: return "Bad address"; 364 case WSAEFAULT: return "Bad address";
363 case WSAEINVAL: return "Invalid argument"; 365 case WSAEINVAL: return "Invalid argument";
364 case WSAEMFILE: return "Too many open files"; 366 case WSAEMFILE: return "Too many open files";
@@ -371,23 +373,23 @@ static const char *wstrerror(int err) {
371 case WSAEPROTOTYPE: return "Protocol wrong type for socket"; 373 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
372 case WSAENOPROTOOPT: return "Bad protocol option"; 374 case WSAENOPROTOOPT: return "Bad protocol option";
373 case WSAEPROTONOSUPPORT: return "Protocol not supported"; 375 case WSAEPROTONOSUPPORT: return "Protocol not supported";
374 case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported"; 376 case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; /* "Socket type not supported"; */
375 case WSAEOPNOTSUPP: return "Operation not supported"; 377 case WSAEOPNOTSUPP: return "Operation not supported";
376 case WSAEPFNOSUPPORT: return "Protocol family not supported"; 378 case WSAEPFNOSUPPORT: return "Protocol family not supported";
377 case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family"; 379 case WSAEAFNOSUPPORT: return PIE_FAMILY; /* "Address family not supported by protocol family"; */
378 case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use"; 380 case WSAEADDRINUSE: return PIE_ADDRINUSE; /* "Address already in use"; */
379 case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; 381 case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
380 case WSAENETDOWN: return "Network is down"; 382 case WSAENETDOWN: return "Network is down";
381 case WSAENETUNREACH: return "Network is unreachable"; 383 case WSAENETUNREACH: return "Network is unreachable";
382 case WSAENETRESET: return "Network dropped connection on reset"; 384 case WSAENETRESET: return "Network dropped connection on reset";
383 case WSAECONNABORTED: return "Software caused connection abort"; 385 case WSAECONNABORTED: return "Software caused connection abort";
384 case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer"; 386 case WSAECONNRESET: return PIE_CONNRESET; /* "Connection reset by peer"; */
385 case WSAENOBUFS: return "No buffer space available"; 387 case WSAENOBUFS: return "No buffer space available";
386 case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected"; 388 case WSAEISCONN: return PIE_ISCONN; /* "Socket is already connected"; */
387 case WSAENOTCONN: return "Socket is not connected"; 389 case WSAENOTCONN: return "Socket is not connected";
388 case WSAESHUTDOWN: return "Cannot send after socket shutdown"; 390 case WSAESHUTDOWN: return "Cannot send after socket shutdown";
389 case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out"; 391 case WSAETIMEDOUT: return PIE_TIMEDOUT; /* "Connection timed out"; */
390 case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused"; 392 case WSAECONNREFUSED: return PIE_CONNREFUSED; /* "Connection refused"; */
391 case WSAEHOSTDOWN: return "Host is down"; 393 case WSAEHOSTDOWN: return "Host is down";
392 case WSAEHOSTUNREACH: return "No route to host"; 394 case WSAEHOSTUNREACH: return "No route to host";
393 case WSAEPROCLIM: return "Too many processes"; 395 case WSAEPROCLIM: return "Too many processes";
@@ -396,9 +398,9 @@ static const char *wstrerror(int err) {
396 case WSANOTINITIALISED: 398 case WSANOTINITIALISED:
397 return "Successful WSAStartup not yet performed"; 399 return "Successful WSAStartup not yet performed";
398 case WSAEDISCON: return "Graceful shutdown in progress"; 400 case WSAEDISCON: return "Graceful shutdown in progress";
399 case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found"; 401 case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; /* "Host not found"; */
400 case WSATRY_AGAIN: return "Nonauthoritative host not found"; 402 case WSATRY_AGAIN: return "Nonauthoritative host not found";
401 case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error"; 403 case WSANO_RECOVERY: return PIE_FAIL; /* "Nonrecoverable name lookup error"; */
402 case WSANO_DATA: return "Valid name, no data record of requested type"; 404 case WSANO_DATA: return "Valid name, no data record of requested type";
403 default: return "Unknown error"; 405 default: return "Unknown error";
404 } 406 }
@@ -427,7 +429,6 @@ const char *socket_gaistrerror(int err) {
427#ifdef EAI_SYSTEM 429#ifdef EAI_SYSTEM
428 case EAI_SYSTEM: return strerror(errno); 430 case EAI_SYSTEM: return strerror(errno);
429#endif 431#endif
430 default: return gai_strerror(err); 432 default: return LUA_GAI_STRERROR(err);
431 } 433 }
432} 434}
433