149 Commits

Author SHA1 Message Date
22cd5833fc Change link to github page. 2013-06-14 19:27:32 +08:00
19bd8baf9b Add files to distribution. 2013-06-14 19:21:27 +08:00
de58cb417a Change 2.1 to 3.0 2013-06-14 19:16:16 +08:00
bf7bc59a4d Change 2.1 to 3.0-rc1 2013-06-14 19:15:37 +08:00
ea812a755e Update NEW file and section 2013-06-14 19:12:44 +08:00
2cc51443c2 Download archive with https rather than git scheme 2013-06-13 17:35:52 +08:00
85aa5e3d9c Fix version in rockspec. 2013-06-13 17:13:14 +08:00
9ddfe92820 Fix path for rockspec in travis file. 2013-06-13 16:40:14 +08:00
c07ad19ca1 Merging moteus suggestions for rockspec and travis 2013-06-13 16:19:03 +08:00
7cad902bb7 Fix makefile and test_socket_error.lua 2013-06-12 21:45:15 +08:00
b34386ca5c Merge pull request #58 from mascarenhas/master
New rockspec that uses LuaRocks to build instead of the makefile
2013-06-12 06:38:37 -07:00
cce138c8e5 new rockspec using builtin build type 2013-06-11 17:23:50 -03:00
6e00ffd62f Changing from 2.1-rc1 to 3.0-rc1. 2013-06-11 19:10:03 +08:00
906abf29d1 Fix unix export marker. 2013-06-11 17:20:27 +08:00
bc709ac7b7 Export global table only if "module()" is defined. 2013-06-05 18:36:51 +08:00
b1d1e721d1 No need for inet_pton. 2013-06-04 16:26:49 +08:00
802567b7de Merge pull request #49 from moteus/moteus-ftp-get-2xx
Fix. recive 2xx while ftp.get cause timeout error
2013-05-30 03:02:33 -07:00
ebde49944b Unix domain tests still broken. 2013-05-30 17:59:28 +08:00
5eefc73b57 Remove warnings. Move windows specific code. 2013-05-30 16:50:28 +08:00
a233e27865 Leaving if in src/ but out of build for now. 2013-05-30 16:20:34 +08:00
00a06857c9 Fix. recive 2xx while ftp.get cause timeout error
In this example:
>Client send: MDTM test.txt
>Server response: 213 20120824120909
Because FTP server do not open new channel (2XX response)
and LuaSocket try open new channel we get timeout.

```lua
local ftp   = require "socket.ftp"
local ltn12 = require "ltn12"
local url   = require("socket.url")

local URL = "ftp://USER:TEST@127.0.0.1";
local CMD = 'MDTM test.txt';

-- get timeout
ftp.get{
  url = URL;
  command = CMD;
  sink = ltn12.sink.table{};
}

-- or we can use ftp.command
ftp.command{
  url = URL;
  command = URL,
  check = function(...)
    local status, data = ...
    return true
  end;
}
```
2013-05-30 11:01:07 +04:00
5341131cd0 Merge pull request #43 from moteus/moteus-getopt-error
Add. Allow get `error` option to socket.
2013-05-29 04:20:33 -07:00
1de617e355 Add. Allow get error option to socket. 2013-05-29 14:33:27 +04:00
b84a5f3d08 Change VC12 project to no LUA_COMPAT_MODUULE 2013-05-29 17:19:24 +08:00
79e6c4915d Export global only if LUA_COMPAT_MODULE defined. 2013-05-29 16:56:56 +08:00
5167ddaf49 Merge branch 'unstable' of git://github.com/diegonehab/luasocket into moteus-lua52 2013-05-28 14:06:18 +04:00
2d51d61688 Fix "final" bug in pton and TCP connreset handling 2013-05-28 17:27:06 +08:00
27fd725c6d Typo fixed. 2013-05-28 01:54:49 +08:00
734cc23e1f Fixed inet_pton and a new Winsock UDP bug.
inet_pton was copying the entire sockaddr_in struct,
rather than just the sin_addr field...

I am a bit unsure about the UDP fix, because it may affect
TCP as well. On UDP sockets, when a sendto fails, the next
receive/receivefrom fails with CONNRESET. I changed
sock_recv/sock_recvfrom in wsocket.c to skip the CONNRESET
from the recv/recvfrom, hoping that if the socket is TCP,
sock_waitfd will get the CONNRESET again. The tests pass,
but this should be tested more thoroughly.
2013-05-28 00:09:30 +08:00
66cd8cfcee Fix wrong usage of inet_pton. 2013-05-27 22:17:51 +08:00
056d7653f3 Link only against ws2_32.lib. 2013-05-27 21:58:41 +08:00
3d61b0fe36 Merge branch 'pkulchenko' into unstable 2013-05-27 21:17:00 +08:00
834a3cf520 Simplifying getaddrinfo treatment. 2013-05-27 21:05:48 +08:00
5e0b56b8d3 Merge branch 'moteus' of https://github.com/moteus/luasocket into moteus 2013-05-27 20:32:54 +08:00
26704061a4 Fix Visual Studio 2012 projects 2013-05-27 20:30:06 +08:00
45ff0e1775 Fix. use table.unpack in mimetest on Lua 5.2. 2013-05-27 13:11:07 +04:00
920bc97629 Build with Lua 5.2 without LUA_COMPAT_MODULE flag.
LUASOCKET_USE_GLOBAL flag enable create global variables when load socket/mime modules.
2013-05-27 12:45:09 +04:00
bd51d8c1a5 Fix. Optional IPv6 test 2013-05-27 11:26:35 +04:00
e54f78c61c Fix. setsockname fails with "*" as host.
Add. test_bind.lua
2013-05-27 11:25:31 +04:00
56dbda39ed Fix. getaddrinfo returns garbage as address on Windows.
Add. test_getaddrinfo.lua
2013-05-27 11:20:52 +04:00
fbe184f28a No need for build script: makefile target instead. 2013-05-26 21:27:18 +08:00
427220c7b1 Merge tryconnect6 into inet_tryconnect. 2013-05-26 21:26:26 +08:00
6d93fd7c8f Fix socket.connect
Previous implementation was not making sure the socket
had the same family as the addr returned by getaddrinfo.
So instead of "connection refused", we could get "invalid
argument", which was our fault.
2013-05-26 15:18:13 +08:00
22107bb9fc Check linux build. 2013-05-25 07:25:02 -03:00
5d3a78b4a6 Added my test command lines. 2013-05-25 18:10:46 +08:00
bb0b31301a Add MingW support. 2013-05-25 18:07:38 +08:00
afe0494318 Change Mac OS Lua directory 2013-05-25 15:26:12 +08:00
cbc77440c8 Merge branch 'lua52-mingw' of https://github.com/pkulchenko/luasocket into pkulchenko 2013-05-24 18:33:43 +08:00
ca48baf495 Merge pull request #37 from davidm/unstable
lpr.lua: fix invalid string escape sequence \?
2013-04-17 20:55:19 -07:00
817d47df42 lpr.lua: fix invalid string escape sequence \?
Not valid in 5.2 and luajit.
2013-04-17 23:35:56 -04:00
238b217c4f Merge pull request #29 from keplerproject/94c958871919726f2954b3d3fa9a9f8ae21124e9
Rockspec for building and installing LuaSocket 2.1 with LuaRocks
2013-04-17 19:40:14 -07:00
c28fa1d309 Merge pull request #27 from catwell/pull-noarg
fix more uses of arg
2013-04-17 19:38:21 -07:00
00435529bb Merge pull request #32 from ideka/unstable
Use the length operator (#) instead of table.getn.
2013-04-17 19:13:28 -07:00
571308a94e Updated IPV6_V6ONLY to match header files on Windows. 2013-04-09 09:25:40 -07:00
5a58786a39 Added inet_pton/inet_ntop for MinGW on Windows; compiles with Lua52. 2013-04-07 12:39:56 -07:00
56893e9dcd Use the length operator (#) instead of table.getn.
table.getn was deprecated in Lua 5.1 in favor of #, the length operator.
See: http://www.lua.org/manual/5.1/manual.html#7.2
2013-02-25 20:28:28 -02:00
94c9588719 rockspec for luasocket 2.1 unstable 2013-01-24 15:28:17 -02:00
33b4f0cfc7 remove uses of arg in the codebase 2013-01-23 19:13:32 +01:00
eea1bc04d7 fix use of arg in ltn documentation 2013-01-23 19:03:46 +01:00
d548a78e55 Cookie modifications. 2013-01-10 01:10:34 -02:00
72a5347f97 Remove warnings and fix makefile for Win32. 2012-12-11 17:43:49 -02:00
618ce43ee3 Fix socket_accept usage to depend on family. 2012-12-11 16:35:27 -02:00
66670c3541 Move Visual Studio projects to 2012. 2012-12-10 18:45:05 -02:00
9d97d39575 Fix ltn12 version. 2012-12-10 15:50:44 -02:00
a4b45edef2 Merge pull request #25 from ewmailing/unstable
Copied socket_gaistrerror implementation from usocket to wsocket to allo...
2012-12-10 09:31:13 -08:00
114080d835 Merge pull request #24 from catwell/tracking-diego
fix use of arg in ltn12
2012-12-10 09:25:21 -08:00
5c467b3954 Copied socket_gaistrerror implementation from usocket to wsocket to allow Windows version to compile because it is missing the function. EAI_OVERFLOW and EAI_SYSTEM are commented out because they don't exist on Windows. 2012-11-20 12:58:52 -08:00
ffddaf4a2e fix use of arg in ltn12 2012-09-17 23:44:04 +02:00
a402222464 Merge pull request #22 from Florob/smtp
Send SMTP AUTH LOGIN response using tp:send(). Fixes #18
2012-08-23 15:34:43 -07:00
6368caeb5a Fix udp:setpeername("*")
There seems to be a curious difference between MacOS and
Linux and I am not sure if this is documented. When you
break a "connection" on Mac OS, you only eliminate the peer
association, but the local address remains bound. On Linux,
breaking a "connection" eliminates the binding to the local
address. Have you guys ever come accross this?

Another irritating difference is that connect() returns the
error EAFNOSUPPORT on Mac OS. I am going to ignore all
errors when the reason for calling connect() is simply to
break the "connection".
2012-08-23 19:31:15 -03:00
32e7a107e2 Send SMTP AUTH LOGIN response using tp:send(). Fixes #18
tp:command() uppercases the command.
Without a command we would end up with a space in
front of the data. Therefore use send() directly here.
2012-08-07 00:01:48 +02:00
03ba06f70c Add new bug fix comment. 2012-08-01 03:34:06 -03:00
f329aae724 Fix HORRIBLE but in b64/qp code.
Bug was caught by user moteus.
Code was checking if arguments was nil after using
luaL_Buffer code, which messes with the stack.
Simple to fix, though.
2012-08-01 03:06:09 -03:00
54ffcd483f Fixed default Linux path to work with Ubuntu
Also fixed clean target to remove serial objects
2012-08-01 02:13:27 -03:00
6370b61414 Merge pull request #20 from Florob/sendto
IPv6 support for udp:sendto() and udp:receivefrom()
2012-07-31 22:04:06 -07:00
5616f3a0ae Merge pull request #15 from darkrain42/unstable
tcp: Initialize clnt->family in :accept()
2012-07-31 22:02:10 -07:00
c1bb432eff Merge pull request #14 from Zash/zash-improves-makefile
Use the install util instead of cp and mkdir
2012-07-31 22:00:03 -07:00
7503bb0ca3 Add IPv6 support to udp:receivefrom() 2012-07-18 21:05:30 +02:00
a6cf48596d Add IPv6 support to udp:sendto() 2012-07-17 19:02:20 +02:00
d777341eaf tcp: Initialize clnt->family in :accept()
Also unconditionally zero out the structs when allocated, for
good measure.
2012-05-21 19:44:08 -07:00
36461db5bb src/makefile: Use install instead of cp and mkdir. 2012-05-15 18:44:38 +02:00
c624761d32 src/makefile: Move mkdir to a variable 2012-05-15 18:27:46 +02:00
05535a19f8 Improve makefile to allow overriden variables
Before this change, it was difficult to set default
directories for different platforms that would still
work with different Lua versions.
2012-05-11 15:33:47 +08:00
399bdb7f41 Merge pull request #12 from sam-github/fix-connect6-and-do-connect-in-c
socket.connect now implemented in the C core
2012-05-10 23:16:38 -07:00
156669c28b socket.connect now implemented in the C core
This avoid socket.lua duplicating the iteration over the results
of getaddrinfo(). Some problems with the C implementation not
initializing sockets or the luasocket family have also been fixed,
and error reporting made more robust.
2012-05-10 14:14:22 -07:00
3d3e69c6e4 Merge pull request #8 from sam-github/fix-confusing-servname-reference
Reword error msg to distinguish between service and server
2012-05-08 11:52:23 -07:00
1bb586d655 Merge pull request #7 from sam-github/fix-makefiles
Rework makefiles to simplify setting and choosing build options.
2012-05-08 11:51:25 -07:00
ee7c53c3e5 Merge pull request #6 from Florob/getnameinfo
Add a getnameinfo() wrapper
2012-05-08 11:48:54 -07:00
ac59bcbeac Reword error msg to distinguish between service and server
servname is easily confused with "server name", making it seem
as if the server name couldn't be resolved.
2012-05-08 10:55:33 -07:00
c291383ce2 Rework makefiles to simplify setting and choosing build options.
Includes documentation for common build settings, reasonable
defaults, and ability to set common build options in the
environment.
2012-05-08 10:51:56 -07:00
0c3e067af1 Add a getnameinfo() wrapper
This wrapper takes a domain name or an IP as first argument
and a service name or port as second argument.
Either argument may be nil.

It returns a list of names (always only one in the IP case) and a
service name.
2012-05-05 02:13:56 +02:00
04be61f88d Test server exits gracefully at command of test client 2012-05-01 16:21:06 +08:00
af55d25675 Merge branch 'tests52' of https://github.com/Florob/luasocket into Florob-tests52 2012-05-01 16:12:16 +08:00
6de0aa54fd Update method list in tests 2012-04-29 21:03:28 +02:00
cf4d29f86d Select loadstring or load for Lua 5.1/5.2 respectively 2012-04-29 20:46:35 +02:00
46736a3355 Test method registration for IPv6 sockets 2012-04-29 20:44:15 +02:00
e86eac96fa :shutdown() errors on all invalid argument strings
It used to error only on invalid argument strings that started with 's',
'r', or 'b'.
2012-04-26 16:50:27 -07:00
30d1aae140 Added Sam's suggestion to TODO 2012-04-27 02:03:09 +08:00
c2e29537f5 Fixed getpeername/getsockname situation
- Added IPv6 support to getsockname
- Simplified getpeername implementation
- Added family to return of getsockname and getpeername
and added modification to the manual to describe
2012-04-24 00:47:30 +08:00
1acf8188cd socket.bind also tries all addresses returned by getaddrinfo. 2012-04-23 01:40:31 +08:00
966642f76a socket.connect() loops over addresses returned by getaddrinfo 2012-04-23 01:29:41 +08:00
f960b3872a Making progress toward a release
Documented headers.lua
Update copyright date everywhere
Remove RCSID from files
Move version back to 2.1 rather than 2.1.1
Fixed url package to support ipv6 hosts
Changed "domain" to "family" in tcp and udp structures
Implemented getfamily methods
2012-04-23 00:18:45 +08:00
f37e026026 First stab at documenation
Update Lua and Luasocket version in samples and in documentation
Documented ipv5_v6only default option being set
Documented tcp6 and udp6
Documented dns.getaddrinfo
Documented zero-sized datagram change?
Documented getoption
2012-04-17 01:15:26 +08:00
b3c4f46179 merged lua_typerrror.{c,h} into auxiliar.{c,h} 2012-04-16 20:41:48 +08:00
4b671f4551 Merge branch 'git-sam' into diego-sam-mwild-integration
Conflicts in options.c were just due to independent small functions
being close to each other.

unix.c in mwild was broken, it wasn't using LUASOCKET_API.

serial.c needed luaL_reg renamed, and to use LUASOCKET_API.

makefile didn't respect standard DESTDIR and prefix makefile
variables, and didn't allow LUAV variable to select lua version to build
against.

I've tested the top-level install-both target builds and installs
against both lua5.1 and lua5.2, but not done further testing.

Conflicts:
	README
	config
	gem/ltn012.tex
	makefile
	src/makefile
	src/options.c
	src/options.h
	src/tcp.c
	src/usocket.c
2012-04-11 14:18:20 -07:00
195b2a74bb On failure, exit with a message instead of blocking indefinitely. 2012-04-11 13:54:01 -07:00
38b99b80a2 Add Wurldtech note to README. 2012-04-11 13:54:01 -07:00
d1a50282a7 Correct luasocket version in v2.0.2 readme.
v2.0.2 was released with a README saying it was v2.0.1.
2012-04-11 13:54:01 -07:00
8bb542baaf Support getoption method for tcp objects. 2012-04-11 13:54:01 -07:00
0716cb868e Bounds check the argument to FD_SET
Failing to check the FD_SET argument against FD_SETSIZE causes
undefined behaviour (segfaults, for example).
2012-04-11 13:54:01 -07:00
27a3964ff7 socket_strerror() sometimes maps errno, instead of its argument
Looks like a historical bug. Its err argument is an error number, but
if it isn't using a custom error message for it, it just calls
strerror() with the errno global, effectively ignoring its argument
and returning a semi-random string.
2012-04-11 13:54:01 -07:00
db47a91d40 Fix links to home.html, they should be to index.html.
home.html doesn't exist, index.html does.
2012-04-11 13:45:59 -07:00
e716e7347b mime: Remove io dependency
This dependency was spuriously added, maybe for debug reasons,
as confirmed to me by Diego Nehab by mail.
Some systems based in Lua (e.g. Ginga) prohibit the use of
io module for security reasons, so this dependency makes
mime unusable; even worse this makes other modules, based
on mime, unusable too (e.g. html).
2012-04-11 13:45:59 -07:00
12bde801f6 Document dirty, getfd, and setfd for select and tcp. 2012-04-11 13:45:59 -07:00
3a0fd4744d Reference index was missing documented APIs, and only partially alphabetized. 2012-04-11 13:45:59 -07:00
b1f7c349b5 Add support for serial devices as socket streams on unix. 2012-04-11 13:45:59 -07:00
3b19f2a7ed testsrvr asserts when test finishes successfully.
When the test client finishes, the test server asserts with a "closed" message.
After looking carefully at this, I think the tests are running
successfully and passing. Since it appears to be a test failure, I
modified the server to allow the client to close the control connection.
2012-04-11 13:45:59 -07:00
dace50628c Utility to find how many TCP connections can be made. 2012-04-11 13:45:59 -07:00
f63d616bc0 Use poll by default for socket.connect(), instead of select().
Connect timeouts are implemented by waiting on the new socket
descriptor. When select() is used for this, it imposes an arbitrary
limit on the number of connections that can be made, usually 1024-3.
Using poll() removes this limit on the number of simultaneous TCP
connections can be made using luasocket. The previous default
implementation using select() is available by defining SOCKET_SELECT.
Note that using socket.select() always uses select(), so it isn't
possible to wait on an arbitrary number of connections at once.
2012-04-11 13:45:59 -07:00
21698c7665 Receive of zero for UDP is now possible.
Previously, receive of zero was considered to be "closed", but that
is only true for stream-based protocols, like TCP.
2012-04-11 13:45:59 -07:00
c37f71d062 Test showing failure to receive a zero-length packet. 2012-04-11 13:45:59 -07:00
51acb54760 Stop returning an error after successful send of zero length UDP packets
A zero-length send is invalid with TCP, but well defined with UDP.
udp:send"" was returning (nil,"refused"), indicating that it failed when
the packet was actually sent. The test script reproduces the bug, and
includes a tcpdump of the zero length packet being sent.
2012-04-11 13:45:59 -07:00
a8b19e5367 OS X CFLAGS definition caused silent failure to build debug version of luasocket.
The luasocket tests require LUASOCKET_DEBUG to be defined at build time,
but for OS X if COMPAT was undefined, the command line looked like
  ... -I -DLUASOCKET_DEBUG ...
so that the the macro definition was silently being treated as the
argument to -I. Result is the macro was never set, and tests would
never run. Fixed by moving -I to the (optional) definition of the
location of compat headers.
2012-04-11 13:45:59 -07:00
1f704cfb89 Add all-unix and install-unix targets which include all modules supported on unix.
Besides standard socket and mime modules, this includes unix domain
socket support.
2012-04-11 13:45:59 -07:00
826589afcd Add location of Ubuntu's lua5.1 headers to config. 2012-04-11 13:45:59 -07:00
dcb92d6268 Support the conventional DESTDIR and prefix variables
Many packaging systems rely on them, they are described here:
- http://www.gnu.org/prep/standards/standards.html#index-prefix
- http://www.gnu.org/prep/standards/standards.html#DESTDIR
2012-04-11 13:45:58 -07:00
e3e0dee639 ignore build output 2012-04-11 13:45:58 -07:00
f399ab25fc inet: Honor the strict aliasing rule 2012-04-11 13:33:35 -07:00
e81a6ff623 Conditional creation of p_timeout instance 'tm' 2012-04-11 13:33:34 -07:00
9a58252528 change localhost to loopback ip to prevent error on my mac box???? 2012-04-11 13:33:34 -07:00
51187ecc90 Updated readme version and os tested 2012-04-11 13:33:34 -07:00
c8eed36788 This is a replacement for luaL_typerror , removed from Lua 5.2, which corrects the spelling.
NOTE:
There is one failing test in.the /test/testsrvr.lua and /test/testclnt.lua combination which was present in the repo I cloned from.
2012-04-11 13:33:34 -07:00
e15ed19db6 Compiles with Lua 5.1.4 and Lua 5.2.0-beta, although the makefile needs sorting out to take maybe a version number and also the local paths need removing. 2012-04-11 13:33:34 -07:00
a984607f28 inet: return more useful errors 2012-04-11 13:33:34 -07:00
7893d9ece2 inet: refactor getpeername to allocate the struct on the stack 2012-04-11 13:33:34 -07:00
8393c76180 Fix getpeername to work with IPv6 addresses 2012-04-11 13:33:34 -07:00
594f826aa1 Add support for connecting to IPv6 hosts 2012-04-11 13:33:34 -07:00
5874d47f55 dns.getaddrinfo: Return proper error messages 2012-04-11 13:33:34 -07:00
f871a29f27 Add support for the IPV6_V6ONLY socket option defaulting to on. 2012-04-11 13:33:34 -07:00
4df1618aab Adapt socket.bind() to create a IPv4 or IPv6 depending on the address given 2012-04-11 13:33:34 -07:00
5065a2585c dns: Rename toip6() to getaddrinfo() since the old name is misleading 2012-04-11 13:33:34 -07:00
923eef1929 Rework binding IPv6 sockets by harmonizing it with the IPv4 variant 2012-04-11 13:33:34 -07:00
5c33ef9997 url.escape/url.unescape: Fix to return *only* the encoded/decoded string (thanks moodydeath) 2012-04-11 13:33:34 -07:00
908ee2cce1 Fix two crashes and add -Wshadow so that this can't happen again.
The two crashes are the s/const char *// changes in tcp.c.  The rest
is cleanup so it will build.
2012-04-11 13:33:34 -07:00
dd83e0a849 #ifdef EAI_BADHINTS and EAI_PROTOCOL which don't seem available on my system (Linux/glibc 2.11) 2012-04-11 13:33:34 -07:00
2778766d67 Preliminary IPv6 support for v2.1 2012-04-11 13:25:11 -07:00
3a8ba90dfb Saving before big changes to support IPv6. 2011-05-25 20:57:22 +00:00
bce60be30f Decent makefiles! 2009-05-27 09:31:38 +00:00
d1a72435d5 New release. 2007-10-13 23:55:20 +00:00
128 changed files with 5482 additions and 2396 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
*.o
*.so
*.so.*
*.obj
*.lib
*.dll*
*.user
*.sdf
Lua.props
Debug
Release
*.manifest
*.swp
*.suo
x64

54
.travis.yml Normal file
View File

@ -0,0 +1,54 @@
language: erlang
env:
global:
- LUAROCKS_BASE=luarocks-2.0.13
matrix:
- LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
- LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
- LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
branches:
only:
- master
before_install:
- if [ $LUA = "luajit" ]; then
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
fi
- sudo apt-get install $LUA
- sudo apt-get install $LUA_DEV
- lua$LUA_SFX -v
# Install a recent luarocks release
- wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
- tar zxvpf $LUAROCKS_BASE.tar.gz
- cd $LUAROCKS_BASE
- ./configure
--lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
- sudo make
- sudo make install
- cd $TRAVIS_BUILD_DIR
install:
- export DEBUG=DEBUG
- sudo -E luarocks make luasocket-scm-0.rockspec
script:
- cd test
- lua$LUA_SFX hello.lua
- lua$LUA_SFX testsrvr.lua > /dev/null &
- lua$LUA_SFX testclnt.lua
- lua$LUA_SFX stufftest.lua
- lua$LUA_SFX excepttest.lua
- lua$LUA_SFX test_bind.lua
- lua$LUA_SFX test_getaddrinfo.lua
- lua$LUA_SFX ltn12test.lua
- lua$LUA_SFX mimetest.lua
- lua$LUA_SFX urltest.lua
- lua$LUA_SFX test_socket_error.lua
notifications:
email:
on_success: change
on_failure: always

13
FIX
View File

@ -1,15 +1,14 @@
http was preserving old host header during redirects
fix smtp.send hang on source error
add create field to FTP and SMTP and fix HTTP ugliness
clean timeout argument to open functions in SMTP, HTTP and FTP
eliminate globals from namespaces created by module().
url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class.

View File

@ -1,5 +1,5 @@
LuaSocket 2.0.2 license
Copyright <20> 2004-2007 Diego Nehab
LuaSocket 3.0 license
Copyright <20> 2004-2013 Diego Nehab
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

28
Lua51.props Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.1\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.1\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.1\</LUAINC_PATH>
<LUALIB>lua51.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua51</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

28
Lua52.props Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.2\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.2\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.2\</LUAINC_PATH>
<LUALIB>lua52.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua52</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

49
NEW
View File

@ -1,11 +1,44 @@
What's New
This is just a bug-fix/update release.
Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
* Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
* Fixed: return values are consistent when reading from closed sockets;
* Fixed: case sensitivity in headers of multipart messages in
smtp.message() (Graham Henstridge);
* Fixed a couple instances of error() being called instead of base.error(). These would cause an error when an error was reported. :) (Ketmar Dark);
* Fixed: test script now uses pairs() iterator instead of the old
Lua syntax (Robert Dodier).
* Added: Compatible with Lua 5.2
- Note that unless you define LUA_COMPAT_MODULE, package
tables will not be exported as globals!
* Added: IPv6 support;
- Socket.connect and socket.bind support IPv6 addresses;
- Getpeername and getsockname support IPv6 addresses, and
return the socket family as a third value;
- URL module updated to support IPv6 host names;
- New socket.tcp6 and socket.udp6 functions;
- New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
* Added: getoption method;
* Fixed: url.unescape was returning additional values;
* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could
mistaking their own stack slots for functions arguments;
* Fixed: Receiving zero-length datagram is now possible;
* Improved: Hidden all internal library symbols;
* Improved: Better error messages;
* Improved: Better documentation of socket options.
* Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
* Fixed: failure on bind() was destroying the socket (Sam Roberts);
* Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
* Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
* Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
* Fixed: manual links to home.html changed to index.html (Robert Hahn);
* Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
* Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
* Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
* Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
* Improved: Clarified tcp:receive() in the manual (MPB);
* Improved: Decent makefiles (LHF).
* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).

11
README
View File

@ -1,6 +1,11 @@
This is the LuaSocket 2.0.1. It has been tested on WinXP, Mac OS X,
and Linux. Please use the Lua mailing list to report any bugs
(or "features") you encounter.
This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
and Linux.
Please use the project page at GitHub
https://github.com/diegonehab/luasocket
to file bug reports or propose changes.
Have fun,
Diego Nehab.

64
TODO
View File

@ -1,7 +1,67 @@
- bizarre default values for getnameinfo should throw error instead!
> It's just too bad it can't talk to gmail -
> reason 1: they absolutely want TLS
> reason 2: unlike all the other SMTP implementations, they
> don't
> tolerate missing < > around adresses
- document the new bind and connect behavior.
- shouldn't we instead make the code compatible to Lua 5.2
without any compat stuff, and use a compatibility layer to
make it work on 5.1?
- add what's new to manual
- should there be an equivalent to tohostname for IPv6?
- should we add service name resolution as well to getaddrinfo?
- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
- add http POST sample to manual
people keep asking stupid questions
- documentation of dirty/getfd/setfd is problematic because of portability
same for unix and serial.
what to do about this? add a stronger disclaimer?
- fix makefile with decent defaults?
Done:
- added IPv6 support to getsockname
- simplified getpeername implementation
- added family to return of getsockname and getpeername
and added modification to the manual to describe
- connect and bind try all adresses returned by getaddrinfo
- document headers.lua?
- update copyright date everywhere?
- remove RCSID from files?
- move version to 2.1 rather than 2.1.1?
- fixed url package to support ipv6 hosts
- changed domain to family
- implement getfamily methods.
- remove references to Lua 5.0 from documentation, add 5.2?
- update lua and luasocket version in samples in documentation
- document ipv5_v6only default option being set?
- document tcp6 and udp6
- document dns.getaddrinfo
- documented zero-sized datagram change?
no.
- document unix socket and serial socket? add raw support?
no.
- document getoption
- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
replace \r\n with \0xD\0xA in everything
New mime support
ftp send should return server replies?
make sure there are no object files in the distribution tarball
http handling of 100-continue, see DB patch

60
config
View File

@ -1,60 +0,0 @@
#------
# LuaSocket makefile configuration
#
#------
# Output file names
#
EXT=so
SOCKET_V=2.0.2
MIME_V=1.0.2
SOCKET_SO=socket.$(EXT).$(SOCKET_V)
MIME_SO=mime.$(EXT).$(MIME_V)
UNIX_SO=unix.$(EXT)
#------
# Lua includes and libraries
#
#LUAINC=-I/usr/local/include/lua50
#LUAINC=-I/usr/local/include/lua5.1
#LUAINC=-Ilua-5.1.1/src
#------
# Compat-5.1 directory
#
#COMPAT=compat-5.1r5
#------
# Top of your Lua installation
# Relative paths will be inside the src tree
#
#INSTALL_TOP_SHARE=/usr/local/share/lua/5.0
#INSTALL_TOP_LIB=/usr/local/lib/lua/5.0
INSTALL_TOP_SHARE=/usr/local/share/lua/5.1
INSTALL_TOP_LIB=/usr/local/lib/lua/5.1
INSTALL_DATA=cp
INSTALL_EXEC=cp
#------
# Compiler and linker settings
# for Mac OS X
#
#CC=gcc
#DEF= -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN
#CFLAGS= $(LUAINC) -I$(COMPAT) $(DEF) -pedantic -Wall -O2 -fno-common
#LDFLAGS=-bundle -undefined dynamic_lookup
#LD=export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
#------
# Compiler and linker settings
# for Linux
CC=gcc
DEF=-DLUASOCKET_DEBUG
CFLAGS= $(LUAINC) $(DEF) -pedantic -Wall -O2 -fpic
LDFLAGS=-O -shared -fpic
LD=gcc
#------
# End of makefile configuration
#

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -39,12 +39,16 @@
<h2 id=dns>DNS</h2>
<p>
Name resolution functions return <em>all</em> information obtained from the
resolver in a table of the form:
IPv4 name resolution functions
<a href=#toip><tt>dns.toip</tt></a>
and
<a href=#tohostname><tt>dns.tohostname</tt></a>
return <em>all</em> information obtained from
the resolver in a table of the form:
</p>
<blockquote><tt>
resolved = {<br>
resolved4 = {<br>
&nbsp;&nbsp;name = <i>canonic-name</i>,<br>
&nbsp;&nbsp;alias = <i>alias-list</i>,<br>
&nbsp;&nbsp;ip = <i>ip-address-list</i><br>
@ -55,6 +59,53 @@ resolved = {<br>
Note that the <tt>alias</tt> list can be empty.
</p>
<p>
The more general name resolution function
<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which
supports both IPv6 and IPv4,
returns <em>all</em> information obtained from
the resolver in a table of the form:
</p>
<blockquote><tt>
resolved6 = {<br>
&nbsp;&nbsp;[1] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-1</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-1</i><br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;[n] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-n</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-n</i><br>
&nbsp;&nbsp;}<br>
}
</tt> </blockquote>
<p>
Here, <tt>family</tt> contains the string <tt>"inet"</tt> for IPv4
addresses, and <tt>"inet6"</tt> for IPv6 addresses.
</p>
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getaddrinfo>
socket.dns.<b>getaddrinfo(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to address.
</p>
<p class=parameters>
<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
</p>
<p class=return>
The function returns a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b>
followed by an error message.
</p>
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gethostname>
@ -72,7 +123,7 @@ socket.dns.<b>tohostname(</b>address<b>)</b>
</p>
<p class=description>
Converts from IP address to host name.
Converts from IPv4 address to host name.
</p>
<p class=parameters>
@ -93,7 +144,7 @@ socket.dns.<b>toip(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to IP address.
Converts from host name to IPv4 address.
</p>
<p class=parameters>
@ -113,8 +164,8 @@ message.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -42,7 +42,7 @@
FTP (File Transfer Protocol) is a protocol used to transfer files
between hosts. The <tt>ftp</tt> namespace offers thorough support
to FTP, under a simple interface. The implementation conforms to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc0959.txt">RFC 959</a>.
<a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a>.
</p>
<p>
@ -70,8 +70,8 @@ local ftp = require("socket.ftp")
<p>
URLs MUST conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
1738</a>, that is, an URL is a string in the form:
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
<blockquote>
@ -270,8 +270,8 @@ f, e = ftp.put{
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -36,7 +36,7 @@
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=http>HTTP</h2>
<h2 id="http">HTTP</h2>
<p>
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
@ -45,8 +45,7 @@ namespace offers full support for the client side of the HTTP
protocol (i.e.,
the facilities that would be used by a web-browser implementation). The
implementation conforms to the HTTP/1.1 standard,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
2616</a>.
<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p>
@ -67,8 +66,7 @@ local http = require("socket.http")
<p>
URLs must conform to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
1738</a>,
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
@ -97,8 +95,9 @@ headers = {<br>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names.
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified.
</p>
@ -119,9 +118,10 @@ the HTTP module:
<li> <tt>USERAGENT</tt>: default user agent reported to server.
</ul>
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=request>
<p class=name id="request">
http.<b>request(</b>url [, body]<b>)</b><br>
http.<b>request{</b><br>
&nbsp;&nbsp;url = <i>string</i>,<br>
@ -199,8 +199,7 @@ it usually returns a message body (a web page informing the
URL was not found or some other useless page). To make sure the
operation was successful, check the returned status <tt>code</tt>. For
a list of the possible values and their meanings, refer to <a
href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC
2616</a>.
href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p class=description>
@ -259,7 +258,7 @@ r, c, h = http.request {
-- }
</pre>
<p class=note id=post>
<p class=note id="post">
Note: When sending a POST request, simple interface adds a
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
header to the request. This is the type used by
@ -267,7 +266,7 @@ HTML forms. If you need another type, use the generic
interface.
</p>
<p class=note id=authentication>
<p class=note id="authentication">
Note: Some URLs are protected by their
servers from anonymous download. For those URLs, the server must receive
some sort of authentication along with the request or it will deny
@ -278,7 +277,7 @@ download and return status "401&nbsp;Authentication Required".
The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both
explained in detail in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2068.txt">RFC 2068</a>.
<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
</p>
<p class=note>The Basic Authentication Scheme sends
@ -304,7 +303,7 @@ b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
-- the request directly.
r, c = http.request {
url = "http://www.example.com/private/index.html",
headers = { authentication = "Basic " .. (mime.b64("fulano:silva")) }
headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
}
</pre>
@ -314,8 +313,8 @@ r, c = http.request {
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -49,7 +49,7 @@ functionality commonly needed by applications that deal with the Internet.
The core support has been implemented so that it is both efficient and
simple to use. It is available to any Lua application once it has been
properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and Unix platforms. </p>
and runs well on several Windows and UNIX platforms. </p>
<p>
Among the support modules, the most commonly used implement the
@ -78,8 +78,8 @@ LuaSocket.
</p>
<p>
Copyright &copy; 2004-2007 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
</p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -87,25 +87,18 @@ Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
<h2 id=download>Download</h2>
<p>
LuaSocket version 2.0.2 is now available for download! It is
compatible with Lua&nbsp;5.1, and has
LuaSocket version 3.0-rc1 is now available for download!
It is compatible with Lua&nbsp;5.1 and 5.2, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
are it works well on most UNIX distributions and Windows flavors.
</p>
<p>
The library can be downloaded in source code from the
<a href=http://luaforge.net/projects/luasocket/>LuaSocket
project page</a> at LuaForge.
Besides the full C and Lua source code for the library, the distribution
contains several examples, this user's manual and basic test procedures.
</p>
<p>
Danilo Tuler is maintaining Win32 binaries for LuaSocket, which are also
available from LuaForge. These are compatible with the
<a href=http://luaforge.net/projects/luabinaries>LuaBinaries</a>,
also available from LuaForge.
The current version of the library can be found at
the <a href="https://github.com/diegonehab/luasocket">LuaSocket
project page</a> on GitHub. Besides the full C and Lua source code
for the library, the distribution contains several examples,
this user's manual and basic test procedures.
</p>
<p> Take a look at the <a
@ -118,14 +111,14 @@ manual to find out how to properly install the library.
<h2 id=thanks>Special thanks</h2>
<p>
Throughout LuaSocket's history, many people gave suggestions that helped
improve it. For that, I thank the Lua community.
Special thanks go to
David Burgess, who has helped push the library to a new level of quality and
from whom I have learned a lot of stuff that doesn't show up in RFCs.
Special thanks also to Carlos Cassino, who played a big part in the
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall
has been helping a lot too! Thanks to you all!
This marks the first release of LuaSocket that
wholeheartedly embraces the open-source development
philosophy. After a long hiatus, Matthew Wild finally
convinced me it was time for a release including IPv6 and
Lua 5.2 support. It was more work than we anticipated.
Special thanks to Sam Roberts, Florian Zeitz, and Paul
Aurich, Liam Devine, Alexey Melnichuk, and everybody else
that has helped bring this library back to life.
</p>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -133,41 +126,58 @@ has been helping a lot too! Thanks to you all!
<h2 id=new>What's New</h2>
<p>
2.0.2 is just a bug-fix/update release.
Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
and Lua&nbsp;5.2 compatibility.
</p>
<ul>
<li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
<li> Fixed: return values are consistent when reading from closed sockets;
<li> Fixed: case sensitivity in headers of multipart
messages in smtp.message() (Graham Henstridge);
<li> Fixed a couple instances of error() being called instead of
base.error(). These would cause an error when an error was
reported :) (Ketmar Dark);
<li> Fixed: test script now uses pairs() iterator instead
of the old Lua syntax (Robert Dodier).
<li> Added: Compatible with Lua&nbsp;5.2
<ul>
<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
package tables will <em>not</em> be exported as globals!
</ul>
<p>
2.0.1 is just a bug-fix/update release.
</p>
<li> Added: IPv6 support;
<ul>
<li> Updated: now using <tt>compat-5.1r5</tt>;
<li> Improved: <tt>http.request</tt> is more robust to
malformed URLs (Adrian Sietsma);
<li> Improved: the simple <tt>http.request</tt> interface sends a
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
header (William Trenker);
<li> Improved: <tt>http.request</tt> is robust to evil
servers that send inappropriate 100-continue messages
(David Burgess);
<li> Fixed: <tt>http.request</tt> was using the old host header during
redirects (Florian Berger);
<li> Fixed: sample <tt>unix.c</tt> had fallen through the
cracks during development (Matthew Percival);
<li> Fixed: error code was not being propagated correctly in
ftp.lua (David Burgess).
<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
IPv6 addresses, and return the socket family as a third value;
<li> URL module updated to support IPv6 host names;
<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
<li> New <tt>socket.dns.getaddrinfo</tt> and
<tt>socket.dns.getnameinfo</tt> functions;
</ul>
<li> Added: <tt>getoption</tt> method;
<li> Fixed: <tt>url.unescape</tt> was returning additional values;
<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
<tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
mistaking their own stack slots for functions arguments;
<li> Fixed: Receiving zero-length datagram is now possible;
<li> Improved: Hidden all internal library symbols;
<li> Improved: Better error messages;
<li> Improved: Better documentation of socket options.
<li> Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
<li> Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
<li> Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
<li> Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
<li> Fixed: manual links to home.html changed to index.html
(Robert Hahn);
<li> Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
<li> Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
<li> Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
<li> Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
<li> Improved: Clarified tcp:receive() in the manual (MPB);
<li> Improved: Decent makefiles (LHF).
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
</ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -176,7 +186,7 @@ ftp.lua (David Burgess).
<p>
All previous versions of the LuaSocket library can be downloaded <a
href="http://www.cs.princeton.edu/~diego/professional/luasocket/old">
href="http://www.impa.br/~diego/software/luasocket/old">
here</a>. Although these versions are no longer supported, they are
still available for those that have compatibility issues.
</p>
@ -187,7 +197,7 @@ still available for those that have compatibility issues.
<hr>
<center>
<p class=bar>
<a href="home.html#download">download</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -195,7 +205,7 @@ still available for those that have compatibility issues.
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:23 EDT 2006
Tue Jun 11 18:50:23 HKT 2013
</small>
</p>
</center>

View File

@ -25,8 +25,8 @@ Installation">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -39,24 +39,10 @@ Installation">
<h2>Installation</h2>
<p> LuaSocket 2.0.2 uses the new package system for Lua 5.1.
All Lua library developers are encouraged to update their libraries so that
all libraries can coexist peacefully and users can benefit from the
standardization and flexibility of the standard.
</p>
<p>
Those stuck with Lua 5.0 will need the
<a href=http://www.keplerproject.org/compat/>compat-5.1</a>
module. It is maintained by
<a href=http://www.keplerproject.org/>The Kepler
Project</a>'s team, and implements the Lua 5.1 package proposal
on top of Lua 5.0. </p>
<p> Here we will only describe the standard distribution.
If the standard doesn't meet your needs, we refer you to the
Lua discussion list, where any question about the package
scheme will likely already have been answered. </p>
<p> Here we describe the standard distribution. If the
standard doesn't meet your needs, we refer you to the Lua
discussion list, where any question about the package scheme
will likely already have been answered. </p>
<h3>Directory structure</h3>
@ -64,14 +50,19 @@ scheme will likely already have been answered. </p>
directories, one for system dependent files, and another for system
independent files. Let's call these directories <tt>&lt;CDIR&gt;</tt>
and <tt>&lt;LDIR&gt;</tt>, respectively.
For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.0</tt>' for
<tt>&lt;LDIR&gt;</tt>. On Windows, sometimes only one directory is used, say
'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket
For example, in my laptp, Lua&nbsp;5.1 is configured to
use '<tt>/usr/local/lib/lua/5.1</tt>' for
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.1</tt>' for
<tt>&lt;LDIR&gt;</tt>. On Windows, <tt>&lt;CDIR&gt;</tt>
usually points to the directory where the Lua executable is
found, and <tt>&lt;LDIR&gt;</tt> points to a
<tt>lua/</tt> directory inside <tt>&lt;CDIR&gt;</tt>. (These
settings can be overridden by environment variables
<tt>LUA_PATH</tt> and <tt>LUA_CPATH</tt>. See the Lua
documentation for details.) Here is the standard LuaSocket
distribution directory structure:</p>
<pre class=example>
&lt;LDIR&gt;/compat-5.1.lua
&lt;LDIR&gt;/ltn12.lua
&lt;LDIR&gt;/socket.lua
&lt;CDIR&gt;/socket/core.dll
@ -88,33 +79,6 @@ distribution directory structure:</p>
would be replaced by <tt>core.so</tt>.
</p>
<p> In order for the interpreter to find all LuaSocket components, three
environment variables need to be set. The first environment variable tells
the interpreter to load the <tt>compat-5.1.lua</tt> module at startup: </p>
<pre class=example>
LUA_INIT=@&lt;LDIR&gt;/compat-5.1.lua
</pre>
<p>
This is only need for Lua&nbsp;5.0! Lua&nbsp;5.1 comes with
the package system built in, of course.
</p>
<p>
The other two environment variables instruct the compatibility module to
look for dynamic libraries and extension modules in the appropriate
directories and with the appropriate filename extensions.
</p>
<pre class=example>
LUA_PATH=&lt;LDIR&gt;/?.lua;?.lua
LUA_CPATH=&lt;CDIR&gt;/?.dll;?.dll
</pre>
<p> Again, naturally, on Unix systems the shared library extension would be
<tt>.so</tt> instead of <tt>.dll</tt>.</p>
<h3>Using LuaSocket</h3>
<p> With the above setup, and an interpreter with shared library support,
@ -122,19 +86,19 @@ it should be easy to use LuaSocket. Just fire the interpreter and use the
<tt>require</tt> function to gain access to whatever module you need:</p>
<pre class=example>
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; socket = require("socket")
&gt; print(socket._VERSION)
--&gt; LuaSocket 2.0.2
--&gt; LuaSocket 3.0-rc1
</pre>
<p> Each module loads their dependencies automatically, so you only need to
load the modules you directly depend upon: </p>
<pre class=example>
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; http = require("socket.http")
&gt; print(http.request("http://www.cs.princeton.edu/~diego/professional/luasocket"))
&gt; print(http.request("http://www.impa.br/~diego/software/luasocket"))
--&gt; homepage gets dumped to terminal
</pre>
@ -144,8 +108,8 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -153,7 +117,7 @@ Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:30 EDT 2006
Tue Jun 11 19:06:14 HKT 2013
</small>
</p>
</center>

View File

@ -25,8 +25,8 @@ Library, Support">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -314,8 +314,8 @@ and many others are covered by the <a href=reference.html>reference manual</a>.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -25,8 +25,8 @@ Pump, Support, Library">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -224,8 +224,8 @@ local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png")),
ltn12.sink.file(io.open("copy.png"))
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
@ -379,8 +379,8 @@ local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png")),
ltn12.sink.file(io.open("copy.png"))
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
@ -411,8 +411,8 @@ Creates and returns a source that produces the contents of a
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -44,11 +44,11 @@ content transfer encodings, such as Base64 and Quoted-Printable.
It also provides functions to break text into lines and change
the end-of-line convention.
MIME is described mainly in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2048.txt">2049</a>.
<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
</p>
<p>
@ -457,8 +457,8 @@ marker.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -25,8 +25,8 @@ Support, Manual">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -42,9 +42,10 @@ Support, Manual">
<blockquote>
<a href="dns.html">DNS (in socket)</a>
<blockquote>
<a href="dns.html#toip">toip</a>,
<a href="dns.html#getaddrinfo">getaddrinfo</a>,
<a href="dns.html#gethostname">gethostname</a>,
<a href="dns.html#tohostname">tohostname</a>,
<a href="dns.html#gethostname">gethostname</a>.
<a href="dns.html#toip">toip</a>.
</blockquote>
</blockquote>
@ -108,9 +109,9 @@ Support, Manual">
<a href="mime.html">MIME</a>
<blockquote>
<a href="mime.html#high">high-level</a>:
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#decode">decode</a>,
<a href="mime.html#encode">encode</a>,
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#stuff">stuff</a>,
<a href="mime.html#wrap">wrap</a>.
</blockquote>
@ -120,10 +121,10 @@ Support, Manual">
<a href="mime.html#dot">dot</a>,
<a href="mime.html#eol">eol</a>,
<a href="mime.html#qp">qp</a>,
<a href="mime.html#wrp">wrp</a>,
<a href="mime.html#qpwrp">qpwrp</a>.
<a href="mime.html#qpwrp">qpwrp</a>,
<a href="mime.html#unb64">unb64</a>,
<a href="mime.html#unqp">unqp</a>,
<a href="mime.html#wrp">wrp</a>.
</blockquote>
</blockquote>
@ -142,19 +143,27 @@ Support, Manual">
<blockquote>
<a href="socket.html">Socket</a>
<blockquote>
<a href="socket.html#bind">bind</a>,
<a href="socket.html#connect">connect</a>,
<a href="socket.html#connect">connect4</a>,
<a href="socket.html#connect">connect6</a>,
<a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
<a href="socket.html#headers.canonic">headers.canonic</a>,
<a href="socket.html#newtry">newtry</a>,
<a href="socket.html#protect">protect</a>,
<a href="socket.html#select">select</a>,
<a href="socket.html#sink">sink</a>,
<a href="socket.html#skip">skip</a>,
<a href="socket.html#sleep">sleep</a>,
<a href="socket.html#setsize">_SETSIZE</a>,
<a href="socket.html#source">source</a>,
<a href="tcp.html#tcp">tcp</a>,
<a href="tcp.html#socket.tcp">tcp</a>,
<a href="tcp.html#socket.tcp6">tcp6</a>,
<a href="socket.html#try">try</a>,
<a href="udp.html#udp">udp</a>,
<a href="udp.html#socket.udp">udp</a>,
<a href="udp.html#socket.udp6">udp6</a>,
<a href="socket.html#version">_VERSION</a>.
</blockquote>
</blockquote>
@ -168,11 +177,16 @@ Support, Manual">
<a href="tcp.html#bind">bind</a>,
<a href="tcp.html#close">close</a>,
<a href="tcp.html#connect">connect</a>,
<a href="tcp.html#dirty">dirty</a>,
<a href="tcp.html#getfd">getfd</a>,
<a href="tcp.html#getoption">getoption</a>,
<a href="tcp.html#getpeername">getpeername</a>,
<a href="tcp.html#getsockname">getsockname</a>,
<a href="tcp.html#getstats">getstats</a>,
<a href="tcp.html#listen">listen</a>,
<a href="tcp.html#receive">receive</a>,
<a href="tcp.html#send">send</a>,
<a href="tcp.html#setfd">setfd</a>,
<a href="tcp.html#setoption">setoption</a>,
<a href="tcp.html#setstats">setstats</a>,
<a href="tcp.html#settimeout">settimeout</a>,
@ -186,6 +200,7 @@ Support, Manual">
<a href="udp.html">UDP (in socket)</a>
<blockquote>
<a href="udp.html#close">close</a>,
<a href="udp.html#getoption">getoption</a>,
<a href="udp.html#getpeername">getpeername</a>,
<a href="udp.html#getsockname">getsockname</a>,
<a href="udp.html#receive">receive</a>,
@ -220,8 +235,8 @@ Support, Manual">
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -25,8 +25,8 @@ Library, Support">
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -48,14 +48,13 @@ control (if you bother to read the code).
</p>
<p>The implementation conforms to the Simple Mail Transfer Protocol,
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>.
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>.
Another RFC of interest is <a
href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>,
href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
which governs the Internet Message Format.
Multipart messages (those that contain attachments) are part
of the MIME standard, but described mainly
in <a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">RFC
2046</a>
in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
<p> In the description below, good understanding of <a
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
@ -91,8 +90,9 @@ headers = {<br>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names.
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified.
</p>
@ -196,7 +196,7 @@ part of the message and will not be sent to anyone.
</p>
<p class=note>
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper
use of these headers. Here is a summary of what it says:
@ -236,9 +236,9 @@ exactly what you <em>don't</em> want to happen!
<p class=note>
I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
and
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>.
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
</p>
<pre class=example>
@ -398,8 +398,8 @@ r, e = smtp.send{
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -73,14 +73,19 @@ set to <tt><b>true</b></tt>.
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect>
socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b>
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p>
<p class=description>
This function is a shortcut that creates and returns a TCP client object
connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally,
connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
the user can also specify the local address and port to bind
(<tt>locaddr</tt> and <tt>locport</tt>).
(<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
to "<tt>inet</tt>" or "<tt>inet6</tt>".
Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
connection is created depends on your system configuration. Two variations
of connect are defined as simple helper functions that restrict the
<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
</p>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -94,6 +99,47 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support.
</p>
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
socket.<b>gettime()</b>
</p>
<p class=description>
Returns the time in seconds, relative to the origin of the
universe. You should subtract the values returned by this function
to get meaningful values.
</p>
<pre class=example>
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- socket.headers ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="headers.canonic">
socket.headers.<b>canonic</b></p>
<p> The <tt>socket.headers.canonic</tt> table
is used by the HTTP and SMTP modules to translate from
lowercase field names back into their canonic
capitalization. When a lowercase field name exists as a key
in this table, the associated value is substituted in
whenever the field name is sent out.
</p>
<p>
You can obtain the <tt>headers</tt> namespace if case run-time
modifications are required by running:
</p>
<pre class=example>
-- loads the headers module
local headers = require("headers")
</pre>
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry>
@ -199,6 +245,15 @@ themselves, to simplify the test if a specific socket has
changed status.
</p>
<p class=note>
<b>Note: </b>: <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
number may be as high as 1024 or as low as 64 by default,
depending on the system. It is usually possible to change this
at compile time. Invoking <tt>select</tt> with a larger
number of sockets will raise an error.
</p>
<p class=note>
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
on non-blocking TCP sockets. The function may return a socket as
@ -217,6 +272,10 @@ method or <tt>accept</tt> might block forever.
it to <tt>select</tt>, it will be ignored.
</p>
<p class=note>
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
</p>
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink>
@ -288,8 +347,8 @@ Freezes the program execution during a given amount of time.
</p>
<p class=parameters>
<tt>Time</tt> is the number of seconds to sleep for.
The function truncates <tt>time</tt> down to the nearest integer.
<tt>Time</tt> is the number of seconds to sleep for. If
<tt>time</tt> is negative, the function returns immediately.
</p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -324,24 +383,17 @@ side closes the connection.
The function returns a source with the appropriate behavior.
</p>
<!-- time ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
socket.<b>gettime()</b>
<p class=name id=setsize>
socket.<b>_SETSIZE</b>
</p>
<p class=description>
Returns the time in seconds, relative to the origin of the
universe. You should subtract the values returned by this function
to get meaningful values.
The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle.
</p>
<pre class=example>
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try>
@ -386,8 +438,8 @@ This constant has a string describing the current LuaSocket version.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -36,16 +36,16 @@
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=tcp>TCP</h2>
<h2 id="tcp">TCP</h2>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socket.tcp>
<p class=name id="socket.tcp">
socket.<b>tcp()</b>
</p>
<p class=description>
Creates and returns a TCP master object. A master object can
Creates and returns an IPv4 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
@ -58,9 +58,34 @@ In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp6">
socket.<b>tcp6()</b>
</p>
<p class=description>
Creates and returns an IPv6 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=accept>
<p class=name id="accept">
server:<b>accept()</b>
</p>
@ -87,7 +112,7 @@ might block until <em>another</em> client shows up.
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind>
<p class=name id="bind">
master:<b>bind(</b>address, port<b>)</b>
</p>
@ -100,7 +125,9 @@ local host.
<tt>Port</tt> must be an integer number in the range [0..64K).
If <tt>address</tt>
is '<tt>*</tt>', the system binds to all local interfaces
using the <tt>INADDR_ANY</tt> constant. If <tt>port</tt> is 0, the system automatically
using the <tt>INADDR_ANY</tt> constant or
<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port.
</p>
@ -116,7 +143,7 @@ is available and is a shortcut for the creation of server sockets.
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=close>
<p class=name id="close">
master:<b>close()</b><br>
client:<b>close()</b><br>
server:<b>close()</b>
@ -139,7 +166,7 @@ automatically closed before destruction, though.
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect>
<p class=name id="connect">
master:<b>connect(</b>address, port<b>)</b>
</p>
@ -180,9 +207,18 @@ href=socket.html#select><tt>socket.select</tt></a> with the socket in the
established.
</p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by <a
href=#socket.tcp><tt>socket.tcp</tt></a> or <a
href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
the appropriate family are tried in succession until the
first success or until the last failure.
</p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getpeername>
<p class=name id="getpeername">
client:<b>getpeername()</b>
</p>
@ -191,8 +227,9 @@ Returns information about the remote side of a connected client object.
</p>
<p class=return>
Returns a string with the IP address of the peer, followed by the
port number that peer is using for the connection.
Returns a string with the IP address of the peer, the
port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
@ -202,7 +239,7 @@ Note: It makes no sense to call this method on server objects.
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getsockname>
<p class=name id="getsockname">
master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br>
server:<b>getsockname()</b>
@ -213,13 +250,15 @@ Returns the local address information associated to the object.
</p>
<p class=return>
The method returns a string with local IP address and a number with
the port. In case of error, the method returns <b><tt>nil</tt></b>.
The method returns a string with local IP address, a number with
the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getstats>
<p class=name id="getstats">
master:<b>getstats()</b><br>
client:<b>getstats()</b><br>
server:<b>getstats()</b><br>
@ -237,7 +276,7 @@ and the age of the socket object in seconds.
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=listen>
<p class=name id="listen">
master:<b>listen(</b>backlog<b>)</b>
</p>
@ -265,7 +304,7 @@ method returns <b><tt>nil</tt></b> followed by an error message.
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=receive>
<p class=name id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p>
@ -284,7 +323,8 @@ closed. No end-of-line translation is performed;
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is
terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. This is the default pattern;
the returned line. In fact, <em>all</em> CR characters are
ignored by the pattern. This is the default pattern;
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket.
</ul>
@ -296,12 +336,12 @@ of any received data before return.
<p class=return>
If successful, the method returns the received pattern. In case of error,
the method returns <tt><b>nil</b></tt> followed by an error message which
can be the string '<tt>closed</tt>' in case the connection was
the method returns <tt><b>nil</b></tt> followed by an error
message, followed by a (possibly empty) string containing
the partial that was received. The error message can be
the string '<tt>closed</tt>' in case the connection was
closed before the transmission was completed or the string
'<tt>timeout</tt>' in case there was a timeout during the operation.
Also, after the error message, the function returns the partial result of
the transmission.
</p>
<p class=note>
@ -315,7 +355,7 @@ too.
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send>
<p class=name id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b>
</p>
@ -353,7 +393,7 @@ instead of calling the method several times.
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setoption>
<p class=name id="setoption">
client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b>
</p>
@ -391,21 +431,53 @@ used in validating addresses supplied in a call to
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
disables the Nagle's algorithm for the connection.
disables the Nagle's algorithm for the connection;
<li> '<tt>ipv6-v6only</tt>':
Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
sending and receiving only IPv6 packets.
</ul>
<p class=return>
The method returns 1 in case of success, or <b><tt>nil</tt></b> otherwise.
The method returns 1 in case of success, or <b><tt>nil</tt></b>
followed by an error message otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getoption">
client:<b>getoption(</b>option)</b><br>
server:<b>getoption(</b>option)</b>
</p>
<p class=description>
Gets options for the TCP object.
See <a href=#setoption><tt>setoption</tt></a> for description of the
option names and values.
</p>
<p class=parameters>
<tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>keepalive</tt>'
<li> '<tt>linger</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>tcp-nodelay</tt>'
</ul>
<p class=return>
The method returns the option <tt>value</tt> in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setstats>
<p class=name id="setstats">
master:<b>setstats(</b>received, sent, age<b>)</b><br>
client:<b>setstats(</b>received, sent, age<b>)</b><br>
server:<b>setstats(</b>received, sent, age<b>)</b><br>
@ -428,7 +500,7 @@ The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=settimeout>
<p class=name id="settimeout">
master:<b>settimeout(</b>value [, mode]<b>)</b><br>
client:<b>settimeout(</b>value [, mode]<b>)</b><br>
server:<b>settimeout(</b>value [, mode]<b>)</b>
@ -485,7 +557,7 @@ contained verbs making their imperative nature obvious.
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=shutdown>
<p class=name id="shutdown">
client:<b>shutdown(</b>mode<b>)</b><br>
</p>
@ -507,14 +579,74 @@ This is the default mode;
This function returns 1.
</p>
<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dirty">
master:<b>dirty()</b><br>
client:<b>dirty()</b><br>
server:<b>dirty()</b>
</p>
<p class=description>
Check the read buffer status.
</p>
<p class=return>
Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
</p>
<p class=note>
Note: <b>This is an internal method, any use is unlikely to be portable.</b>
</p>
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getfd">
master:<b>getfd()</b><br>
client:<b>getfd()</b><br>
server:<b>getfd()</b>
</p>
<p class=description>
Returns the underling socket descriptor or handle associated to the object.
</p>
<p class=return>
The descriptor or handle. In case the object has been closed, the return will be -1.
</p>
<p class=note>
Note: <b>This is an internal method, any use is unlikely to be portable.</b>
</p>
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setfd">
master:<b>setfd(</b>fd<b>)</b><br>
client:<b>setfd(</b>fd<b>)</b><br>
server:<b>setfd(</b>fd<b>)</b>
</p>
<p class=description>
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
</p>
<p class=return>
No return value.
</p>
<p class=note>
Note: <b>This is an internal method, any use is unlikely to be portable.</b>
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -37,7 +37,7 @@
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=udp>UDP</h2>
<h2 id="udp">UDP</h2>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -46,10 +46,12 @@ socket.<b>udp()</b>
</p>
<p class="description">
Creates and returns an unconnected UDP object. Unconnected objects support the
Creates and returns an unconnected IPv4 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
@ -66,6 +68,44 @@ returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6">
socket.<b>udp6()</b>
</p>
<p class="description">
Creates and returns an unconnected IPv6 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="close">
@ -100,8 +140,12 @@ Retrieves information about the peer
associated with a connected UDP object.
</p>
<p class="return">
Returns the IP address and port number of the peer.
<p class=return>
Returns a string with the IP address of the peer, the
port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class="note">
@ -119,10 +163,12 @@ unconnected:<b>getsockname()</b>
Returns the local address information associated to the object.
</p>
<p class="return">
The method returns a string with local IP
address and a number with the port. In case of error, the method
returns <b><tt>nil</tt></b>.
<p class=return>
The method returns a string with local IP address, a number with
the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class="note">
@ -177,6 +223,40 @@ address and port as extra return values (and is therefore slightly less
efficient).
</p>
<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getoption">
connected:<b>getoption()</b><br>
unconnected:<b>getoption()</b>
</p>
<p class="description">
Gets an option value from the UDP object.
See <a href=#setoption><tt>setoption</tt></a> for
description of the option names and values.
</p>
<p class="parameters"><tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>dontroute</tt>'
<li> '<tt>broadcast</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>reuseport</tt>'
<li> '<tt>ip-multicast-loop</tt>'
<li> '<tt>ipv6-v6only</tt>'
<li> '<tt>ip-multicast-if</tt>'
<li> '<tt>ip-multicast-ttl</tt>'
<li> '<tt>ip-add-membership</tt>'
<li> '<tt>ip-drop-membership</tt>'
</ul>
</p>
<p class=return>
The method returns the option <tt>value</tt> in case of
success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="send">
@ -284,6 +364,15 @@ is recommended when the same peer is used for several transmissions
and can result in up to 30% performance gains.
</p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by <a
href=#socket.udp><tt>socket.udp</tt></a> or <a
href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from
the appropriate family are tried in succession until the
first success or until the last failure.
</p>
<!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setsockname">
@ -332,23 +421,57 @@ only modify an option if you are sure you need it.</p>
name, and <tt>value</tt> depends on the option being set:
</p>
<ul>
<li>'<tt>dontroute</tt>': Setting this option to <tt>true</tt>
indicates that outgoing messages should bypass the standard routing
facilities;</li>
<li>'<tt>broadcast</tt>': Setting this option to <tt>true</tt>
requests permission to send broadcast datagrams on the
socket.</li>
</ul>
<ul>
<li> '<tt>dontroute</tt>': Indicates that outgoing
messages should bypass the standard routing facilities.
Receives a boolean value;
<li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket.
Receives a boolean value;
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
validating addresses supplied in a <tt>bind()</tt> call
should allow reuse of local addresses.
Receives a boolean value;
<li> '<tt>reuseport</tt>': Allows completely duplicate
bindings by multiple processes if they all set
'<tt>reuseport</tt>' before binding the port.
Receives a boolean value;
<li> '<tt>ip-multicast-loop</tt>':
Specifies whether or not a copy of an outgoing multicast
datagram is delivered to the sending host as long as it is a
member of the multicast group.
Receives a boolean value;
<li> '<tt>ipv6-v6only</tt>':
Specifies whether to restrict <tt>inet6</tt> sockets to
sending and receiving only IPv6 packets.
Receive a boolean value;
<li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams
are sent.
Receives an IP address;
<li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing
multicast datagrams.
Receives a number;
<li> '<tt>ip-add-membership</tt>':
Joins the multicast group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address;
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address.
</ul>
<p class="return">
The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class="note">
Note: The descriptions above come from the man
pages.
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@ -397,8 +520,8 @@ imperative nature obvious.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -24,8 +24,8 @@
</td></tr>
</table>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#download">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
@ -36,14 +36,13 @@
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=url>URL</h2>
<h2 id="url">URL</h2>
<p>
The <tt>url</tt> namespace provides functions to parse, protect,
and build URLs, as well as functions to compose absolute URLs
from base and relative URLs, according to
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC
2396</a>.
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
</p>
<p>
@ -70,7 +69,7 @@ An URL is defined by the following grammar:
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=absolute>
<p class=name id="absolute">
url.<b>absolute(</b>base, relative<b>)</b>
</p>
@ -91,7 +90,7 @@ The function returns a string with the absolute URL.
<p class=note>
Note: The rules that
govern the composition are fairly complex, and are described in detail in
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC 2396</a>.
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
The example bellow should give an idea of what the rules are.
</p>
@ -126,7 +125,7 @@ g;x?y#s = http://a/b/c/g;x?y#s
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build>
<p class=name id="build">
url.<b>build(</b>parsed_url<b>)</b>
</p>
@ -147,7 +146,7 @@ The function returns a string with the built URL.
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=build_path>
<p class=name id="build_path">
url.<b>build_path(</b>segments, unsafe<b>)</b>
</p>
@ -201,7 +200,7 @@ code = url.escape("/#?;")
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse>
<p class=name id="parse">
url.<b>parse(</b>url, default<b>)</b>
</p>
@ -266,7 +265,7 @@ parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=parse_path>
<p class=name id="parse_path">
url.<b>parse_path(</b>path<b>)</b>
</p>
@ -310,8 +309,8 @@ The function returns the decoded string.
<hr>
<center>
<p class=bar>
<a href="home.html">home</a> &middot;
<a href="home.html#down">download</a> &middot;
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>

View File

@ -2,7 +2,6 @@
-- Little program to convert to and from Base64
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local ltn12 = require("ltn12")
local mime = require("mime")

View File

@ -3,7 +3,6 @@
-- non-blocking I/O via the dispatcher module.
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $$
-----------------------------------------------------------------------------
local url = require("socket.url")
local dispatch = require("dispatch")
@ -12,7 +11,7 @@ dispatch.TIMEOUT = 10
-- make sure the user knows how to invoke us
arg = arg or {}
if table.getn(arg) < 1 then
if #arg < 1 then
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
exit()
end

88
etc/cookie.lua Normal file
View File

@ -0,0 +1,88 @@
local socket = require"socket"
local http = require"socket.http"
local url = require"socket.url"
local ltn12 = require"ltn12"
local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
local function unquote(t, quoted)
local n = string.match(t, "%$(%d+)$")
if n then n = tonumber(n) end
if quoted[n] then return quoted[n]
else return t end
end
local function parse_set_cookie(c, quoted, cookie_table)
c = c .. ";$last=last;"
local _, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=%s*(.-)%s*;%s*()")
local cookie = {
name = n,
value = unquote(v, quoted),
attributes = {}
}
while 1 do
_, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=?%s*(.-)%s*;%s*()", i)
if not n or n == "$last" then break end
cookie.attributes[#cookie.attributes+1] = {
name = n,
value = unquote(v, quoted)
}
end
cookie_table[#cookie_table+1] = cookie
end
local function split_set_cookie(s, cookie_table)
cookie_table = cookie_table or {}
-- remove quoted strings from cookie list
local quoted = {}
s = string.gsub(s, '"(.-)"', function(q)
quoted[#quoted+1] = q
return "$" .. #quoted
end)
-- add sentinel
s = s .. ",$last="
-- split into individual cookies
i = 1
while 1 do
local _, __, cookie, next_token
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
token_class .. "+)%s*=", i)
if not next_token then break end
parse_set_cookie(cookie, quoted, cookie_table)
if next_token == "$last" then break end
end
return cookie_table
end
local function quote(s)
if string.find(s, "[ %,%;]") then return '"' .. s .. '"'
else return s end
end
local _empty = {}
local function build_cookies(cookies)
s = ""
for i,v in ipairs(cookies or _empty) do
if v.name then
s = s .. v.name
if v.value and v.value ~= "" then
s = s .. '=' .. quote(v.value)
end
end
if v.name and #(v.attributes or _empty) > 0 then s = s .. "; " end
for j,u in ipairs(v.attributes or _empty) do
if u.name then
s = s .. u.name
if u.value and u.value ~= "" then
s = s .. '=' .. quote(u.value)
end
end
if j < #v.attributes then s = s .. "; " end
end
if i < #cookies then s = s .. ", " end
end
return s
end

View File

@ -2,7 +2,6 @@
-- Little program to download DICT word definitions
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -44,48 +43,48 @@ function metat.__index:check(ok)
end
function metat.__index:getdef()
local line = socket.try(self.tp:receive())
local def = {}
while line ~= "." do
table.insert(def, line)
line = socket.try(self.tp:receive())
end
return table.concat(def, "\n")
local line = socket.try(self.tp:receive())
local def = {}
while line ~= "." do
table.insert(def, line)
line = socket.try(self.tp:receive())
end
return table.concat(def, "\n")
end
function metat.__index:define(database, word)
database = database or "!"
socket.try(self.tp:command("DEFINE", database .. " " .. word))
socket.try(self.tp:command("DEFINE", database .. " " .. word))
local code, count = self:check(150)
local defs = {}
for i = 1, count do
self:check(151)
table.insert(defs, self:getdef())
end
self:check(250)
local defs = {}
for i = 1, count do
self:check(151)
table.insert(defs, self:getdef())
end
self:check(250)
return defs
end
function metat.__index:match(database, strat, word)
database = database or "!"
strat = strat or "."
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
self:check(152)
local mat = {}
local line = socket.try(self.tp:receive())
local mat = {}
local line = socket.try(self.tp:receive())
while line ~= '.' do
database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
if not mat[database] then mat[database] = {} end
table.insert(mat[database], word)
line = socket.try(self.tp:receive())
end
self:check(250)
line = socket.try(self.tp:receive())
end
self:check(250)
return mat
end
function metat.__index:quit()
self.tp:command("QUIT")
return self:check(221)
self.tp:command("QUIT")
return self:check(221)
end
function metat.__index:close()

View File

@ -2,7 +2,6 @@
-- A hacked dispatcher module
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $$
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
@ -51,10 +50,10 @@ function socket.protect(f)
return function(...)
local co = coroutine.create(f)
while true do
local results = {coroutine.resume(co, base.unpack(arg))}
local results = {coroutine.resume(co, ...)}
local status = table.remove(results, 1)
if not status then
if type(results[1]) == 'table' then
if base.type(results[1]) == 'table' then
return nil, results[1][1]
else base.error(results[1]) end
end
@ -77,7 +76,7 @@ local function newset()
insert = function(set, value)
if not reverse[value] then
table.insert(set, value)
reverse[value] = table.getn(set)
reverse[value] = #set
end
end,
remove = function(set, value)
@ -105,8 +104,7 @@ local function cowrap(dispatcher, tcp, error)
-- don't override explicitly.
local metat = { __index = function(table, key)
table[key] = function(...)
arg[1] = tcp
return tcp[key](base.unpack(arg))
return tcp[key](tcp,select(2,...))
end
return table[key]
end}

View File

@ -2,7 +2,6 @@
-- Little program to adjust end of line markers.
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local mime = require("mime")
local ltn12 = require("ltn12")

View File

@ -3,7 +3,7 @@ local dispatch = require("dispatch")
local handler = dispatch.newhandler()
-- make sure the user knows how to invoke us
if table.getn(arg) < 1 then
if #arg < 1 then
print("Usage")
print(" lua forward.lua <iport:ohost:oport> ...")
os.exit(1)

View File

@ -2,7 +2,6 @@
-- Little program to download files from URLs
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
local http = require("socket.http")
@ -12,53 +11,53 @@ local ltn12 = require("ltn12")
-- formats a number of seconds into human readable form
function nicetime(s)
local l = "s"
if s > 60 then
s = s / 60
l = "m"
if s > 60 then
s = s / 60
l = "h"
if s > 24 then
s = s / 24
l = "d" -- hmmm
end
end
end
if l == "s" then return string.format("%5.0f%s", s, l)
else return string.format("%5.2f%s", s, l) end
local l = "s"
if s > 60 then
s = s / 60
l = "m"
if s > 60 then
s = s / 60
l = "h"
if s > 24 then
s = s / 24
l = "d" -- hmmm
end
end
end
if l == "s" then return string.format("%5.0f%s", s, l)
else return string.format("%5.2f%s", s, l) end
end
-- formats a number of bytes into human readable form
function nicesize(b)
local l = "B"
if b > 1024 then
b = b / 1024
l = "KB"
if b > 1024 then
b = b / 1024
l = "MB"
if b > 1024 then
b = b / 1024
l = "GB" -- hmmm
end
end
end
return string.format("%7.2f%2s", b, l)
local l = "B"
if b > 1024 then
b = b / 1024
l = "KB"
if b > 1024 then
b = b / 1024
l = "MB"
if b > 1024 then
b = b / 1024
l = "GB" -- hmmm
end
end
end
return string.format("%7.2f%2s", b, l)
end
-- returns a string with the current state of the download
local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
local elapsed_s = "%s received, %s/s throughput, %s elapsed "
function gauge(got, delta, size)
local rate = got / delta
if size and size >= 1 then
return string.format(remaining_s, nicesize(got), nicesize(rate),
100*got/size, nicetime((size-got)/rate))
else
return string.format(elapsed_s, nicesize(got),
nicesize(rate), nicetime(delta))
end
local rate = got / delta
if size and size >= 1 then
return string.format(remaining_s, nicesize(got), nicesize(rate),
100*got/size, nicetime((size-got)/rate))
else
return string.format(elapsed_s, nicesize(got),
nicesize(rate), nicetime(delta))
end
end
-- creates a new instance of a receive_cb that saves to disk
@ -89,10 +88,10 @@ end
-- determines the size of a http file
function gethttpsize(u)
local r, c, h = http.request {method = "HEAD", url = u}
if c == 200 then
return tonumber(h["content-length"])
end
local r, c, h = http.request {method = "HEAD", url = u}
if c == 200 then
return tonumber(h["content-length"])
end
end
-- downloads a file using the http protocol
@ -101,7 +100,7 @@ function getbyhttp(u, file)
-- only print feedback if output is not stdout
if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
local r, c, h, s = http.request {url = u, sink = save }
if c ~= 200 then io.stderr:write(s or c, "\n") end
if c ~= 200 then io.stderr:write(s or c, "\n") end
end
-- downloads a file using the ftp protocol
@ -114,29 +113,29 @@ function getbyftp(u, file)
gett.sink = save
gett.type = "i"
local ret, err = ftp.get(gett)
if err then print(err) end
if err then print(err) end
end
-- determines the scheme
function getscheme(u)
-- this is an heuristic to solve a common invalid url poblem
if not string.find(u, "//") then u = "//" .. u end
local parsed = url.parse(u, {scheme = "http"})
return parsed.scheme
-- this is an heuristic to solve a common invalid url poblem
if not string.find(u, "//") then u = "//" .. u end
local parsed = url.parse(u, {scheme = "http"})
return parsed.scheme
end
-- gets a file either by http or ftp, saving as <name>
function get(u, name)
local fout = name and io.open(name, "wb")
local scheme = getscheme(u)
if scheme == "ftp" then getbyftp(u, fout)
elseif scheme == "http" then getbyhttp(u, fout)
else print("unknown scheme" .. scheme) end
local scheme = getscheme(u)
if scheme == "ftp" then getbyftp(u, fout)
elseif scheme == "http" then getbyhttp(u, fout)
else print("unknown scheme" .. scheme) end
end
-- main program
arg = arg or {}
if table.getn(arg) < 1 then
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
os.exit(1)
if #arg < 1 then
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
os.exit(1)
else get(arg[1], arg[2]) end

View File

@ -3,7 +3,6 @@
-- LuaSocket toolkit.
-- Author: David Burgess
-- Modified by Diego Nehab, but David is in charge
-- RCS ID: $Id$
-----------------------------------------------------------------------------
--[[
if you have any questions: RFC 1179
@ -268,11 +267,11 @@ send = socket.protect(function(option)
local class = string.sub(option.class or localip or localhost,1,31)
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
ctlfn = string.sub(ctlfn or file,1,131)
local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost,
local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost,
class,
option.job or "LuaSocket",
option.job or "LuaSocket",
user,
fmt, lpfile,
lpfile,

View File

@ -2,7 +2,6 @@
-- Little program to convert to and from Quoted-Printable
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local ltn12 = require("ltn12")
local mime = require("mime")

View File

@ -2,7 +2,6 @@
-- TFTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -35,18 +34,18 @@ local OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
-- Packet creation functions
-----------------------------------------------------------------------------
local function RRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end
local function WRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end
local function ACK(block)
local low, high
low = math.mod(block, 256)
high = (block - low)/256
return char(0, OP_ACK, high, low)
local low, high
low = math.mod(block, 256)
high = (block - low)/256
return char(0, OP_ACK, high, low)
end
local function get_OP(dgram)
@ -58,16 +57,16 @@ end
-- Packet analysis functions
-----------------------------------------------------------------------------
local function split_DATA(dgram)
local block = byte(dgram, 3)*256 + byte(dgram, 4)
local data = string.sub(dgram, 5)
return block, data
local block = byte(dgram, 3)*256 + byte(dgram, 4)
local data = string.sub(dgram, 5)
return block, data
end
local function get_ERROR(dgram)
local code = byte(dgram, 3)*256 + byte(dgram, 4)
local msg
_,_, msg = string.find(dgram, "(.*)\000", 5)
return string.format("error code %d: %s", code, msg)
local code = byte(dgram, 3)*256 + byte(dgram, 4)
local msg
_,_, msg = string.find(dgram, "(.*)\000", 5)
return string.format("error code %d: %s", code, msg)
end
-----------------------------------------------------------------------------
@ -77,40 +76,40 @@ local function tget(gett)
local retries, dgram, sent, datahost, dataport, code
local last = 0
socket.try(gett.host, "missing host")
local con = socket.try(socket.udp())
local con = socket.try(socket.udp())
local try = socket.newtry(function() con:close() end)
-- convert from name to ip if needed
gett.host = try(socket.dns.toip(gett.host))
con:settimeout(1)
gett.host = try(socket.dns.toip(gett.host))
con:settimeout(1)
-- first packet gives data host/port to be used for data transfers
local path = string.gsub(gett.path or "", "^/", "")
path = url.unescape(path)
retries = 0
repeat
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
dgram, datahost, dataport = con:receivefrom()
repeat
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
dgram, datahost, dataport = con:receivefrom()
retries = retries + 1
until dgram or datahost ~= "timeout" or retries > 5
try(dgram, datahost)
until dgram or datahost ~= "timeout" or retries > 5
try(dgram, datahost)
-- associate socket with data host/port
try(con:setpeername(datahost, dataport))
try(con:setpeername(datahost, dataport))
-- default sink
local sink = gett.sink or ltn12.sink.null()
-- process all data packets
while 1 do
while 1 do
-- decode packet
code = get_OP(dgram)
try(code ~= OP_ERROR, get_ERROR(dgram))
code = get_OP(dgram)
try(code ~= OP_ERROR, get_ERROR(dgram))
try(code == OP_DATA, "unhandled opcode " .. code)
-- get data packet parts
local block, data = split_DATA(dgram)
local block, data = split_DATA(dgram)
-- if not repeated, write
if block == last+1 then
try(sink(data))
try(sink(data))
last = block
end
-- last packet brings less than 512 bytes of data
if string.len(data) < 512 then
if string.len(data) < 512 then
try(con:send(ACK(block)))
try(con:close())
try(sink(nil))
@ -118,13 +117,13 @@ local function tget(gett)
end
-- get the next packet
retries = 0
repeat
sent = try(con:send(ACK(last)))
dgram, err = con:receive()
repeat
sent = try(con:send(ACK(last)))
dgram, err = con:receive()
retries = retries + 1
until dgram or err ~= "timeout" or retries > 5
try(dgram, err)
end
until dgram or err ~= "timeout" or retries > 5
try(dgram, err)
end
end
local default = {

View File

@ -1,2 +0,0 @@
Talk a bout Wim
Move thanks into the acknowledgement section.

View File

@ -6,7 +6,10 @@
\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
\newcommand{\CR}{\texttt{CR}}
\newcommand{\LF}{\texttt{LF}}
\newcommand{\CRLF}{\texttt{CR~LF}}
\newcommand{\nil}{\texttt{nil}}
\title{Filters, sources, sinks, and pumps\\
{\large or Functional programming for the rest of us}}
@ -17,30 +20,31 @@
\maketitle
\begin{abstract}
Certain data processing operations can be implemented in the
form of filters. A filter is a function that can process data
received in consecutive function calls, returning partial
results after each invocation. Examples of operations that can be
implemented as filters include the end-of-line normalization
for text, Base64 and Quoted-Printable transfer content
encodings, the breaking of text into lines, SMTP dot-stuffing,
and there are many others. Filters become even
more powerful when we allow them to be chained together to
create composite filters. In this context, filters can be seen
as the middle links in a chain of data transformations. Sources an sinks
are the corresponding end points of these chains. A source
is a function that produces data, chunk by chunk, and a sink
is a function that takes data, chunk by chunk. In this
article, we describe the design of an elegant interface for filters,
sources, sinks, and chaining, and illustrate each step
with concrete examples.
Certain data processing operations can be implemented in the
form of filters. A filter is a function that can process
data received in consecutive invocations, returning partial
results each time it is called. Examples of operations that
can be implemented as filters include the end-of-line
normalization for text, Base64 and Quoted-Printable transfer
content encodings, the breaking of text into lines, SMTP
dot-stuffing, and there are many others. Filters become
even more powerful when we allow them to be chained together
to create composite filters. In this context, filters can be
seen as the internal links in a chain of data transformations.
Sources and sinks are the corresponding end points in these
chains. A source is a function that produces data, chunk by
chunk, and a sink is a function that takes data, chunk by
chunk. Finally, pumps are procedures that actively drive
data from a source to a sink, and indirectly through all
intervening filters. In this article, we describe the design of an
elegant interface for filters, sources, sinks, chains, and
pumps, and we illustrate each step with concrete examples.
\end{abstract}
\section{Introduction}
Within the realm of networking applications, we are often
required apply transformations to streams of data. Examples
required to apply transformations to streams of data. Examples
include the end-of-line normalization for text, Base64 and
Quoted-Printable transfer content encodings, breaking text
into lines with a maximum number of columns, SMTP
@ -50,38 +54,37 @@ transfer coding, and the list goes on.
Many complex tasks require a combination of two or more such
transformations, and therefore a general mechanism for
promoting reuse is desirable. In the process of designing
\texttt{LuaSocket~2.0}, David Burgess and I were forced to deal with
this problem. The solution we reached proved to be very
general and convenient. It is based on the concepts of
filters, sources, sinks, and pumps, which we introduce
below.
\texttt{LuaSocket~2.0}, we repeatedly faced this problem.
The solution we reached proved to be very general and
convenient. It is based on the concepts of filters, sources,
sinks, and pumps, which we introduce below.
\emph{Filters} are functions that can be repeatedly invoked
with chunks of input, successively returning processed
chunks of output. More importantly, the result of
chunks of output. Naturally, the result of
concatenating all the output chunks must be the same as the
result of applying the filter to the concatenation of all
input chunks. In fancier language, filters \emph{commute}
with the concatenation operator. As a result, chunk
boundaries are irrelevant: filters correctly handle input
data no matter how it is split.
with the concatenation operator. More importantly, filters
must handle input data correctly no matter how the stream
has been split into chunks.
A \emph{chain} transparently combines the effect of one or
more filters. The interface of a chain is
indistinguishable from the interface of its components.
This allows a chained filter to be used wherever an atomic
filter is expected. In particular, chains can be
A \emph{chain} is a function that transparently combines the
effect of one or more filters. The interface of a chain is
indistinguishable from the interface of its component
filters. This allows a chained filter to be used wherever
an atomic filter is accepted. In particular, chains can be
themselves chained to create arbitrarily complex operations.
Filters can be seen as internal nodes in a network through
which data will flow, potentially being transformed many
times along its way. Chains connect these nodes together.
To complete the picture, we need \emph{sources} and
\emph{sinks}. These are the initial and final nodes of the
network, respectively. Less abstractly, a source is a
function that produces new data every time it is called.
Conversely, sinks are functions that give a final
destination to the data they receive. Naturally, sources
times along the way. Chains connect these nodes together.
The initial and final nodes of the network are
\emph{sources} and \emph{sinks}, respectively. Less
abstractly, a source is a function that produces new chunks
of data every time it is invoked. Conversely, sinks are
functions that give a final destination to the chunks of
data they receive in sucessive calls. Naturally, sources
and sinks can also be chained with filters to produce
filtered sources and sinks.
@ -89,37 +92,38 @@ Finally, filters, chains, sources, and sinks are all passive
entities: they must be repeatedly invoked in order for
anything to happen. \emph{Pumps} provide the driving force
that pushes data through the network, from a source to a
sink.
sink, and indirectly through all intervening filters.
In the following sections, we start with a simplified
interface, which we later refine. The evolution we present
is not contrived: it recreates the steps we followed
ourselves as we consolidated our understanding of these
is not contrived: it recreates the steps we ourselves
followed as we consolidated our understanding of these
concepts within our application domain.
\subsection{A simple example}
Let us use the end-of-line normalization of text as an
The end-of-line normalization of text is a good
example to motivate our initial filter interface.
Assume we are given text in an unknown end-of-line
convention (including possibly mixed conventions) out of the
commonly found Unix (LF), Mac OS (CR), and DOS (CRLF)
conventions. We would like to be able to write code like the
following:
commonly found Unix (\LF), Mac OS (\CR), and
DOS (\CRLF) conventions. We would like to be able to
use the folowing code to normalize the end-of-line markers:
\begin{quote}
\begin{lua}
@stick#
local in = source.chain(source.file(io.stdin), normalize("\r\n"))
local out = sink.file(io.stdout)
pump.all(in, out)
local CRLF = "\013\010"
local input = source.chain(source.file(io.stdin), normalize(CRLF))
local output = sink.file(io.stdout)
pump.all(input, output)
%
\end{lua}
\end{quote}
This program should read data from the standard input stream
and normalize the end-of-line markers to the canonic CRLF
marker, as defined by the MIME standard. Finally, the
normalized text should be sent to the standard output
and normalize the end-of-line markers to the canonic
\CRLF\ marker, as defined by the MIME standard.
Finally, the normalized text should be sent to the standard output
stream. We use a \emph{file source} that produces data from
standard input, and chain it with a filter that normalizes
the data. The pump then repeatedly obtains data from the
@ -127,27 +131,28 @@ source, and passes it to the \emph{file sink}, which sends
it to the standard output.
In the code above, the \texttt{normalize} \emph{factory} is a
function that creates our normalization filter. This filter
will replace any end-of-line marker with the canonic
`\verb|\r\n|' marker. The initial filter interface is
function that creates our normalization filter, which
replaces any end-of-line marker with the canonic marker.
The initial filter interface is
trivial: a filter function receives a chunk of input data,
and returns a chunk of processed data. When there are no
more input data left, the caller notifies the filter by invoking
it with a \texttt{nil} chunk. The filter responds by returning
the final chunk of processed data.
it with a \nil\ chunk. The filter responds by returning
the final chunk of processed data (which could of course be
the empty string).
Although the interface is extremely simple, the
implementation is not so obvious. A normalization filter
respecting this interface needs to keep some kind of context
between calls. This is because a chunk boundary may lie between
the CR and LF characters marking the end of a line. This
the \CR\ and \LF\ characters marking the end of a single line. This
need for contextual storage motivates the use of
factories: each time the factory is invoked, it returns a
filter with its own context so that we can have several
independent filters being used at the same time. For
efficiency reasons, we must avoid the obvious solution of
concatenating all the input into the context before
producing any output.
producing any output chunks.
To that end, we break the implementation into two parts:
a low-level filter, and a factory of high-level filters. The
@ -167,10 +172,10 @@ end-of-line normalization filters:
\begin{quote}
\begin{lua}
@stick#
function filter.cycle(low, ctx, extra)
function filter.cycle(lowlevel, context, extra)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
ret, context = lowlevel(context, chunk, extra)
return ret
end
end
@ -178,27 +183,30 @@ end
@stick#
function normalize(marker)
return cycle(eol, 0, marker)
return filter.cycle(eol, 0, marker)
end
%
\end{lua}
\end{quote}
The \texttt{normalize} factory simply calls a more generic
factory, the \texttt{cycle} factory. This factory receives a
factory, the \texttt{cycle}~factory, passing the low-level
filter~\texttt{eol}. The \texttt{cycle}~factory receives a
low-level filter, an initial context, and an extra
parameter, and returns a new high-level filter. Each time
the high-level filer is passed a new chunk, it invokes the
low-level filter with the previous context, the new chunk,
and the extra argument. It is the low-level filter that
does all the work, producing the chunk of processed data and
a new context. The high-level filter then updates its
a new context. The high-level filter then replaces its
internal context, and returns the processed chunk of data to
the user. Notice that we take advantage of Lua's lexical
scoping to store the context in a closure between function
calls.
Concerning the low-level filter code, we must first accept
\subsection{The C part of the filter}
As for the low-level filter, we must first accept
that there is no perfect solution to the end-of-line marker
normalization problem. The difficulty comes from an
inherent ambiguity in the definition of empty lines within
@ -208,39 +216,39 @@ mixed input. It also does a reasonable job with empty lines
and serves as a good example of how to implement a low-level
filter.
The idea is to consider both CR and~LF as end-of-line
The idea is to consider both \CR\ and~\LF\ as end-of-line
\emph{candidates}. We issue a single break if any candidate
is seen alone, or followed by a different candidate. In
other words, CR~CR~and LF~LF each issue two end-of-line
markers, whereas CR~LF~and LF~CR issue only one marker each.
This method correctly handles the Unix, DOS/MIME, VMS, and Mac
OS conventions.
is seen alone, or if it is followed by a different
candidate. In other words, \CR~\CR~and \LF~\LF\ each issue
two end-of-line markers, whereas \CR~\LF~and \LF~\CR\ issue
only one marker each. It is easy to see that this method
correctly handles the most common end-of-line conventions.
\subsection{The C part of the filter}
Our low-level filter is divided into two simple functions.
The inner function performs the normalization itself. It takes
each input character in turn, deciding what to output and
how to modify the context. The context tells if the last
processed character was an end-of-line candidate, and if so,
which candidate it was. For efficiency, it uses
Lua's auxiliary library's buffer interface:
With this in mind, we divide the low-level filter into two
simple functions. The inner function~\texttt{pushchar} performs the
normalization itself. It takes each input character in turn,
deciding what to output and how to modify the context. The
context tells if the last processed character was an
end-of-line candidate, and if so, which candidate it was.
For efficiency, we use Lua's auxiliary library's buffer
interface:
\begin{quote}
\begin{C}
@stick#
@#define candidate(c) (c == CR || c == LF)
static int process(int c, int last, const char *marker,
static int pushchar(int c, int last, const char *marker,
luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last) luaL_addstring(buffer, marker);
if (c == last)
luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
luaL_pushchar(buffer, c);
return 0;
}
}
@ -248,15 +256,20 @@ static int process(int c, int last, const char *marker,
\end{C}
\end{quote}
The outer function simply interfaces with Lua. It receives the
context and input chunk (as well as an optional
custom end-of-line marker), and returns the transformed
output chunk and the new context:
The outer function~\texttt{eol} simply interfaces with Lua.
It receives the context and input chunk (as well as an
optional custom end-of-line marker), and returns the
transformed output chunk and the new context.
Notice that if the input chunk is \nil, the operation
is considered to be finished. In that case, the loop will
not execute a single time and the context is reset to the
initial state. This allows the filter to be reused many
times:
\begin{quote}
\begin{C}
@stick#
static int eol(lua_State *L) {
int ctx = luaL_checkint(L, 1);
int context = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
@ -269,24 +282,18 @@ static int eol(lua_State *L) {
return 2;
}
while (input < last)
ctx = process(*input++, ctx, marker, &buffer);
context = pushchar(*input++, context, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, ctx);
lua_pushnumber(L, context);
return 2;
}
%
\end{C}
\end{quote}
Notice that if the input chunk is \texttt{nil}, the operation
is considered to be finished. In that case, the loop will
not execute a single time and the context is reset to the
initial state. This allows the filter to be reused many
times.
When designing your own filters, the challenging part is to
decide what will be in the context. For line breaking, for
instance, it could be the number of bytes left in the
When designing filters, the challenging part is usually
deciding what to store in the context. For line breaking, for
instance, it could be the number of bytes that still fit in the
current line. For Base64 encoding, it could be a string
with the bytes that remain after the division of the input
into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
@ -294,19 +301,22 @@ distribution has many other examples.
\section{Filter chains}
Chains add a lot to the power of filters. For example,
Chains greatly increase the power of filters. For example,
according to the standard for Quoted-Printable encoding,
text must be normalized to a canonic end-of-line marker
prior to encoding. To help specifying complex
transformations like this, we define a chain factory that
creates a composite filter from one or more filters. A
chained filter passes data through all its components, and
can be used wherever a primitive filter is accepted.
text should be normalized to a canonic end-of-line marker
prior to encoding. After encoding, the resulting text must
be broken into lines of no more than 76 characters, with the
use of soft line breaks (a line terminated by the \texttt{=}
sign). To help specifying complex transformations like
this, we define a chain factory that creates a composite
filter from one or more filters. A chained filter passes
data through all its components, and can be used wherever a
primitive filter is accepted.
The chaining factory is very simple. The auxiliary
function~\texttt{chainpair} chains two filters together,
taking special care if the chunk is the last. This is
because the final \texttt{nil} chunk notification has to be
because the final \nil\ chunk notification has to be
pushed through both filters in turn:
\begin{quote}
\begin{lua}
@ -322,9 +332,9 @@ end
@stick#
function filter.chain(...)
local f = arg[1]
for i = 2, @#arg do
f = chainpair(f, arg[i])
local f = select(1, ...)
for i = 2, select('@#', ...) do
f = chainpair(f, select(i, ...))
end
return f
end
@ -337,11 +347,11 @@ define the Quoted-Printable conversion as such:
\begin{quote}
\begin{lua}
@stick#
local qp = filter.chain(normalize("\r\n"),
encode("quoted-printable"))
local in = source.chain(source.file(io.stdin), qp)
local out = sink.file(io.stdout)
pump.all(in, out)
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
wrap("quoted-printable"))
local input = source.chain(source.file(io.stdin), qp)
local output = sink.file(io.stdout)
pump.all(input, output)
%
\end{lua}
\end{quote}
@ -360,14 +370,14 @@ gives a final destination to the data.
\subsection{Sources}
A source returns the next chunk of data each time it is
invoked. When there is no more data, it simply returns
\texttt{nil}. In the event of an error, the source can inform the
caller by returning \texttt{nil} followed by an error message.
invoked. When there is no more data, it simply returns~\nil.
In the event of an error, the source can inform the
caller by returning \nil\ followed by the error message.
Below are two simple source factories. The \texttt{empty} source
returns no data, possibly returning an associated error
message. The \texttt{file} source works harder, and
yields the contents of a file in a chunk by chunk fashion:
message. The \texttt{file} source yields the contents of a file
in a chunk by chunk fashion:
\begin{quote}
\begin{lua}
@stick#
@ -398,22 +408,26 @@ A filtered source passes its data through the
associated filter before returning it to the caller.
Filtered sources are useful when working with
functions that get their input data from a source (such as
the pump in our first example). By chaining a source with one or
more filters, the function can be transparently provided
with filtered data, with no need to change its interface.
the pumps in our examples). By chaining a source with one or
more filters, such functions can be transparently provided
with filtered data, with no need to change their interfaces.
Here is a factory that does the job:
\begin{quote}
\begin{lua}
@stick#
function source.chain(src, f)
return source.simplify(function()
if not src then return nil end
return function()
if not src then
return nil
end
local chunk, err = src()
if not chunk then
src = nil
return f(nil)
else return f(chunk) end
end)
else
return f(chunk)
end
end
end
%
\end{lua}
@ -421,20 +435,20 @@ end
\subsection{Sinks}
Just as we defined an interface a data source,
we can also define an interface for a data destination.
We call any function respecting this
interface a \emph{sink}. In our first example, we used a
file sink connected to the standard output.
Just as we defined an interface for a source of data, we can
also define an interface for a data destination. We call
any function respecting this interface a sink. In our first
example, we used a file sink connected to the standard
output.
Sinks receive consecutive chunks of data, until the end of
data is signaled by a \texttt{nil} chunk. A sink can be
data is signaled by a \nil\ input chunk. A sink can be
notified of an error with an optional extra argument that
contains the error message, following a \texttt{nil} chunk.
contains the error message, following a \nil\ chunk.
If a sink detects an error itself, and
wishes not to be called again, it can return \texttt{nil},
wishes not to be called again, it can return \nil,
followed by an error message. A return value that
is not \texttt{nil} means the source will accept more data.
is not \nil\ means the sink will accept more data.
Below are two useful sink factories.
The table factory creates a sink that stores
@ -469,7 +483,7 @@ end
Naturally, filtered sinks are just as useful as filtered
sources. A filtered sink passes each chunk it receives
through the associated filter before handing it to the
through the associated filter before handing it down to the
original sink. In the following example, we use a source
that reads from the standard input. The input chunks are
sent to a table sink, which has been coupled with a
@ -479,10 +493,10 @@ standard out:
\begin{quote}
\begin{lua}
@stick#
local in = source.file(io.stdin)
local out, t = sink.table()
out = sink.chain(normalize("\r\n"), out)
pump.all(in, out)
local input = source.file(io.stdin)
local output, t = sink.table()
output = sink.chain(normalize(CRLF), output)
pump.all(input, output)
io.write(table.concat(t))
%
\end{lua}
@ -490,11 +504,11 @@ io.write(table.concat(t))
\subsection{Pumps}
Adrian Sietsma noticed that, although not on purpose, our
interface for sources is compatible with Lua iterators.
That is, a source can be neatly used in conjunction
with \texttt{for} loops. Using our file
source as an iterator, we can write the following code:
Although not on purpose, our interface for sources is
compatible with Lua iterators. That is, a source can be
neatly used in conjunction with \texttt{for} loops. Using
our file source as an iterator, we can write the following
code:
\begin{quote}
\begin{lua}
@stick#
@ -539,20 +553,22 @@ end
The \texttt{pump.step} function moves one chunk of data from
the source to the sink. The \texttt{pump.all} function takes
an optional \texttt{step} function and uses it to pump all the
data from the source to the sink. We can now use everything
we have to write a program that reads a binary file from
data from the source to the sink.
Here is an example that uses the Base64 and the
line wrapping filters from the \texttt{LuaSocket}
distribution. The program reads a binary file from
disk and stores it in another file, after encoding it to the
Base64 transfer content encoding:
\begin{quote}
\begin{lua}
@stick#
local in = source.chain(
local input = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64"))
local out = sink.chain(
local output = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")))
pump.all(in, out)
pump.all(input, output)
%
\end{lua}
\end{quote}
@ -561,19 +577,17 @@ The way we split the filters here is not intuitive, on
purpose. Alternatively, we could have chained the Base64
encode filter and the line-wrap filter together, and then
chain the resulting filter with either the file source or
the file sink. It doesn't really matter. The Base64 and the
line wrapping filters are part of the \texttt{LuaSocket}
distribution.
the file sink. It doesn't really matter.
\section{Exploding filters}
Our current filter interface has one flagrant shortcoming.
When David Burgess was writing his \texttt{gzip} filter, he
noticed that a decompression filter can explode a small
input chunk into a huge amount of data. To address this
problem, we decided to change the filter interface and allow
exploding filters to return large quantities of output data
in a chunk by chunk manner.
Our current filter interface has one serious shortcoming.
Consider for example a \texttt{gzip} decompression filter.
During decompression, a small input chunk can be exploded
into a huge amount of data. To address this problem, we
decided to change the filter interface and allow exploding
filters to return large quantities of output data in a chunk
by chunk manner.
More specifically, after passing each chunk of input to
a filter, and collecting the first chunk of output, the
@ -582,11 +596,11 @@ filtered data is left. Within these secondary calls, the
caller passes an empty string to the filter. The filter
responds with an empty string when it is ready for the next
input chunk. In the end, after the user passes a
\texttt{nil} chunk notifying the filter that there is no
\nil\ chunk notifying the filter that there is no
more input data, the filter might still have to produce too
much output data to return in a single chunk. The user has
to loop again, now passing \texttt{nil} to the filter each time,
until the filter itself returns \texttt{nil} to notify the
to loop again, now passing \nil\ to the filter each time,
until the filter itself returns \nil\ to notify the
user it is finally done.
Fortunately, it is very easy to modify a filter to respect
@ -599,13 +613,13 @@ Interestingly, the modifications do not have a measurable
negative impact in the performance of filters that do
not need the added flexibility. On the other hand, for a
small price in complexity, the changes make exploding
filters practical.
filters practical.
\section{A complex example}
The LTN12 module in the \texttt{LuaSocket} distribution
implements the ideas we have described. The MIME
and SMTP modules are especially integrated with LTN12,
implements all the ideas we have described. The MIME
and SMTP modules are tightly integrated with LTN12,
and can be used to showcase the expressive power of filters,
sources, sinks, and pumps. Below is an example
of how a user would proceed to define and send a
@ -622,9 +636,9 @@ local message = smtp.message{
to = "Fulano <fulano@example.com>",
subject = "A message with an attachment"},
body = {
preamble = "Hope you can see the attachment\r\n",
preamble = "Hope you can see the attachment" .. CRLF,
[1] = {
body = "Here is our logo\r\n"},
body = "Here is our logo" .. CRLF},
[2] = {
headers = {
["content-type"] = 'image/png; name="luasocket.png"',
@ -652,7 +666,7 @@ SMTP dot-stuffing filter, connects a socket sink
with the server, and simply pumps the data. The message is never
assembled in memory. Everything is produced on demand,
transformed in small pieces, and sent to the server in chunks,
including the file attachment that is loaded from disk and
including the file attachment which is loaded from disk and
encoded on the fly. It just works.
\section{Conclusions}
@ -665,6 +679,17 @@ abstraction for final data destinations. Filters define an
interface for data transformations. The chaining of
filters, sources and sinks provides an elegant way to create
arbitrarily complex data transformations from simpler
components. Pumps simply move the data through.
components. Pumps simply push the data through.
\section{Acknowledgements}
The concepts described in this text are the result of long
discussions with David Burgess. A version of this text has
been released on-line as the Lua Technical Note 012, hence
the name of the corresponding LuaSocket module, LTN12. Wim
Couwenberg contributed to the implementation of the module,
and Adrian Sietsma was the first to notice the
correspondence between sources and Lua iterators.
\end{document}

1
linux.cmd Normal file
View File

@ -0,0 +1 @@
make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/linux/include LUAPREFIX_linux=/home/diego/build/linux

View File

@ -126,8 +126,9 @@ local function chain2(f1, f2)
end
function filter.chain(...)
local arg = {...}
local f = arg[1]
for i = 2, table.getn(arg) do
for i = 2, #arg do
f = chain2(f, arg[i])
end
return f
@ -235,9 +236,10 @@ end
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
{{{
function source.cat(...)
local arg = {...}
local co = coroutine.create(function()
local i = 1
while i <= table.getn(arg) do
while i <= #arg do
local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk)
elseif err then return nil, err

View File

@ -73,12 +73,12 @@ Fortunately, all these problems are very easy to solve and that's what we do in
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
{{{
local function pack(ok, ...)
return ok, arg
return ok, {...}
end
function protect(f)
return function(...)
local ok, ret = pack(pcall(f, unpack(arg)))
local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret)
else return nil, ret[1] end
end
@ -157,7 +157,7 @@ function newtry(f)
if f then f() end
error(arg[2], 0)
else
return unpack(arg)
return ...
end
end
end

104
luasocket-scm-0.rockspec Normal file
View File

@ -0,0 +1,104 @@
package = "LuaSocket"
version = "scm-0"
source = {
url = "https://github.com/diegonehab/luasocket/archive/master.zip",
dir = "luasocket-master",
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
},
mingw32 = {
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
}
}
local modules = {
["socket.core"] = {
sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c",
"src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c" },
defines = defines[plat],
incdir = "/src"
},
["mime.core"] = {
sources = { "src/mime.c" },
defines = defines[plat],
incdir = "/src"
},
["socket.http"] = "src/http.lua",
["socket.url"] = "src/url.lua",
["socket.tp"] = "src/tp.lua",
["socket.ftp"] = "src/ftp.lua",
["socket.headers"] = "src/headers.lua",
["socket.smtp"] = "src/smtp.lua",
ltn12 = "src/ltn12.lua",
socket = "src/socket.lua",
mime = "src/mime.lua"
}
if plat == "unix" or plat == "macosx" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
modules["socket.unix"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c",
"src/usocket.c", "src/unix.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c",
"src/io.c", "src/usocket.c", "src/serial.c" },
defines = defines[plat],
incdir = "/src"
}
end
if plat == "win32" or plat == "mingw32" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" }
end
return { modules = modules }
end
build = {
type = "builtin",
platforms = {
unix = make_plat("unix"),
macosx = make_plat("macosx"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = { "doc", "samples", "etc", "test" }
}

View File

@ -1,37 +1,35 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket", "socket.vcxproj", "{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libluasocket", "libluasocket.vcproj", "{599EAD40-60EE-4043-9C14-AE090A8A092D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime.vcxproj", "{128E8BD0-174A-48F0-8771-92B1E8D18713}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.ActiveCfg = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug.Build.0 = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.ActiveCfg = Release|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release.Build.0 = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.ActiveCfg = Debug|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug.Build.0 = Debug|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.ActiveCfg = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release.Build.0 = Release|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.ActiveCfg = Debug|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Debug.Build.0 = Debug|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.ActiveCfg = Release|Win32
{599EAD40-60EE-4043-9C14-AE090A8A092D}.Release.Build.0 = Release|Win32
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.ActiveCfg = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|Win32.Build.0 = Debug|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.ActiveCfg = Debug|x64
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Debug|x64.Build.0 = Debug|x64
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.ActiveCfg = Release|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|Win32.Build.0 = Release|Win32
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.ActiveCfg = Release|x64
{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}.Release|x64.Build.0 = Release|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.ActiveCfg = Debug|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|Win32.Build.0 = Debug|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.ActiveCfg = Debug|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Debug|x64.Build.0 = Debug|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.ActiveCfg = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|Win32.Build.0 = Release|Win32
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.ActiveCfg = Release|x64
{128E8BD0-174A-48F0-8771-92B1E8D18713}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

1
macosx.cmd Normal file
View File

@ -0,0 +1 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/diego/build/macosx/include LUAPREFIX_macosx=/Users/diego/build/macosx install-both

View File

@ -1,51 +1,43 @@
#------
# Load configuration
# luasocket makefile
#
include config
#------
# Hopefully no need to change anything below this line
# see src/makefile for description of how to customize the build
#
INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket
INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
# Targets:
# install install system independent support
# install-unix also install unix-only support
# install-both install for both lua5.1 and lua5.2
# install-both-unix also install unix-only
# print print the build settings
all clean:
cd src; $(MAKE) $@
PLAT?= linux
PLATS= macosx linux win32 mingw
#------
# Files to install
#
TO_SOCKET_SHARE:= \
http.lua \
url.lua \
tp.lua \
ftp.lua \
smtp.lua
all: $(PLAT)
TO_TOP_SHARE:= \
ltn12.lua \
socket.lua \
mime.lua
$(PLATS) none install install-unix local clean:
$(MAKE) -C src $@
TO_MIME_SHARE:=
print:
$(MAKE) -C src $@
#------
# Install LuaSocket according to recommendation
#
install: all
cd src; mkdir -p $(INSTALL_TOP_SHARE)
cd src; $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE)
cd src; mkdir -p $(INSTALL_SOCKET_SHARE)
cd src; $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE)
cd src; mkdir -p $(INSTALL_SOCKET_LIB)
cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT)
#cd src; mkdir -p $(INSTALL_MIME_SHARE)
#cd src; $(INSTALL_DATA) $(TO_MIME_SHARE) $(INSTALL_MIME_SHARE)
cd src; mkdir -p $(INSTALL_MIME_LIB)
cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
test:
lua test/hello.lua
install-both:
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install LUAV=5.1
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.2
@cd src; $(MAKE) install LUAV=5.2
install-both-unix:
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install-unix LUAV=5.1
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.2
@cd src; $(MAKE) install-unix LUAV=5.2
.PHONY: test
#------
# End of makefile
#

View File

@ -1,10 +1,11 @@
#--------------------------------------------------------------------------
# Distribution makefile
#--------------------------------------------------------------------------
DIST = luasocket-2.0.2
DIST = luasocket-3.0-rc1
TEST = \
test/README \
test/hello.lua \
test/testclnt.lua \
test/testsrvr.lua \
test/testsupport.lua
@ -15,6 +16,8 @@ SAMPLES = \
samples/daytimeclnt.lua \
samples/echoclnt.lua \
samples/echosrvr.lua \
samples/mclisten.lua \
samples/mcsend.lua \
samples/listener.lua \
samples/lpr.lua \
samples/talker.lua \
@ -62,6 +65,7 @@ SRC = \
src/udp.c \
src/udp.h \
src/unix.c \
src/serial.c \
src/unix.h \
src/usocket.c \
src/usocket.h \
@ -73,20 +77,25 @@ SRC = \
src/mime.lua \
src/smtp.lua \
src/socket.lua \
src/headers.lua \
src/tp.lua \
src/url.lua
MAKE = \
makefile \
config \
luasocket.sln \
socket.vcproj \
mime.vcproj
luasocket-scm-0.rockspec \
Lua51.props \
Lua52.props \
socket.vcxproj.filters \
mime.vcxproj.filters \
socket.vcxproj \
mime.vcxproj
DOC = \
doc/dns.html \
doc/ftp.html \
doc/home.html \
doc/index.html \
doc/http.html \
doc/installation.html \
doc/introduction.html \

View File

@ -1,141 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="mime"
ProjectGUID="{128E8BD0-174A-48F0-8771-92B1E8D18713}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;MIME_API=__declspec(dllexport)"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mime.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/mime.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/mime.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS; MIME_API=__declspec(dllexport)"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mime.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/mime.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="src\mime.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<File
RelativePath="..\..\lib\lua5.1.dll.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

217
mime.vcxproj Executable file
View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\mime.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\mime.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUALIB_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{128E8BD0-174A-48F0-8771-92B1E8D18713}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(LUABIN_PATH)$(Configuration)\mime\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\mime\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat />
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>
</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

16
mime.vcxproj.filters Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\mime.c" />
</ItemGroup>
<ItemGroup>
<Filter Include="cdir">
<UniqueIdentifier>{fad87a86-297c-4881-a114-73b967bb3c92}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\mime.lua">
<Filter>cdir</Filter>
</CustomBuild>
</ItemGroup>
</Project>

1
mingw.cmd Normal file
View File

@ -0,0 +1 @@
make PLAT=mingw LUAINC_mingw_base=/home/diego/build/mingw/include LUALIB_mingw_base=/home/diego/build/mingw/bin LUAPREFIX_mingw=/home/diego/build/mingw/bin DEBUG=DEBUG install-both

View File

@ -32,7 +32,7 @@ end
local host = socket.dns.gethostname()
local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
local url = string.format(query, server, arg[1], arg[2], host)
local body, headers, code = http.get(url)
local body, headers, code = http.request(url)
if code == 200 then
local data, code, error = parse(body)

View File

@ -2,7 +2,6 @@
-- UDP sample: daytime protocol client
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require"socket"
host = host or "127.0.0.1"

View File

@ -2,7 +2,6 @@
-- UDP sample: echo protocol client
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "localhost"

View File

@ -2,7 +2,6 @@
-- UDP sample: echo protocol server
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "127.0.0.1"

View File

@ -2,7 +2,6 @@
-- TCP sample: Little program to dump lines received at a given port
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "*"

View File

@ -28,8 +28,8 @@ end
do
local opt = {}
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)"
for i = 2, table.getn(arg), 1 do
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]?.?)"
for i = 2, #arg, 1 do
string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
end
if not arg[2] then

18
samples/mclisten.lua Normal file
View File

@ -0,0 +1,18 @@
local socket = require"socket"
local group = "225.0.0.37"
local port = 12345
local c = assert(socket.udp())
print(assert(c:setoption("reuseport", true)))
print(assert(c:setsockname("*", port)))
--print("loop:", c:getoption("ip-multicast-loop"))
--print(assert(c:setoption("ip-multicast-loop", false)))
--print("loop:", c:getoption("ip-multicast-loop"))
--print("if:", c:getoption("ip-multicast-if"))
--print(assert(c:setoption("ip-multicast-if", "127.0.0.1")))
--print("if:", c:getoption("ip-multicast-if"))
--print(assert(c:setoption("ip-multicast-if", "10.0.1.4")))
--print("if:", c:getoption("ip-multicast-if"))
print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
while 1 do
print(c:receivefrom())
end

20
samples/mcsend.lua Normal file
View File

@ -0,0 +1,20 @@
local socket = require"socket"
local group = "225.0.0.37"
local port = 12345
local c = assert(socket.udp())
--print(assert(c:setoption("reuseport", true)))
--print(assert(c:setsockname("*", port)))
--print(assert(c:setoption("ip-multicast-loop", false)))
--print(assert(c:setoption("ip-multicast-ttl", 4)))
--print(assert(c:setoption("ip-multicast-if", "10.0.1.3")))
--print(assert(c:setoption("ip-add-membership", {multiaddr = group, interface = "*"})))
local i = 0
while 1 do
local message = string.format("hello all %d!", i)
assert(c:sendto(message, group, port))
print("sent " .. message)
socket.sleep(1)
c:settimeout(0.5)
print(c:receivefrom())
i = i + 1
end

View File

@ -2,7 +2,6 @@
-- TCP sample: Little program to send text lines to a given host/port
-- LuaSocket sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "localhost"

View File

@ -2,7 +2,6 @@
-- Select sample: simple text line server
-- LuaSocket sample files.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
local socket = require("socket")
host = host or "*"
@ -32,7 +31,7 @@ function newset()
insert = function(set, value)
if not reverse[value] then
table.insert(set, value)
reverse[value] = table.getn(set)
reverse[value] = #set
end
end,
remove = function(set, value)

View File

@ -1,182 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="socket"
ProjectGUID="{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="src"
IntermediateDirectory="src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport)"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/socket.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/socket.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/socket.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="./src"
IntermediateDirectory="./src"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="h:\include\lua5.1"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_EXPORTS;LUASOCKET_API=__declspec(dllexport); LUASOCKET_DEBUG"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
OutputFile="$(OutDir)/socket.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="h:\lib"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/socket.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath="src\auxiliar.c">
</File>
<File
RelativePath="src\buffer.c">
</File>
<File
RelativePath="src\except.c">
</File>
<File
RelativePath="src\inet.c">
</File>
<File
RelativePath="src\io.c">
</File>
<File
RelativePath="src\luasocket.c">
</File>
<File
RelativePath="src\options.c">
</File>
<File
RelativePath="src\select.c">
</File>
<File
RelativePath="src\tcp.c">
</File>
<File
RelativePath="src\timeout.c">
</File>
<File
RelativePath="src\udp.c">
</File>
<File
RelativePath="src\wsocket.c">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
GeneratePreprocessedFile="0"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
<File
RelativePath="..\..\lib\lua5.1.dll.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

307
socket.vcxproj Executable file
View File

@ -0,0 +1,307 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\auxiliar.c" />
<ClCompile Include="src\buffer.c" />
<ClCompile Include="src\except.c" />
<ClCompile Include="src\inet.c" />
<ClCompile Include="src\io.c" />
<ClCompile Include="src\luasocket.c" />
<ClCompile Include="src\options.c" />
<ClCompile Include="src\select.c" />
<ClCompile Include="src\tcp.c" />
<ClCompile Include="src\timeout.c" />
<ClCompile Include="src\udp.c" />
<ClCompile Include="src\wsocket.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ltn12.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
<CustomBuild Include="src\socket.lua">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\%(Filename)%(Extension)</Outputs>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ftp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\headers.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\http.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\smtp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\tp.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
<CustomBuild Include="src\url.lua">
<FileType>Document</FileType>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LUABIN_PATH)$(Configuration)\socket\%(Filename)%(Extension)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy %(FullPath) $(LUABIN_PATH)$(Platform)\$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy %(FullPath) $(LUABIN_PATH)$(Configuration)\socket</Command>
</CustomBuild>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{66E3CE14-884D-4AEA-9F20-15A0BEAF8C5A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
<Import Project="Lua.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>core</TargetName>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(LUALIB_PATH)$(Configuration)\socket\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>core</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(LUABIN_PATH)$(Platform)\$(Configuration)\socket\</OutDir>
<TargetName>core</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;LUASOCKET_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)mime.pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat />
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(LUAINC_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LUASOCKET_API=__declspec(dllexport);_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>
</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName)$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>$(LUALIB);ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
<AdditionalLibraryDirectories>$(LUALIB_PATH)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

51
socket.vcxproj.filters Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\auxiliar.c" />
<ClCompile Include="src\buffer.c" />
<ClCompile Include="src\except.c" />
<ClCompile Include="src\inet.c" />
<ClCompile Include="src\io.c" />
<ClCompile Include="src\luasocket.c" />
<ClCompile Include="src\options.c" />
<ClCompile Include="src\select.c" />
<ClCompile Include="src\tcp.c" />
<ClCompile Include="src\timeout.c" />
<ClCompile Include="src\udp.c" />
<ClCompile Include="src\wsocket.c" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="src\ltn12.lua">
<Filter>cdir</Filter>
</CustomBuild>
<CustomBuild Include="src\socket.lua">
<Filter>cdir</Filter>
</CustomBuild>
<CustomBuild Include="src\ftp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\headers.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\http.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\smtp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\tp.lua">
<Filter>ldir</Filter>
</CustomBuild>
<CustomBuild Include="src\url.lua">
<Filter>ldir</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Filter Include="cdir">
<UniqueIdentifier>{b053460d-5439-4e3a-a2eb-c31a95b5691f}</UniqueIdentifier>
</Filter>
<Filter Include="ldir">
<UniqueIdentifier>{b301b82c-37cb-4e05-9333-194e92ed7a62}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
#include <stdio.h>
@ -24,7 +22,7 @@ int auxiliar_open(lua_State *L) {
* Creates a new class with given methods
* Methods whose names start with __ are passed directly to the metatable.
\*-------------------------------------------------------------------------*/
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func) {
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
luaL_newmetatable(L, classname); /* mt */
/* create __index table to place methods */
lua_pushstring(L, "__index"); /* mt,"__index" */
@ -81,7 +79,7 @@ void auxiliar_add2group(lua_State *L, const char *classname, const char *groupna
\*-------------------------------------------------------------------------*/
int auxiliar_checkboolean(lua_State *L, int objidx) {
if (!lua_isboolean(L, objidx))
luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, objidx);
}
@ -147,3 +145,14 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
return luaL_checkudata(L, objidx, classname);
}
/*-------------------------------------------------------------------------*\
* Throws error when argument does not have correct type.
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
\*-------------------------------------------------------------------------*/
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}

View File

@ -27,15 +27,13 @@
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
int auxiliar_open(lua_State *L);
void auxiliar_newclass(lua_State *L, const char *classname, luaL_reg *func);
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
@ -44,5 +42,6 @@ void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_checkboolean(lua_State *L, int objidx);
int auxiliar_tostring(lua_State *L);
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
#endif /* AUXILIAR_H */

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
@ -42,7 +40,7 @@ int buffer_open(lua_State *L) {
* Initializes C structure
\*-------------------------------------------------------------------------*/
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
buf->first = buf->last = 0;
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
buf->received = buf->sent = 0;
@ -53,8 +51,8 @@ void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, buf->received);
lua_pushnumber(L, buf->sent);
lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3;
}
@ -63,8 +61,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, buf->received);
buf->sent = (long) luaL_optnumber(L, 3, buf->sent);
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1);
return 1;
@ -80,7 +78,9 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
const char *data = luaL_checklstring(L, 2, &size);
long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1;
@ -90,9 +90,9 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, sent+start-1);
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, sent+start-1);
lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L);
lua_pushnil(L);
}
@ -111,7 +111,9 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
@ -122,9 +124,15 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes (minus what was already partially
* received) */
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
/* get a fixed number of bytes (minus what was already partially
* received) */
} else {
double n = lua_tonumber(L, 2);
size_t wanted = (size_t) n;
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
if (size == 0 || wanted > size)
err = recvraw(buf, wanted-size, &b);
}
/* check if there was an error */
if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the
@ -166,7 +174,7 @@ static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
size_t total = 0;
int err = IO_DONE;
while (total < count && err == IO_DONE) {
size_t done;
size_t done = 0;
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm);
total += done;
@ -225,7 +233,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
pos = 0;
while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */
if (data[pos] != '\r') luaL_putchar(b, data[pos]);
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++;
}
if (pos < count) { /* found '\n' */

View File

@ -14,8 +14,6 @@
*
* The module is built on top of the I/O abstraction defined in io.h and the
* timeout management is done with the timeout.h interface.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
@ -31,8 +29,8 @@ typedef struct t_buffer_ {
size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */
p_timeout tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */
size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */
} t_buffer;
typedef t_buffer *p_buffer;

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Simple exception support
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
@ -21,7 +19,7 @@ static int finalize(lua_State *L);
static int do_nothing(lua_State *L);
/* except functions */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"newtry", global_newtry},
{"protect", global_protect},
{NULL, NULL}
@ -94,6 +92,10 @@ static int global_protect(lua_State *L) {
* Init module
\*-------------------------------------------------------------------------*/
int except_open(lua_State *L) {
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}

View File

@ -24,8 +24,6 @@
*
* With these two function, it's easy to write functions that throw
* exceptions on error, but that don't interrupt the user script.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"

View File

@ -2,7 +2,6 @@
-- FTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -16,27 +15,27 @@ local socket = require("socket")
local url = require("socket.url")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
module("socket.ftp")
socket.ftp = {}
local _M = socket.ftp
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout in seconds before the program gives up on a connection
TIMEOUT = 60
_M.TIMEOUT = 60
-- default port for ftp service
PORT = 21
_M.PORT = 21
-- this is the default anonymous password. used when no password is
-- provided in url. should be changed to your e-mail.
USER = "ftp"
PASSWORD = "anonymous@anonymous.org"
_M.USER = "ftp"
_M.PASSWORD = "anonymous@anonymous.org"
-----------------------------------------------------------------------------
-- Low level FTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(server, port, create)
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
function _M.open(server, port, create)
local tp = socket.try(tp.connect(server, port or _M.PORT, _M.TIMEOUT, create))
local f = base.setmetatable({ tp = tp }, metat)
-- make sure everything gets closed in an exception
f.try = socket.newtry(function() f:close() end)
@ -44,22 +43,22 @@ function open(server, port, create)
end
function metat.__index:portconnect()
self.try(self.server:settimeout(TIMEOUT))
self.try(self.server:settimeout(_M.TIMEOUT))
self.data = self.try(self.server:accept())
self.try(self.data:settimeout(TIMEOUT))
self.try(self.data:settimeout(_M.TIMEOUT))
end
function metat.__index:pasvconnect()
self.data = self.try(socket.tcp())
self.try(self.data:settimeout(TIMEOUT))
self.try(self.data:settimeout(_M.TIMEOUT))
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
end
function metat.__index:login(user, password)
self.try(self.tp:command("user", user or USER))
self.try(self.tp:command("user", user or _M.USER))
local code, reply = self.try(self.tp:check{"2..", 331})
if code == 331 then
self.try(self.tp:command("pass", password or PASSWORD))
self.try(self.tp:command("pass", password or _M.PASSWORD))
self.try(self.tp:check("2.."))
end
return 1
@ -88,7 +87,7 @@ function metat.__index:port(ip, port)
ip, port = self.try(self.tp:getcontrol():getsockname())
self.server = self.try(socket.bind(ip, 0))
ip, port = self.try(self.server:getsockname())
self.try(self.server:settimeout(TIMEOUT))
self.try(self.server:settimeout(_M.TIMEOUT))
end
local pl = math.mod(port, 256)
local ph = (port - pl)/256
@ -143,7 +142,11 @@ function metat.__index:receive(recvt)
if argument == "" then argument = nil end
local command = recvt.command or "retr"
self.try(self.tp:command(command, argument))
local code = self.try(self.tp:check{"1..", "2.."})
local code,reply = self.try(self.tp:check{"1..", "2.."})
if (code >= 200) and (code <= 299) then
recvt.sink(reply)
return 1
end
if not self.pasvt then self:portconnect() end
local source = socket.source("until-closed", self.data)
local step = recvt.step or ltn12.pump.step
@ -200,7 +203,7 @@ end
local function tput(putt)
putt = override(putt)
socket.try(putt.host, "missing hostname")
local f = open(putt.host, putt.port, putt.create)
local f = _M.open(putt.host, putt.port, putt.create)
f:greet()
f:login(putt.user, putt.password)
if putt.type then f:type(putt.type) end
@ -212,8 +215,8 @@ local function tput(putt)
end
local default = {
path = "/",
scheme = "ftp"
path = "/",
scheme = "ftp"
}
local function parse(u)
@ -235,7 +238,7 @@ local function sput(u, body)
return tput(putt)
end
put = socket.protect(function(putt, body)
_M.put = socket.protect(function(putt, body)
if base.type(putt) == "string" then return sput(putt, body)
else return tput(putt) end
end)
@ -243,7 +246,7 @@ end)
local function tget(gett)
gett = override(gett)
socket.try(gett.host, "missing hostname")
local f = open(gett.host, gett.port, gett.create)
local f = _M.open(gett.host, gett.port, gett.create)
f:greet()
f:login(gett.user, gett.password)
if gett.type then f:type(gett.type) end
@ -261,7 +264,7 @@ local function sget(u)
return table.concat(t)
end
command = socket.protect(function(cmdt)
_M.command = socket.protect(function(cmdt)
cmdt = override(cmdt)
socket.try(cmdt.host, "missing hostname")
socket.try(cmdt.command, "missing command")
@ -274,8 +277,9 @@ command = socket.protect(function(cmdt)
return f:close()
end)
get = socket.protect(function(gett)
_M.get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end
end)
return _M

104
src/headers.lua Normal file
View File

@ -0,0 +1,104 @@
-----------------------------------------------------------------------------
-- Canonic header field capitalization
-- LuaSocket toolkit.
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local socket = require("socket")
socket.headers = {}
local _M = socket.headers
_M.canonic = {
["accept"] = "Accept",
["accept-charset"] = "Accept-Charset",
["accept-encoding"] = "Accept-Encoding",
["accept-language"] = "Accept-Language",
["accept-ranges"] = "Accept-Ranges",
["action"] = "Action",
["alternate-recipient"] = "Alternate-Recipient",
["age"] = "Age",
["allow"] = "Allow",
["arrival-date"] = "Arrival-Date",
["authorization"] = "Authorization",
["bcc"] = "Bcc",
["cache-control"] = "Cache-Control",
["cc"] = "Cc",
["comments"] = "Comments",
["connection"] = "Connection",
["content-description"] = "Content-Description",
["content-disposition"] = "Content-Disposition",
["content-encoding"] = "Content-Encoding",
["content-id"] = "Content-ID",
["content-language"] = "Content-Language",
["content-length"] = "Content-Length",
["content-location"] = "Content-Location",
["content-md5"] = "Content-MD5",
["content-range"] = "Content-Range",
["content-transfer-encoding"] = "Content-Transfer-Encoding",
["content-type"] = "Content-Type",
["cookie"] = "Cookie",
["date"] = "Date",
["diagnostic-code"] = "Diagnostic-Code",
["dsn-gateway"] = "DSN-Gateway",
["etag"] = "ETag",
["expect"] = "Expect",
["expires"] = "Expires",
["final-log-id"] = "Final-Log-ID",
["final-recipient"] = "Final-Recipient",
["from"] = "From",
["host"] = "Host",
["if-match"] = "If-Match",
["if-modified-since"] = "If-Modified-Since",
["if-none-match"] = "If-None-Match",
["if-range"] = "If-Range",
["if-unmodified-since"] = "If-Unmodified-Since",
["in-reply-to"] = "In-Reply-To",
["keywords"] = "Keywords",
["last-attempt-date"] = "Last-Attempt-Date",
["last-modified"] = "Last-Modified",
["location"] = "Location",
["max-forwards"] = "Max-Forwards",
["message-id"] = "Message-ID",
["mime-version"] = "MIME-Version",
["original-envelope-id"] = "Original-Envelope-ID",
["original-recipient"] = "Original-Recipient",
["pragma"] = "Pragma",
["proxy-authenticate"] = "Proxy-Authenticate",
["proxy-authorization"] = "Proxy-Authorization",
["range"] = "Range",
["received"] = "Received",
["received-from-mta"] = "Received-From-MTA",
["references"] = "References",
["referer"] = "Referer",
["remote-mta"] = "Remote-MTA",
["reply-to"] = "Reply-To",
["reporting-mta"] = "Reporting-MTA",
["resent-bcc"] = "Resent-Bcc",
["resent-cc"] = "Resent-Cc",
["resent-date"] = "Resent-Date",
["resent-from"] = "Resent-From",
["resent-message-id"] = "Resent-Message-ID",
["resent-reply-to"] = "Resent-Reply-To",
["resent-sender"] = "Resent-Sender",
["resent-to"] = "Resent-To",
["retry-after"] = "Retry-After",
["return-path"] = "Return-Path",
["sender"] = "Sender",
["server"] = "Server",
["smtp-remote-recipient"] = "SMTP-Remote-Recipient",
["status"] = "Status",
["subject"] = "Subject",
["te"] = "TE",
["to"] = "To",
["trailer"] = "Trailer",
["transfer-encoding"] = "Transfer-Encoding",
["upgrade"] = "Upgrade",
["user-agent"] = "User-Agent",
["vary"] = "Vary",
["via"] = "Via",
["warning"] = "Warning",
["will-retry-until"] = "Will-Retry-Until",
["www-authenticate"] = "WWW-Authenticate",
["x-mailer"] = "X-Mailer",
}
return _M

View File

@ -2,7 +2,6 @@
-- HTTP/1.1 client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -13,9 +12,11 @@ local url = require("socket.url")
local ltn12 = require("ltn12")
local mime = require("mime")
local string = require("string")
local headers = require("socket.headers")
local base = _G
local table = require("table")
module("socket.http")
socket.http = {}
local _M = socket.http
-----------------------------------------------------------------------------
-- Program constants
@ -23,9 +24,9 @@ module("socket.http")
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
PORT = 80
_M.PORT = 80
-- user agent field sent in request
USERAGENT = socket._VERSION
_M.USERAGENT = socket._VERSION
-----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed
@ -105,15 +106,15 @@ end
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(host, port, create)
function _M.open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)())
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(TIMEOUT))
h.try(c:connect(host, port or PORT))
h.try(c:settimeout(_M.TIMEOUT))
h.try(c:connect(host, port or _M.PORT))
-- here everything worked
return h
end
@ -123,10 +124,11 @@ function metat.__index:sendrequestline(method, uri)
return self.try(self.c:send(reqline))
end
function metat.__index:sendheaders(headers)
function metat.__index:sendheaders(tosend)
local canonic = headers.canonic
local h = "\r\n"
for i, v in base.pairs(headers) do
h = i .. ": " .. v .. "\r\n" .. h
for f, v in base.pairs(tosend) do
h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
end
self.try(self.c:send(h))
return 1
@ -142,7 +144,12 @@ function metat.__index:sendbody(headers, source, step)
end
function metat.__index:receivestatusline()
local status = self.try(self.c:receive())
local status = self.try(self.c:receive(5))
-- identify HTTP/0.9 responses, which do not contain a status line
-- this is just a heuristic, but is what the RFC recommends
if status ~= "HTTP/" then return nil, status end
-- otherwise proceed reading a status line
status = self.try(self.c:receive("*l", status))
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status)
end
@ -163,6 +170,12 @@ function metat.__index:receivebody(headers, sink, step)
sink, step))
end
function metat.__index:receive09body(status, sink, step)
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
source(status)
return self.try(ltn12.pump.all(source, sink, step))
end
function metat.__index:close()
return self.c:close()
end
@ -197,7 +210,7 @@ end
local function adjustheaders(reqt)
-- default headers
local lower = {
["user-agent"] = USERAGENT,
["user-agent"] = _M.USERAGENT,
["host"] = reqt.host,
["connection"] = "close, TE",
["te"] = "trailers"
@ -217,7 +230,7 @@ end
-- default url parts
local default = {
host = "",
port = PORT,
port = _M.PORT,
path ="/",
scheme = "http"
}
@ -243,7 +256,7 @@ local function shouldredirect(reqt, code, headers)
return headers.location and
string.gsub(headers.location, "%s", "") ~= "" and
(reqt.redirect ~= false) and
(code == 301 or code == 302) and
(code == 301 or code == 302 or code == 303 or code == 307) and
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
and (not reqt.nredirects or reqt.nredirects < 5)
end
@ -258,7 +271,7 @@ end
-- forward declarations
local trequest, tredirect
function tredirect(reqt, location)
--[[local]] function tredirect(reqt, location)
local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
@ -271,29 +284,36 @@ function tredirect(reqt, location)
create = reqt.create
}
-- pass location header back as a hint we redirected
headers = headers or {}
headers.location = headers.location or location
return result, code, headers, status
end
function trequest(reqt)
--[[local]] function trequest(reqt)
-- we loop until we get what we want, or
-- until we are sure there is no way to get it
local nreqt = adjustrequest(reqt)
local h = open(nreqt.host, nreqt.port, nreqt.create)
local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
-- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers)
local code = 100
local headers, status
-- if there is a body, check for server status
-- if there is a body, send it
if nreqt.source then
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
end
local code, status = h:receivestatusline()
-- if it is an HTTP/0.9 server, simply get the body and we are done
if not code then
h:receive09body(status, nreqt.sink, nreqt.step)
return 1, 200
end
local headers
-- ignore any 100-continue messages
while code == 100 do
code, status = h:receivestatusline()
headers = h:receiveheaders()
code, status = h:receivestatusline()
end
headers = h:receiveheaders()
-- at this point we should have a honest reply from the server
-- we can't redirect if we already used the source, so we report the error
if shouldredirect(nreqt, code, headers) and not nreqt.source then
@ -326,7 +346,9 @@ local function srequest(u, b)
return table.concat(t), code, headers, status
end
request = socket.protect(function(reqt, body)
_M.request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end
end)
return _M

View File

@ -1,10 +1,9 @@
/*=========================================================================*\
* Internet domain functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
@ -16,14 +15,18 @@
* Internal function prototypes.
\*=========================================================================*/
static int inet_global_toip(lua_State *L);
static int inet_global_getaddrinfo(lua_State *L);
static int inet_global_tohostname(lua_State *L);
static int inet_global_getnameinfo(lua_State *L);
static void inet_pushresolved(lua_State *L, struct hostent *hp);
static int inet_global_gethostname(lua_State *L);
/* DNS functions */
static luaL_reg func[] = {
{ "toip", inet_global_toip },
{ "tohostname", inet_global_tohostname },
static luaL_Reg func[] = {
{ "toip", inet_global_toip},
{ "getaddrinfo", inet_global_getaddrinfo},
{ "tohostname", inet_global_tohostname},
{ "getnameinfo", inet_global_getnameinfo},
{ "gethostname", inet_global_gethostname},
{ NULL, NULL}
};
@ -38,7 +41,11 @@ int inet_open(lua_State *L)
{
lua_pushstring(L, "dns");
lua_newtable(L);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
lua_settable(L, -3);
return 0;
}
@ -54,7 +61,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
struct in_addr addr;
if (inet_aton(address, &addr))
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
else
else
return socket_gethostbyname(address, hp);
}
@ -64,7 +71,7 @@ static int inet_gethost(const char *address, struct hostent **hp) {
\*-------------------------------------------------------------------------*/
static int inet_global_tohostname(lua_State *L) {
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
@ -76,6 +83,50 @@ static int inet_global_tohostname(lua_State *L) {
return 2;
}
static int inet_global_getnameinfo(lua_State *L) {
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
int i, ret;
struct addrinfo hints;
struct addrinfo *resolved, *iter;
const char *host = luaL_optstring(L, 1, NULL);
const char *serv = luaL_optstring(L, 2, NULL);
if (!(host || serv))
luaL_error(L, "host and serv cannot be both nil");
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
ret = getaddrinfo(host, serv, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
hbuf, host? (socklen_t) sizeof(hbuf): 0,
sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
if (host) {
lua_pushnumber(L, i);
lua_pushstring(L, hbuf);
lua_settable(L, -3);
}
}
freeaddrinfo(resolved);
if (serv) {
lua_pushstring(L, sbuf);
return 2;
} else {
return 1;
}
}
/*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name
* or ip address
@ -83,7 +134,7 @@ static int inet_global_tohostname(lua_State *L) {
static int inet_global_toip(lua_State *L)
{
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
@ -95,6 +146,70 @@ static int inet_global_toip(lua_State *L)
return 2;
}
int inet_optfamily(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
int inet_optsocktype(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "stream", "dgram", NULL };
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
static int inet_global_getaddrinfo(lua_State *L)
{
const char *hostname = luaL_checkstring(L, 1);
struct addrinfo *iterator = NULL, *resolved = NULL;
struct addrinfo hints;
int i = 1, ret = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
char hbuf[NI_MAXHOST];
ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
if (ret){
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_pushnumber(L, i);
lua_newtable(L);
switch (iterator->ai_family) {
case AF_INET:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet");
lua_settable(L, -3);
break;
case AF_INET6:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet6");
lua_settable(L, -3);
break;
}
lua_pushliteral(L, "addr");
lua_pushstring(L, hbuf);
lua_settable(L, -3);
lua_settable(L, -3);
i++;
}
freeaddrinfo(resolved);
return 1;
}
/*-------------------------------------------------------------------------*\
* Gets the host name
@ -105,7 +220,7 @@ static int inet_global_gethostname(lua_State *L)
name[256] = '\0';
if (gethostname(name, 256) < 0) {
lua_pushnil(L);
lua_pushstring(L, "gethostname failed");
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
lua_pushstring(L, name);
@ -113,43 +228,76 @@ static int inet_global_gethostname(lua_State *L)
}
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Retrieves socket peer name
\*-------------------------------------------------------------------------*/
int inet_meth_getpeername(lua_State *L, p_socket ps)
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
{
struct sockaddr_in peer;
int err;
struct sockaddr_storage peer;
socklen_t peer_len = sizeof(peer);
char name[INET6_ADDRSTRLEN];
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getpeername failed");
} else {
lua_pushstring(L, inet_ntoa(peer.sin_addr));
lua_pushnumber(L, ntohs(peer.sin_port));
lua_pushstring(L, socket_strerror(errno));
return 2;
}
return 2;
err = getnameinfo((struct sockaddr *) &peer, peer_len,
name, INET6_ADDRSTRLEN,
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
lua_pushstring(L, name);
lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
if (family == PF_INET) {
lua_pushliteral(L, "inet");
} else if (family == PF_INET6) {
lua_pushliteral(L, "inet6");
} else {
lua_pushliteral(L, "uknown family");
}
return 3;
}
/*-------------------------------------------------------------------------*\
* Retrieves socket local name
\*-------------------------------------------------------------------------*/
int inet_meth_getsockname(lua_State *L, p_socket ps)
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
{
struct sockaddr_in local;
socklen_t local_len = sizeof(local);
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
int err;
struct sockaddr_storage peer;
socklen_t peer_len = sizeof(peer);
char name[INET6_ADDRSTRLEN];
char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockname failed");
} else {
lua_pushstring(L, inet_ntoa(local.sin_addr));
lua_pushnumber(L, ntohs(local.sin_port));
lua_pushstring(L, socket_strerror(errno));
return 2;
}
return 2;
err=getnameinfo((struct sockaddr *)&peer, peer_len,
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
lua_pushstring(L, name);
lua_pushstring(L, port);
if (family == PF_INET) {
lua_pushliteral(L, "inet");
} else if (family == PF_INET6) {
lua_pushliteral(L, "inet6");
} else {
lua_pushliteral(L, "uknown family");
}
return 3;
}
/*=========================================================================*\
@ -198,65 +346,150 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
/*-------------------------------------------------------------------------*\
* Tries to create a new inet socket
\*-------------------------------------------------------------------------*/
const char *inet_trycreate(p_socket ps, int type) {
return socket_strerror(socket_create(ps, AF_INET, type, 0));
const char *inet_trycreate(p_socket ps, int family, int type) {
return socket_strerror(socket_create(ps, family, type, 0));
}
/*-------------------------------------------------------------------------*\
* "Disconnects" a DGRAM socket
\*-------------------------------------------------------------------------*/
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
{
switch (family) {
case PF_INET: {
struct sockaddr_in sin;
memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_UNSPEC;
sin.sin_addr.s_addr = INADDR_ANY;
return socket_strerror(socket_connect(ps, (SA *) &sin,
sizeof(sin), tm));
}
case PF_INET6: {
struct sockaddr_in6 sin6;
struct in6_addr addrany = IN6ADDR_ANY_INIT;
memset((char *) &sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_UNSPEC;
sin6.sin6_addr = addrany;
return socket_strerror(socket_connect(ps, (SA *) &sin6,
sizeof(sin6), tm));
}
}
return NULL;
}
/*-------------------------------------------------------------------------*\
* Tries to connect to remote address (address, port)
\*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_socket ps, const char *address,
unsigned short port, p_timeout tm)
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints)
{
struct sockaddr_in remote;
int err;
memset(&remote, 0, sizeof(remote));
remote.sin_family = AF_INET;
remote.sin_port = htons(port);
if (strcmp(address, "*")) {
if (!inet_aton(address, &remote.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = socket_gethostbyname(address, &hp);
if (err != IO_DONE) return socket_hoststrerror(err);
addr = (struct in_addr **) hp->h_addr_list;
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
timeout_markstart(tm);
/* create new socket if necessary. if there was no
* bind, we need to create one for every new family
* that shows up while iterating. if there was a
* bind, all families will be the same and we will
* not enter this branch. */
if (*family != iterator->ai_family) {
socket_destroy(ps);
err = socket_strerror(socket_create(ps, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol));
if (err != NULL) {
freeaddrinfo(resolved);
return err;
}
*family = iterator->ai_family;
/* all sockets initially non-blocking */
socket_setnonblocking(ps);
}
} else remote.sin_family = AF_UNSPEC;
err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
return socket_strerror(err);
/* try connecting to remote address */
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
/*-------------------------------------------------------------------------*\
* Tries to accept a socket
\*-------------------------------------------------------------------------*/
const char *inet_tryaccept(p_socket server, int family, p_socket client,
p_timeout tm)
{
socklen_t len;
t_sockaddr_storage addr;
if (family == PF_INET6) {
len = sizeof(struct sockaddr_in6);
} else {
len = sizeof(struct sockaddr_in);
}
return socket_strerror(socket_accept(server, client, (SA *) &addr,
&len, tm));
}
/*-------------------------------------------------------------------------*\
* Tries to bind socket to (address, port)
\*-------------------------------------------------------------------------*/
const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints)
{
struct sockaddr_in local;
int err;
memset(&local, 0, sizeof(local));
/* address is either wildcard or a valid ip address */
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
local.sin_family = AF_INET;
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
struct hostent *hp = NULL;
struct in_addr **addr;
err = socket_gethostbyname(address, &hp);
if (err != IO_DONE) return socket_hoststrerror(err);
addr = (struct in_addr **) hp->h_addr_list;
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
t_socket sock = *ps;
/* translate luasocket special values to C */
if (strcmp(address, "*") == 0) address = NULL;
if (!serv) serv = "0";
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
if (err) {
if (resolved) freeaddrinfo(resolved);
return err;
}
err = socket_bind(ps, (SA *) &local, sizeof(local));
if (err != IO_DONE) socket_destroy(ps);
return socket_strerror(err);
/* iterate over resolved addresses until one is good */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
if(sock == SOCKET_INVALID) {
err = socket_strerror(socket_create(&sock, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol));
if(err)
continue;
}
/* try binding to local address */
err = socket_strerror(socket_bind(&sock,
(SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen));
/* keep trying unless bind succeeded */
if (err) {
if(sock != *ps)
socket_destroy(&sock);
} else {
/* remember what we connected to, particularly the family */
*bindhints = *iterator;
break;
}
}
/* cleanup and return error */
freeaddrinfo(resolved);
*ps = sock;
return err;
}
/*-------------------------------------------------------------------------*\
* Some systems do not provide this so that we provide our own. It's not
* marvelously fast, but it works just fine.
* Some systems do not provide these so that we provide our own.
\*-------------------------------------------------------------------------*/
#ifdef INET_ATON
#ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
unsigned int a = 0, b = 0, c = 0, d = 0;
@ -278,4 +511,26 @@ int inet_aton(const char *cp, struct in_addr *inp)
}
#endif
#ifdef LUASOCKET_INET_PTON
int inet_pton(int af, const char *src, void *dst)
{
struct addrinfo hints, *res;
int ret = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = af;
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
if (af == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
} else if (af == AF_INET6) {
struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
} else {
ret = -1;
}
freeaddrinfo(res);
return ret;
}
#endif

View File

@ -13,30 +13,38 @@
* getpeername and getsockname functions as seen by Lua programs.
*
* The Lua functions toip and tohostname are also implemented here.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
#include "socket.h"
#include "timeout.h"
#ifdef _WIN32
#define INET_ATON
#define LUASOCKET_INET_ATON
#endif
int inet_open(lua_State *L);
const char *inet_trycreate(p_socket ps, int type);
const char *inet_tryconnect(p_socket ps, const char *address,
unsigned short port, p_timeout tm);
const char *inet_trybind(p_socket ps, const char *address,
unsigned short port);
const char *inet_trycreate(p_socket ps, int family, int type);
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints);
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints);
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
int inet_meth_getpeername(lua_State *L, p_socket ps);
int inet_meth_getsockname(lua_State *L, p_socket ps);
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
#ifdef INET_ATON
int inet_optfamily(lua_State* L, int narg, const char* def);
int inet_optsocktype(lua_State* L, int narg, const char* def);
#ifdef LUASOCKET_INET_ATON
int inet_aton(const char *cp, struct in_addr *inp);
#endif
#ifdef LUASOCKET_INET_PTON
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
int inet_pton(int af, const char *src, void *dst);
#endif
#endif /* INET_H */

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "io.h"

View File

@ -11,8 +11,6 @@
*
* The module socket.h implements this interface, and thus the module tcp.h
* is very simple.
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
#include "lua.h"
@ -24,7 +22,7 @@ enum {
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_UNKNOWN = -3
IO_UNKNOWN = -3
};
/* interface to error message function */

View File

@ -2,7 +2,6 @@
-- LTN12 - Filters, sources, sinks and pumps.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -11,16 +10,20 @@
local string = require("string")
local table = require("table")
local base = _G
module("ltn12")
local _M = {}
if module then -- heuristic for exporting a global package table
ltn12 = _M
end
local filter,source,sink,pump = {},{},{},{}
filter = {}
source = {}
sink = {}
pump = {}
_M.filter = filter
_M.source = source
_M.sink = sink
_M.pump = pump
-- 2048 seems to be better in windows...
BLOCKSIZE = 2048
_VERSION = "LTN12 1.0.1"
_M.BLOCKSIZE = 2048
_M._VERSION = "LTN12 1.0.3"
-----------------------------------------------------------------------------
-- Filter stuff
@ -38,7 +41,8 @@ end
-- chains a bunch of filters together
-- (thanks to Wim Couwenberg)
function filter.chain(...)
local n = table.getn(arg)
local arg = {...}
local n = select('#',...)
local top, index = 1, 1
local retry = ""
return function(chunk)
@ -89,7 +93,7 @@ end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(BLOCKSIZE)
local chunk = handle:read(_M.BLOCKSIZE)
if not chunk then handle:close() end
return chunk
end
@ -112,8 +116,8 @@ function source.string(s)
if s then
local i = 1
return function()
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
i = i + BLOCKSIZE
local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
i = i + _M.BLOCKSIZE
if chunk ~= "" then return chunk
else return nil end
end
@ -186,6 +190,7 @@ end
-- other, as if they were concatenated
-- (thanks to Wim Couwenberg)
function source.cat(...)
local arg = {...}
local src = table.remove(arg, 1)
return function()
while src do
@ -290,3 +295,4 @@ function pump.all(src, snk, step)
end
end
return _M

View File

@ -10,8 +10,6 @@
* involved in setting up both client and server connections. The provided
* IO routines, however, follow the Lua style, being very similar to the
* standard Lua read and write functions.
*
* RCS ID: $Id$
\*=========================================================================*/
/*=========================================================================*\
@ -20,9 +18,6 @@
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
/*=========================================================================*\
* LuaSocket includes
@ -47,7 +42,7 @@ static int base_open(lua_State *L);
/*-------------------------------------------------------------------------*\
* Modules and functions
\*-------------------------------------------------------------------------*/
static const luaL_reg mod[] = {
static const luaL_Reg mod[] = {
{"auxiliar", auxiliar_open},
{"except", except_open},
{"timeout", timeout_open},
@ -59,7 +54,7 @@ static const luaL_reg mod[] = {
{NULL, NULL}
};
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"skip", global_skip},
{"__unload", global_unload},
{NULL, NULL}
@ -83,13 +78,26 @@ static int global_unload(lua_State *L) {
return 0;
}
#if LUA_VERSION_NUM > 501
int luaL_typerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s",
tname, luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}
#endif
/*-------------------------------------------------------------------------*\
* Setup basic stuff.
\*-------------------------------------------------------------------------*/
static int base_open(lua_State *L) {
if (socket_open()) {
/* export functions (and leave namespace table on top of stack) */
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_newtable(L);
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, "socket", func, 0);
#endif
#ifdef LUASOCKET_DEBUG
lua_pushstring(L, "_DEBUG");
lua_pushboolean(L, 1);

View File

@ -5,17 +5,14 @@
* Networking support for the Lua language
* Diego Nehab
* 9/11/1999
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\
* Current socket library version
\*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 2.0.2"
#define LUASOCKET_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab"
#define LUASOCKET_AUTHORS "Diego Nehab"
#define LUASOCKET_VERSION "LuaSocket 3.0-rc1"
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab"
/*-------------------------------------------------------------------------*\
* This macro prefixes all exported API functions

View File

@ -1,90 +1,374 @@
#------
# Load configuration
# luasocket src/makefile
#
include ../config
# Definitions in this section can be overriden on the command line or in the
# environment.
#
# These are equivalent:
#
# export PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
# make
#
# and
#
# make PLAT=linux DEBUG=DEBUG LUAV=5.2 prefix=/sw
# PLAT: linux macosx win32 mingw
# platform to build for
PLAT?=linux
# LUAV: 5.1 5.2
# lua version to build against
LUAV?=5.1
# DEBUG: NODEBUG DEBUG
# debug mode causes luasocket to collect and returns timing information useful
# for testing and debugging luasocket itself
DEBUG?=NODEBUG
# COMPAT: COMPAT NOCOMPAT
# when compiling for 5.2, use LUA_COMPAT_MODULE
COMPAT?=NOCOMPAT
# where lua headers are found for macosx builds
# LUAINC_macosx:
# /opt/local/include
LUAINC_macosx_base?=/opt/local/include
LUAINC_macosx?=$(LUAINC_macosx_base)/lua/$(LUAV)
# FIXME default should this default to fink or to macports?
# What happens when more than one Lua version is installed?
LUAPREFIX_macosx?=/opt/local
CDIR_macosx?=lib/lua/$(LUAV)
LDIR_macosx?=share/lua/$(LUAV)
# LUAINC_linux:
# /usr/include/lua$(LUAV)
# /usr/local/include
# /usr/local/include/lua$(LUAV)
# where lua headers are found for linux builds
LUAINC_linux_base?=/usr/include
LUAINC_linux?=$(LUAINC_linux_base)/lua/$(LUAV)
LUAPREFIX_linux?=/usr/local
CDIR_linux?=lib/lua/$(LUAV)
LDIR_linux?=share/lua/$(LUAV)
# where lua headers are found for mingw builds
# LUAINC_mingw:
# /opt/local/include
LUAINC_mingw_base?=/usr/include
LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV)
LUALIB_mingw_base?=/usr/bin
LUALIB_mingw?=$(LUALIB_mingw_base)/lua/$(LUAV)/lua$(subst .,,$(LUAV)).dll
LUAPREFIX_mingw?=/usr
CDIR_mingw?=lua/$(LUAV)
LDIR_mingw?=lua/$(LUAV)/lua
# LUAINC_win32:
# LUALIB_win32:
# where lua headers and libraries are found for win32 builds
LUAINC_win32_base?=
LUAINC_win32?=$(LUAINC_win32_base)/lua/$(LUAV)
PLATFORM_win32?=Release
LUAPREFIX_win32?=
CDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)
LDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)/lua
LUALIB_win32?=$(LUAPREFIX_win32)/lua/$(LUAV)/$(PLATFORM_win32)
# prefix: /usr/local /usr /opt/local /sw
# the top of the default install tree
prefix?=$(LUAPREFIX_$(PLAT))
CDIR?=$(CDIR_$(PLAT))
LDIR?=$(LDIR_$(PLAT))
# DESTDIR: (no default)
# used by package managers to install into a temporary destination
DESTDIR=
#------
# Hopefully no need to change anything below this line
# Definitions below can be overridden on the make command line, but
# shouldn't have to be.
#------
# Install directories
#
INSTALL_DIR=install -d
INSTALL_DATA=install -m644
INSTALL_EXEC=install
INSTALL_TOP=$(DESTDIR)$(prefix)
INSTALL_TOP_LDIR=$(INSTALL_TOP)/$(LDIR)
INSTALL_TOP_CDIR=$(INSTALL_TOP)/$(CDIR)
INSTALL_SOCKET_LDIR=$(INSTALL_TOP_LDIR)/socket
INSTALL_SOCKET_CDIR=$(INSTALL_TOP_CDIR)/socket
INSTALL_MIME_LDIR=$(INSTALL_TOP_LDIR)/mime
INSTALL_MIME_CDIR=$(INSTALL_TOP_CDIR)/mime
print:
@echo PLAT=$(PLAT)
@echo LUAV=$(LUAV)
@echo DEBUG=$(DEBUG)
@echo prefix=$(prefix)
@echo LUAINC_$(PLAT)=$(LUAINC_$(PLAT))
@echo LUALIB_$(PLAT)=$(LUALIB_$(PLAT))
@echo INSTALL_TOP_CDIR=$(INSTALL_TOP_CDIR)
@echo INSTALL_TOP_LDIR=$(INSTALL_TOP_LDIR)
#------
# Supported platforms
#
PLATS= macosx linux win32 mingw
#------
# Compiler and linker settings
# for Mac OS X
SO_macosx=so
O_macosx=o
CC_macosx=gcc
DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN -DLUA_$(COMPAT)_MODULE \
-DLUASOCKET_API='__attribute__((visibility("default")))' \
-DUNIX_API='__attribute__((visibility("default")))' \
-DMIME_API='__attribute__((visibility("default")))'
CFLAGS_macosx= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
-fvisibility=hidden
LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
SOCKET_macosx=usocket.o
#------
# Compiler and linker settings
# for Linux
SO_linux=so
O_linux=o
CC_linux=gcc
DEF_linux=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
-DLUASOCKET_API='__attribute__((visibility("default")))' \
-DUNIX_API='__attribute__((visibility("default")))' \
-DMIME_API='__attribute__((visibility("default")))'
CFLAGS_linux= -I$(LUAINC) $(DEF) -pedantic -Wall -Wshadow -Wextra \
-Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
LDFLAGS_linux=-O -shared -fpic -o
LD_linux=gcc
SOCKET_linux=usocket.o
#------
# Compiler and linker settings
# for MingW
SO_mingw=dll
O_mingw=o
CC_mingw=gcc
DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
-DWINVER=0x0501 -DLUASOCKET_API='__declspec(dllexport)' \
-DMIME_API='__declspec(dllexport)'
CFLAGS_mingw= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
-fvisibility=hidden
LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o
LD_mingw=gcc
SOCKET_mingw=wsocket.o
#------
# Compiler and linker settings
# for Win32
SO_win32=dll
O_win32=obj
CC_win32=cl
DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
//D "LUASOCKET_API=__declspec(dllexport)" //D "_CRT_SECURE_NO_WARNINGS" \
//D "_WINDLL" //D "LUA_$(COMPAT)_MODULE" \
//D "MIME_API=__declspec(dllexport)" \
//D "LUASOCKET_$(DEBUG)"
CFLAGS_win32=//I "$(LUAINC)" $(DEF) //O2 //Ot //MD //W3 //nologo
LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
//MANIFEST //MANIFESTFILE:"intermediate.manifest" \
//MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
//MACHINE:X86 /LIBPATH:"$(shell cmd //c echo $(LUALIB))" \
lua$(subst .,,$(LUAV)).lib ws2_32.lib //OUT:
LD_win32=cl
SOCKET_win32=wsocket.obj
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) //Fo"$@" //c $<
#------
# Output file names
#
SO=$(SO_$(PLAT))
O=$(O_$(PLAT))
SOCKET_V=3.0-rc1
MIME_V=1.0.3
SOCKET_SO=socket.$(SO).$(SOCKET_V)
MIME_SO=mime.$(SO).$(MIME_V)
UNIX_SO=unix.$(SO)
SERIAL_SO=serial.$(SO)
SOCKET=$(SOCKET_$(PLAT))
#------
# Settings selected for platform
#
CC=$(CC_$(PLAT))
DEF=$(DEF_$(PLAT))
CFLAGS=$(CFLAGS_$(PLAT))
LDFLAGS=$(LDFLAGS_$(PLAT))
LD=$(LD_$(PLAT))
LUAINC= $(LUAINC_$(PLAT))
LUALIB= $(LUALIB_$(PLAT))
#------
# Modules belonging to socket-core
#
#$(COMPAT)/compat-5.1.o \
SOCKET_OBJS:= \
luasocket.o \
timeout.o \
buffer.o \
io.o \
auxiliar.o \
options.o \
inet.o \
tcp.o \
udp.o \
except.o \
select.o \
usocket.o
SOCKET_OBJS= \
luasocket.$(O) \
timeout.$(O) \
buffer.$(O) \
io.$(O) \
auxiliar.$(O) \
options.$(O) \
inet.$(O) \
$(SOCKET) \
except.$(O) \
select.$(O) \
tcp.$(O) \
udp.$(O)
#------
# Modules belonging mime-core
#
#$(COMPAT)/compat-5.1.o \
MIME_OBJS:=\
mime.o
MIME_OBJS= \
mime.$(O)
#------
# Modules belonging unix (local domain sockets)
#
UNIX_OBJS:=\
buffer.o \
auxiliar.o \
options.o \
timeout.o \
io.o \
usocket.o \
unix.o
UNIX_OBJS=\
buffer.$(O) \
auxiliar.$(O) \
options.$(O) \
timeout.$(O) \
io.$(O) \
usocket.$(O) \
unix.$(O)
all: $(SOCKET_SO) $(MIME_SO)
#------
# Modules belonging to serial (device streams)
#
SERIAL_OBJS:=\
buffer.$(O) \
auxiliar.$(O) \
options.$(O) \
timeout.$(O) \
io.$(O) \
usocket.$(O) \
serial.$(O)
#------
# Files to install
#
TO_SOCKET_LDIR= \
http.lua \
url.lua \
tp.lua \
ftp.lua \
headers.lua \
smtp.lua
TO_TOP_LDIR= \
ltn12.lua \
socket.lua \
mime.lua
#------
# Targets
#
default: $(PLAT)
macosx:
$(MAKE) all-unix PLAT=macosx
win32:
$(MAKE) all PLAT=win32
linux:
$(MAKE) all-unix PLAT=linux
mingw:
$(MAKE) all PLAT=mingw
none:
@echo "Please run"
@echo " make PLATFORM"
@echo "where PLATFORM is one of these:"
@echo " $(PLATS)"
all: $(SOCKET_SO) $(MIME_SO)
$(SOCKET_SO): $(SOCKET_OBJS)
$(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS)
$(LD) $(SOCKET_OBJS) $(LDFLAGS)$@
$(MIME_SO): $(MIME_OBJS)
$(LD) $(LDFLAGS) -o $@ $(MIME_OBJS)
$(LD) $(MIME_OBJS) $(LDFLAGS)$@
all-unix: all $(UNIX_SO) $(SERIAL_SO)
$(UNIX_SO): $(UNIX_OBJS)
$(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS)
$(LD) $(UNIX_OBJS) $(LDFLAGS)$@
$(SERIAL_SO): $(SERIAL_OBJS)
$(LD) $(SERIAL_OBJS) $(LDFLAGS)$@
install:
$(INSTALL_DIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DATA) $(TO_TOP_LDIR) $(INSTALL_TOP_LDIR)
$(INSTALL_DIR) $(INSTALL_SOCKET_LDIR)
$(INSTALL_DATA) $(TO_SOCKET_LDIR) $(INSTALL_SOCKET_LDIR)
$(INSTALL_DIR) $(INSTALL_SOCKET_CDIR)
$(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_CDIR)/core.$(SO)
$(INSTALL_DIR) $(INSTALL_MIME_CDIR)
$(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_CDIR)/core.$(SO)
install-unix: install
$(INSTALL_EXEC) $(UNIX_SO) $(INSTALL_SOCKET_CDIR)/$(UNIX_SO)
$(INSTALL_EXEC) $(SERIAL_SO) $(INSTALL_SOCKET_CDIR)/$(SERIAL_SO)
local:
$(MAKE) install INSTALL_TOP_CDIR=.. INSTALL_TOP_LDIR=..
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS) $(SERIAL_OBJS)
rm -f $(MIME_SO) $(UNIX_SO) $(SERIAL_SO) $(MIME_OBJS) $(UNIX_OBJS)
.PHONY: all $(PLATS) default clean echo none
#------
# List of dependencies
#
auxiliar.o: auxiliar.c auxiliar.h
buffer.o: buffer.c buffer.h io.h timeout.h
except.o: except.c except.h
inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h
io.o: io.c io.h timeout.h
luasocket.o: luasocket.c luasocket.h auxiliar.h except.h timeout.h \
buffer.h io.h inet.h socket.h usocket.h tcp.h udp.h select.h
mime.o: mime.c mime.h
options.o: options.c auxiliar.h options.h socket.h io.h timeout.h \
usocket.h inet.h
select.o: select.c socket.h io.h timeout.h usocket.h select.h
tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h tcp.h buffer.h
timeout.o: timeout.c auxiliar.h timeout.h
udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h inet.h \
options.h udp.h
unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h options.h \
unix.h buffer.h
usocket.o: usocket.c socket.h io.h timeout.h usocket.h
clean:
rm -f $(SOCKET_SO) $(SOCKET_OBJS)
rm -f $(MIME_SO) $(UNIX_SO) $(MIME_OBJS) $(UNIX_OBJS)
#------
# End of makefile configuration
#
auxiliar.$(O): auxiliar.c auxiliar.h
buffer.$(O): buffer.c buffer.h io.h timeout.h
except.$(O): except.c except.h
inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
io.$(O): io.c io.h timeout.h
luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
udp.h select.h
mime.$(O): mime.c mime.h
options.$(O): options.c auxiliar.h options.h socket.h io.h \
timeout.h usocket.h inet.h
select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
serial.$(O): serial.c auxiliar.h socket.h io.h timeout.h usocket.h \
options.h unix.h buffer.h
tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h tcp.h buffer.h
timeout.$(O): timeout.c auxiliar.h timeout.h
udp.$(O): udp.c auxiliar.h socket.h io.h timeout.h usocket.h \
inet.h options.h udp.h
unix.$(O): unix.c auxiliar.h socket.h io.h timeout.h usocket.h \
options.h unix.h buffer.h
usocket.$(O): usocket.c socket.h io.h timeout.h usocket.h
wsocket.$(O): wsocket.c socket.h io.h timeout.h usocket.h

View File

@ -1,14 +1,16 @@
local Public = {}
local _M = {}
mbox = Public
if module then
mbox = _M
end
function Public.split_message(message_s)
function _M.split_message(message_s)
local message = {}
message_s = string.gsub(message_s, "\r\n", "\n")
string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
if not message.body then
string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
end
if not message.headers and not message.body then
message.headers = message_s
@ -16,7 +18,7 @@ function Public.split_message(message_s)
return message.headers or "", message.body or ""
end
function Public.split_headers(headers_s)
function _M.split_headers(headers_s)
local headers = {}
headers_s = string.gsub(headers_s, "\r\n", "\n")
headers_s = string.gsub(headers_s, "\n[ ]+", " ")
@ -24,18 +26,18 @@ function Public.split_headers(headers_s)
return headers
end
function Public.parse_header(header_s)
function _M.parse_header(header_s)
header_s = string.gsub(header_s, "\n[ ]+", " ")
header_s = string.gsub(header_s, "\n+", "")
local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
return name, value
end
function Public.parse_headers(headers_s)
local headers_t = Public.split_headers(headers_s)
function _M.parse_headers(headers_s)
local headers_t = _M.split_headers(headers_s)
local headers = {}
for i = 1, table.getn(headers_t) do
local name, value = Public.parse_header(headers_t[i])
for i = 1, #headers_t do
local name, value = _M.parse_header(headers_t[i])
if name then
name = string.lower(name)
if headers[name] then
@ -46,7 +48,7 @@ function Public.parse_headers(headers_s)
return headers
end
function Public.parse_from(from)
function _M.parse_from(from)
local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
if not address then
_, __, address = string.find(from, "%s*(.+)%s*")
@ -54,35 +56,37 @@ function Public.parse_from(from)
name = name or ""
address = address or ""
if name == "" then name = address end
name = string.gsub(name, '"', "")
name = string.gsub(name, '"', "")
return name, address
end
function Public.split_mbox(mbox_s)
mbox = {}
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
local nj, i, j = 1, 1, 1
while 1 do
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
if not i then break end
local message = string.sub(mbox_s, j, i-1)
table.insert(mbox, message)
j = nj+1
end
return mbox
function _M.split_mbox(mbox_s)
mbox = {}
mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
local nj, i, j = 1, 1, 1
while 1 do
i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
if not i then break end
local message = string.sub(mbox_s, j, i-1)
table.insert(mbox, message)
j = nj+1
end
return mbox
end
function Public.parse(mbox_s)
local mbox = Public.split_mbox(mbox_s)
for i = 1, table.getn(mbox) do
mbox[i] = Public.parse_message(mbox[i])
end
return mbox
function _M.parse(mbox_s)
local mbox = _M.split_mbox(mbox_s)
for i = 1, #mbox do
mbox[i] = _M.parse_message(mbox[i])
end
return mbox
end
function Public.parse_message(message_s)
function _M.parse_message(message_s)
local message = {}
message.headers, message.body = Public.split_message(message_s)
message.headers = Public.parse_headers(message.headers)
message.headers, message.body = _M.split_message(message_s)
message.headers = _M.parse_headers(message.headers)
return message
end
return _M

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* MIME support functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
@ -35,12 +33,12 @@ static int mime_global_eol(lua_State *L);
static int mime_global_dot(lua_State *L);
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
static void b64setup(UC *b64unbase);
static void b64setup(UC *base);
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static void qpsetup(UC *qpclass, UC *qpunbase);
static void qpsetup(UC *class, UC *unbase);
static void qpquote(UC c, luaL_Buffer *buffer);
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t qpencode(UC c, UC *input, size_t size,
@ -48,7 +46,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
/* code support functions */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{ "dot", mime_global_dot },
{ "b64", mime_global_b64 },
{ "eol", mime_global_eol },
@ -83,7 +81,12 @@ static UC b64unbase[256];
\*-------------------------------------------------------------------------*/
MIME_API int luaopen_mime_core(lua_State *L)
{
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_newtable(L);
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, "mime", func, 0);
#endif
/* make version string available to scripts */
lua_pushstring(L, "_VERSION");
lua_pushstring(L, MIME_VERSION);
@ -135,7 +138,7 @@ static int mime_global_wrp(lua_State *L)
left = length;
luaL_addstring(&buffer, CRLF);
}
luaL_putchar(&buffer, *input);
luaL_addchar(&buffer, *input);
left--;
break;
}
@ -149,12 +152,12 @@ static int mime_global_wrp(lua_State *L)
/*-------------------------------------------------------------------------*\
* Fill base64 decode map.
\*-------------------------------------------------------------------------*/
static void b64setup(UC *b64unbase)
static void b64setup(UC *unbase)
{
int i;
for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i;
b64unbase['='] = 0;
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
unbase['='] = 0;
}
/*-------------------------------------------------------------------------*\
@ -265,6 +268,8 @@ static int mime_global_b64(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
@ -272,9 +277,12 @@ static int mime_global_b64(lua_State *L)
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */
if (!input) {
size_t osize = 0;
asize = b64pad(atom, asize, &buffer);
luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
/* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
@ -306,6 +314,8 @@ static int mime_global_unb64(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
@ -313,8 +323,11 @@ static int mime_global_unb64(lua_State *L)
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second is nil, we are done */
if (!input) {
size_t osize = 0;
luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
/* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
@ -343,24 +356,24 @@ static int mime_global_unb64(lua_State *L)
* Split quoted-printable characters into classes
* Precompute reverse map for encoding
\*-------------------------------------------------------------------------*/
static void qpsetup(UC *qpclass, UC *qpunbase)
static void qpsetup(UC *cl, UC *unbase)
{
int i;
for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN;
qpclass['\t'] = QP_IF_LAST;
qpclass[' '] = QP_IF_LAST;
qpclass['\r'] = QP_CR;
for (i = 0; i < 256; i++) qpunbase[i] = 255;
qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2;
qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5;
qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8;
qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10;
qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12;
qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13;
qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15;
qpunbase['f'] = 15;
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
cl['\t'] = QP_IF_LAST;
cl[' '] = QP_IF_LAST;
cl['\r'] = QP_CR;
for (i = 0; i < 256; i++) unbase[i] = 255;
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
unbase['f'] = 15;
}
/*-------------------------------------------------------------------------*\
@ -368,9 +381,9 @@ static void qpsetup(UC *qpclass, UC *qpunbase)
\*-------------------------------------------------------------------------*/
static void qpquote(UC c, luaL_Buffer *buffer)
{
luaL_putchar(buffer, '=');
luaL_putchar(buffer, qpbase[c >> 4]);
luaL_putchar(buffer, qpbase[c & 0x0F]);
luaL_addchar(buffer, '=');
luaL_addchar(buffer, qpbase[c >> 4]);
luaL_addchar(buffer, qpbase[c & 0x0F]);
}
/*-------------------------------------------------------------------------*\
@ -400,7 +413,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
qpquote(input[0], buffer);
luaL_addstring(buffer, marker);
return 0;
} else luaL_putchar(buffer, input[0]);
} else luaL_addchar(buffer, input[0]);
break;
/* might have to be quoted always */
case QP_QUOTED:
@ -408,7 +421,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
break;
/* might never have to be quoted */
default:
luaL_putchar(buffer, input[0]);
luaL_addchar(buffer, input[0]);
break;
}
input[0] = input[1]; input[1] = input[2];
@ -424,7 +437,7 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
{
size_t i;
for (i = 0; i < size; i++) {
if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]);
if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
else qpquote(input[i], buffer);
}
if (size > 0) luaL_addstring(buffer, EQCRLF);
@ -454,6 +467,8 @@ static int mime_global_qp(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
@ -494,7 +509,7 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
c = qpunbase[input[1]]; d = qpunbase[input[2]];
/* if it is an invalid, do not decode */
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
else luaL_putchar(buffer, (c << 4) + d);
else luaL_addchar(buffer, (char) ((c << 4) + d));
return 0;
case '\r':
if (size < 2) return size;
@ -502,7 +517,7 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
return 0;
default:
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
luaL_putchar(buffer, input[0]);
luaL_addchar(buffer, input[0]);
return 0;
}
}
@ -527,6 +542,8 @@ static int mime_global_unqp(lua_State *L)
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
@ -587,7 +604,7 @@ static int mime_global_qpwrp(lua_State *L)
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_putchar(&buffer, *input);
luaL_addchar(&buffer, *input);
left--;
break;
default:
@ -595,7 +612,7 @@ static int mime_global_qpwrp(lua_State *L)
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_putchar(&buffer, *input);
luaL_addchar(&buffer, *input);
left--;
break;
}
@ -630,7 +647,7 @@ static int eolprocess(int c, int last, const char *marker,
return c;
}
} else {
luaL_putchar(buffer, c);
luaL_addchar(buffer, (char) c);
return 0;
}
}
@ -670,7 +687,7 @@ static int mime_global_eol(lua_State *L)
\*-------------------------------------------------------------------------*/
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
{
luaL_putchar(buffer, c);
luaL_addchar(buffer, (char) c);
switch (c) {
case '\r':
return 1;
@ -678,7 +695,7 @@ static size_t dot(int c, size_t state, luaL_Buffer *buffer)
return (state == 1)? 2: 0;
case '.':
if (state == 2)
luaL_putchar(buffer, '.');
luaL_addchar(buffer, '.');
default:
return 0;
}
@ -705,7 +722,7 @@ static int mime_global_dot(lua_State *L)
while (input < last)
state = dot(*input++, state, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, state);
lua_pushnumber(L, (lua_Number) state);
return 2;
}

View File

@ -7,16 +7,14 @@
* This module provides functions to implement transfer content encodings
* and formatting conforming to RFC 2045. It is used by mime.lua, which
* provide a higher level interface to this functionality.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\
* Current MIME library version
\*-------------------------------------------------------------------------*/
#define MIME_VERSION "MIME 1.0.2"
#define MIME_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab"
#define MIME_VERSION "MIME 1.0.3"
#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab"
#define MIME_AUTHORS "Diego Nehab"
/*-------------------------------------------------------------------------*\

View File

@ -2,7 +2,6 @@
-- MIME support for the Lua language.
-- Author: Diego Nehab
-- Conforming to RFCs 2045-2049
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -13,12 +12,14 @@ local ltn12 = require("ltn12")
local mime = require("mime.core")
local io = require("io")
local string = require("string")
module("mime")
local _M = mime
-- encode, decode and wrap algorithm tables
encodet = {}
decodet = {}
wrapt = {}
local encodet, decodet, wrapt = {},{},{}
_M.encodet = encodet
_M.decodet = decodet
_M.wrapt = wrapt
-- creates a function that chooses a filter by name from a given table
local function choose(table)
@ -35,21 +36,21 @@ end
-- define the encoding filters
encodet['base64'] = function()
return ltn12.filter.cycle(b64, "")
return ltn12.filter.cycle(_M.b64, "")
end
encodet['quoted-printable'] = function(mode)
return ltn12.filter.cycle(qp, "",
return ltn12.filter.cycle(_M.qp, "",
(mode == "binary") and "=0D=0A" or "\r\n")
end
-- define the decoding filters
decodet['base64'] = function()
return ltn12.filter.cycle(unb64, "")
return ltn12.filter.cycle(_M.unb64, "")
end
decodet['quoted-printable'] = function()
return ltn12.filter.cycle(unqp, "")
return ltn12.filter.cycle(_M.unqp, "")
end
local function format(chunk)
@ -62,26 +63,28 @@ end
-- define the line-wrap filters
wrapt['text'] = function(length)
length = length or 76
return ltn12.filter.cycle(wrp, length, length)
return ltn12.filter.cycle(_M.wrp, length, length)
end
wrapt['base64'] = wrapt['text']
wrapt['default'] = wrapt['text']
wrapt['quoted-printable'] = function()
return ltn12.filter.cycle(qpwrp, 76, 76)
return ltn12.filter.cycle(_M.qpwrp, 76, 76)
end
-- function that choose the encoding, decoding or wrap algorithm
encode = choose(encodet)
decode = choose(decodet)
wrap = choose(wrapt)
_M.encode = choose(encodet)
_M.decode = choose(decodet)
_M.wrap = choose(wrapt)
-- define the end-of-line normalization filter
function normalize(marker)
return ltn12.filter.cycle(eol, 0, marker)
function _M.normalize(marker)
return ltn12.filter.cycle(_M.eol, 0, marker)
end
-- high level stuffing filter
function stuff()
return ltn12.filter.cycle(dot, 2)
function _M.stuff()
return ltn12.filter.cycle(_M.dot, 2)
end
return _M

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Common option interface
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
@ -17,9 +15,15 @@
* Internal functions prototypes
\*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name);
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_setint(lua_State *L, p_socket ps, int level, int name);
static int opt_getint(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name,
void *val, int len);
static int opt_get(lua_State *L, p_socket ps, int level, int name,
void *val, int* len);
/*=========================================================================*\
* Exported functions
@ -40,42 +44,116 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
return opt->func(L, ps);
}
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
{
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
return opt->func(L, ps);
}
/* enables reuse of local address */
int opt_reuseaddr(lua_State *L, p_socket ps)
int opt_set_reuseaddr(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
int opt_get_reuseaddr(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
/* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
int opt_get_reuseport(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
/* disables the Naggle algorithm */
int opt_tcp_nodelay(lua_State *L, p_socket ps)
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_keepalive(lua_State *L, p_socket ps)
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_set_keepalive(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_dontroute(lua_State *L, p_socket ps)
int opt_get_keepalive(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_set_dontroute(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
}
int opt_broadcast(lua_State *L, p_socket ps)
int opt_set_broadcast(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
}
int opt_ip_multicast_loop(lua_State *L, p_socket ps)
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
}
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
}
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
}
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
{
return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
}
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
int opt_linger(lua_State *L, p_socket ps)
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
}
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
}
int opt_set_linger(lua_State *L, p_socket ps)
{
struct linger li; /* obj, name, table */
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "on");
lua_gettable(L, 3);
if (!lua_isboolean(L, -1))
@ -89,29 +167,87 @@ int opt_linger(lua_State *L, p_socket ps)
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
}
int opt_ip_multicast_ttl(lua_State *L, p_socket ps)
int opt_get_linger(lua_State *L, p_socket ps)
{
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val));
struct linger li; /* obj, name */
int len = sizeof(li);
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
if (err)
return err;
lua_newtable(L);
lua_pushboolean(L, li.l_onoff);
lua_setfield(L, -2, "on");
lua_pushinteger(L, li.l_linger);
lua_setfield(L, -2, "timeout");
return 1;
}
int opt_ip_add_membership(lua_State *L, p_socket ps)
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{
return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
}
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
{
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
struct in_addr val;
val.s_addr = htonl(INADDR_ANY);
if (strcmp(address, "*") && !inet_aton(address, &val))
luaL_argerror(L, 3, "ip expected");
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &val, sizeof(val));
}
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
{
struct in_addr val;
socklen_t len = sizeof(val);
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, inet_ntoa(val));
return 1;
}
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
{
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
}
int opt_ip_drop_membersip(lua_State *L, p_socket ps)
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
{
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
}
int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
{
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
}
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
{
return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
}
int opt_get_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
/*=========================================================================*\
* Auxiliar functions
\*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
{
struct ip_mreq val; /* obj, name, table */
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
@ -129,6 +265,45 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
{
struct ipv6_mreq val; /* obj, opt-name, table */
memset(&val, 0, sizeof(val));
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 3);
/* By default we listen to interface on default route
* (sigh). However, interface= can override it. We should
* support either number, or name for it. Waiting for
* windows port of if_nametoindex */
if (!lua_isnil(L, -1)) {
if (lua_isnumber(L, -1)) {
val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1);
} else
luaL_argerror(L, -1, "number 'interface' field expected");
}
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
{
socklen_t socklen = *len;
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
*len = socklen;
return 0;
}
static
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
{
@ -141,9 +316,49 @@ int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
return 1;
}
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
int len = sizeof(val);
int err = opt_get(L, ps, level, name, (char *) &val, &len);
if (err)
return err;
lua_pushboolean(L, val);
return 1;
}
int opt_get_error(lua_State *L, p_socket ps)
{
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, socket_strerror(val));
return 1;
}
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static int opt_getint(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
int len = sizeof(val);
int err = opt_get(L, ps, level, name, (char *) &val, &len);
if (err)
return err;
lua_pushnumber(L, val);
return 1;
}
static int opt_setint(lua_State *L, p_socket ps, int level, int name)
{
int val = (int) lua_tonumber(L, 3); /* obj, name, int */
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}

View File

@ -6,8 +6,6 @@
*
* This module provides a common interface to socket options, used mainly by
* modules UDP and TCP.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
@ -20,20 +18,43 @@ typedef struct t_opt {
} t_opt;
typedef t_opt *p_opt;
/* supported options */
int opt_dontroute(lua_State *L, p_socket ps);
int opt_broadcast(lua_State *L, p_socket ps);
int opt_reuseaddr(lua_State *L, p_socket ps);
int opt_tcp_nodelay(lua_State *L, p_socket ps);
int opt_keepalive(lua_State *L, p_socket ps);
int opt_linger(lua_State *L, p_socket ps);
int opt_reuseaddr(lua_State *L, p_socket ps);
int opt_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_ip_add_membership(lua_State *L, p_socket ps);
int opt_ip_drop_membersip(lua_State *L, p_socket ps);
/* supported options for setoption */
int opt_set_dontroute(lua_State *L, p_socket ps);
int opt_set_broadcast(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
int opt_set_keepalive(lua_State *L, p_socket ps);
int opt_set_linger(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_reuseport(lua_State *L, p_socket ps);
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip6_add_membership(lua_State *L, p_socket ps);
int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
/* supported options for getoption */
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
int opt_get_keepalive(lua_State *L, p_socket ps);
int opt_get_linger(lua_State *L, p_socket ps);
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
int opt_get_error(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
int opt_get_ip6_v6only(lua_State *L, p_socket ps);
/* invokes the appropriate option handler */
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
#endif

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Select implementation
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
@ -18,8 +16,8 @@
\*=========================================================================*/
static t_socket getfd(lua_State *L);
static int dirty(lua_State *L);
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
int itab, fd_set *set);
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd);
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start);
@ -27,7 +25,7 @@ static void make_assoc(lua_State *L, int tab);
static int global_select(lua_State *L);
/* functions in library namespace */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"select", global_select},
{NULL, NULL}
};
@ -39,7 +37,14 @@ static luaL_reg func[] = {
* Initializes module
\*-------------------------------------------------------------------------*/
int select_open(lua_State *L) {
lua_pushstring(L, "_SETSIZE");
lua_pushnumber(L, FD_SETSIZE);
lua_rawset(L, -3);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -51,7 +56,7 @@ int select_open(lua_State *L) {
\*-------------------------------------------------------------------------*/
static int global_select(lua_State *L) {
int rtab, wtab, itab, ret, ndirty;
t_socket max_fd;
t_socket max_fd = SOCKET_INVALID;
fd_set rset, wset;
t_timeout tm;
double t = luaL_optnumber(L, 3, -1);
@ -60,12 +65,12 @@ static int global_select(lua_State *L) {
lua_newtable(L); itab = lua_gettop(L);
lua_newtable(L); rtab = lua_gettop(L);
lua_newtable(L); wtab = lua_gettop(L);
max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset);
collect_fd(L, 1, itab, &rset, &max_fd);
collect_fd(L, 2, itab, &wset, &max_fd);
ndirty = check_dirty(L, 1, rtab, &rset);
t = ndirty > 0? 0.0: t;
timeout_init(&tm, t, -1);
timeout_markstart(&tm);
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
if (ret > 0 || ndirty > 0) {
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
@ -77,7 +82,7 @@ static int global_select(lua_State *L) {
lua_pushstring(L, "timeout");
return 3;
} else {
lua_pushstring(L, "error");
luaL_error(L, "select failed");
return 3;
}
}
@ -92,8 +97,10 @@ static t_socket getfd(lua_State *L) {
if (!lua_isnil(L, -1)) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
if (lua_isnumber(L, -1))
fd = (t_socket) lua_tonumber(L, -1);
if (lua_isnumber(L, -1)) {
double numfd = lua_tonumber(L, -1);
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
}
}
lua_pop(L, 1);
return fd;
@ -112,12 +119,14 @@ static int dirty(lua_State *L) {
return is;
}
static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
int itab, fd_set *set) {
int i = 1;
if (lua_isnil(L, tab))
return max_fd;
while (1) {
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd) {
int i = 1, n = 0;
/* nil is the same as an empty table */
if (lua_isnil(L, tab)) return;
/* otherwise we need it to be a table */
luaL_checktype(L, tab, LUA_TTABLE);
for ( ;; ) {
t_socket fd;
lua_pushnumber(L, i);
lua_gettable(L, tab);
@ -125,26 +134,37 @@ static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd,
lua_pop(L, 1);
break;
}
/* getfd figures out if this is a socket */
fd = getfd(L);
if (fd != SOCKET_INVALID) {
/* make sure we don't overflow the fd_set */
#ifdef _WIN32
if (n >= FD_SETSIZE)
luaL_argerror(L, tab, "too many sockets");
#else
if (fd >= FD_SETSIZE)
luaL_argerror(L, tab, "descriptor too large for set size");
#endif
FD_SET(fd, set);
if (max_fd == SOCKET_INVALID || max_fd < fd)
max_fd = fd;
lua_pushnumber(L, fd);
n++;
/* keep track of the largest descriptor so far */
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
*max_fd = fd;
/* make sure we can map back from descriptor to the object */
lua_pushnumber(L, (lua_Number) fd);
lua_pushvalue(L, -2);
lua_settable(L, itab);
}
lua_pop(L, 1);
i = i + 1;
}
return max_fd;
}
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
int ndirty = 0, i = 1;
if (lua_isnil(L, tab))
return 0;
while (1) {
for ( ;; ) {
t_socket fd;
lua_pushnumber(L, i);
lua_gettable(L, tab);
@ -171,7 +191,7 @@ static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
for (fd = 0; fd < max_fd; fd++) {
if (FD_ISSET(fd, set)) {
lua_pushnumber(L, ++start);
lua_pushnumber(L, fd);
lua_pushnumber(L, (lua_Number) fd);
lua_gettable(L, itab);
lua_settable(L, tab);
}
@ -181,7 +201,7 @@ static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
static void make_assoc(lua_State *L, int tab) {
int i = 1, atab;
lua_newtable(L); atab = lua_gettop(L);
while (1) {
for ( ;; ) {
lua_pushnumber(L, i);
lua_gettable(L, tab);
if (!lua_isnil(L, -1)) {

View File

@ -8,8 +8,6 @@
* method getfd() which returns the descriptor to be passed to the
* underlying select function. Another method, dirty(), should return
* true if there is data ready for reading (required for buffered input).
*
* RCS ID: $Id$
\*=========================================================================*/
int select_open(lua_State *L);

188
src/serial.c Normal file
View File

@ -0,0 +1,188 @@
/*=========================================================================*\
* Serial stream
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <sys/un.h>
/*
Reuses userdata definition from unix.h, since it is useful for all
stream-like objects.
If we stored the serial path for use in error messages or userdata
printing, we might need our own userdata definition.
Group usage is semi-inherited from unix.c, but unnecessary since we
have only one object type.
*/
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_send(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_close(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
/* serial object methods */
static luaL_Reg serial_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"close", meth_close},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"settimeout", meth_settimeout},
{NULL, NULL}
};
/* our socket creation function */
/* this is an ad-hoc module that returns a single function
* as such, do not include other functions in this array. */
static luaL_Reg func[] = {
{"serial", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "serial{client}", serial_methods);
/* create class groups */
auxiliar_add2group(L, "serial{client}", "serial{any}");
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_pushcfunction(L, global_create);
(void) func;
#else
/* set function into socket namespace */
luaL_openlib(L, "socket", func, 0);
lua_pushcfunction(L, global_create);
#endif
return 1;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a serial object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
const char* path = luaL_checkstring(L, 1);
/* allocate unix object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* open serial device */
t_socket sock = open(path, O_NOCTTY|O_RDWR);
/*printf("open %s on %d\n", path, sock);*/
if (sock < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
lua_pushnumber(L, errno);
return 3;
}
/* set its type as client object */
auxiliar_setclass(L, "serial{client}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
}

View File

@ -2,7 +2,6 @@
-- SMTP client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -16,23 +15,26 @@ local os = require("os")
local socket = require("socket")
local tp = require("socket.tp")
local ltn12 = require("ltn12")
local headers = require("socket.headers")
local mime = require("mime")
module("socket.smtp")
socket.smtp = {}
local _M = socket.smtp
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- timeout for connection
TIMEOUT = 60
_M.TIMEOUT = 60
-- default server used to send e-mails
SERVER = "localhost"
_M.SERVER = "localhost"
-- default port
PORT = 25
_M.PORT = 25
-- domain used in HELO command and default sendmail
-- If we are under a CGI, try to get from environment
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost"
-- default time zone (means we don't know)
ZONE = "-0000"
_M.ZONE = "-0000"
---------------------------------------------------------------------------
-- Low level SMTP API
@ -41,7 +43,7 @@ local metat = { __index = {} }
function metat.__index:greet(domain)
self.try(self.tp:check("2.."))
self.try(self.tp:command("EHLO", domain or DOMAIN))
self.try(self.tp:command("EHLO", domain or _M.DOMAIN))
return socket.skip(1, self.try(self.tp:check("2..")))
end
@ -75,9 +77,9 @@ end
function metat.__index:login(user, password)
self.try(self.tp:command("AUTH", "LOGIN"))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(user)))
self.try(self.tp:send(mime.b64(user) .. "\r\n"))
self.try(self.tp:check("3.."))
self.try(self.tp:command(mime.b64(password)))
self.try(self.tp:send(mime.b64(password) .. "\r\n"))
return self.try(self.tp:check("2.."))
end
@ -111,9 +113,9 @@ function metat.__index:send(mailt)
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
end
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
TIMEOUT, create))
function _M.open(server, port, create)
local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,
_M.TIMEOUT, create))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
@ -146,10 +148,11 @@ end
local send_message
-- yield the headers all at once, it's faster
local function send_headers(headers)
local function send_headers(tosend)
local canonic = headers.canonic
local h = "\r\n"
for i,v in base.pairs(headers) do
h = i .. ': ' .. v .. "\r\n" .. h
for f,v in base.pairs(tosend) do
h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h
end
coroutine.yield(h)
end
@ -220,14 +223,14 @@ end
local function adjust_headers(mesgt)
local lower = lower_headers(mesgt.headers)
lower["date"] = lower["date"] or
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE)
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
-- this can't be overriden
lower["mime-version"] = "1.0"
return lower
end
function message(mesgt)
function _M.message(mesgt)
mesgt.headers = adjust_headers(mesgt)
-- create and return message source
local co = coroutine.create(function() send_message(mesgt) end)
@ -241,11 +244,13 @@ end
---------------------------------------------------------------------------
-- High level SMTP API
-----------------------------------------------------------------------------
send = socket.protect(function(mailt)
local s = open(mailt.server, mailt.port, mailt.create)
_M.send = socket.protect(function(mailt)
local s = _M.open(mailt.server, mailt.port, mailt.create)
local ext = s:greet(mailt.domain)
s:auth(mailt.user, mailt.password, ext)
s:send(mailt)
s:quit()
return s:close()
end)
return _M

View File

@ -8,8 +8,6 @@
* differences. Also, not all *nix platforms behave the same. This module
* (and the associated usocket.h and wsocket.h) factor these differences and
* creates a interface compatible with the io.h module.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "io.h"
@ -61,6 +59,7 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr,
socklen_t *addr_len, p_timeout tm);
const char *socket_hoststrerror(int err);
const char *socket_gaistrerror(int err);
const char *socket_strerror(int err);
/* these are perfect to use with the io abstraction module
@ -68,6 +67,9 @@ const char *socket_strerror(int err);
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
const char *socket_ioerror(p_socket ps, int err);
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);

View File

@ -1,7 +1,6 @@
-----------------------------------------------------------------------------
-- LuaSocket helper module
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -11,37 +10,52 @@ local base = _G
local string = require("string")
local math = require("math")
local socket = require("socket.core")
module("socket")
local _M = socket
-----------------------------------------------------------------------------
-- Exported auxiliar functions
-----------------------------------------------------------------------------
function connect(address, port, laddress, lport)
local sock, err = socket.tcp()
if not sock then return nil, err end
if laddress then
local res, err = sock:bind(laddress, lport, -1)
if not res then return nil, err end
function _M.connect4(address, port, laddress, lport)
return socket.connect(address, port, laddress, lport, "inet")
end
function _M.connect6(address, port, laddress, lport)
return socket.connect(address, port, laddress, lport, "inet6")
end
function _M.bind(host, port, backlog)
if host == "*" then host = "0.0.0.0" end
local addrinfo, err = socket.dns.getaddrinfo(host);
if not addrinfo then return nil, err end
local sock, res
err = "no info on address"
for i, alt in base.ipairs(addrinfo) do
if alt.family == "inet" then
sock, err = socket.tcp()
else
sock, err = socket.tcp6()
end
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
res, err = sock:bind(alt.addr, port)
if not res then
sock:close()
else
res, err = sock:listen(backlog)
if not res then
sock:close()
else
return sock
end
end
end
local res, err = sock:connect(address, port)
if not res then return nil, err end
return sock
return nil, err
end
function bind(host, port, backlog)
local sock, err = socket.tcp()
if not sock then return nil, err end
sock:setoption("reuseaddr", true)
local res, err = sock:bind(host, port)
if not res then return nil, err end
res, err = sock:listen(backlog)
if not res then return nil, err end
return sock
end
_M.try = _M.newtry()
try = newtry()
function choose(table)
function _M.choose(table)
return function(name, opt1, opt2)
if base.type(name) ~= "string" then
name, opt1, opt2 = "default", name, opt1
@ -56,10 +70,11 @@ end
-- Socket sources and sinks, conforming to LTN12
-----------------------------------------------------------------------------
-- create namespaces inside LuaSocket namespace
sourcet = {}
sinkt = {}
local sourcet, sinkt = {}, {}
_M.sourcet = sourcet
_M.sinkt = sinkt
BLOCKSIZE = 2048
_M.BLOCKSIZE = 2048
sinkt["close-when-done"] = function(sock)
return base.setmetatable({
@ -89,7 +104,7 @@ end
sinkt["default"] = sinkt["keep-open"]
sink = choose(sinkt)
_M.sink = _M.choose(sinkt)
sourcet["by-length"] = function(sock, length)
return base.setmetatable({
@ -129,5 +144,6 @@ end
sourcet["default"] = sourcet["until-closed"]
source = choose(sourcet)
_M.source = _M.choose(sourcet)
return _M

266
src/tcp.c
View File

@ -1,10 +1,8 @@
/*=========================================================================*\
* TCP object
* TCP object
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
@ -19,8 +17,11 @@
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create6(lua_State *L);
static int global_connect(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_getstats(lua_State *L);
@ -31,6 +32,7 @@ static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
@ -38,7 +40,7 @@ static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
/* tcp object methods */
static luaL_reg tcp[] = {
static luaL_Reg tcp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
@ -46,7 +48,9 @@ static luaL_reg tcp[] = {
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd},
{"getoption", meth_getoption},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
{"getstats", meth_getstats},
@ -64,17 +68,29 @@ static luaL_reg tcp[] = {
};
/* socket option handlers */
static t_opt opt[] = {
{"keepalive", opt_keepalive},
{"reuseaddr", opt_reuseaddr},
{"tcp-nodelay", opt_tcp_nodelay},
{"linger", opt_linger},
static t_opt optget[] = {
{"keepalive", opt_get_keepalive},
{"reuseaddr", opt_get_reuseaddr},
{"tcp-nodelay", opt_get_tcp_nodelay},
{"linger", opt_get_linger},
{"error", opt_get_error},
{NULL, NULL}
};
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"tcp-nodelay", opt_set_tcp_nodelay},
{"ipv6-v6only", opt_set_ip6_v6only},
{"linger", opt_set_linger},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"tcp", global_create},
{"tcp6", global_create6},
{"connect", global_connect},
{NULL, NULL}
};
@ -84,15 +100,19 @@ static luaL_reg func[] = {
int tcp_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "tcp{master}", tcp);
auxiliar_newclass(L, "tcp{client}", tcp);
auxiliar_newclass(L, "tcp{server}", tcp);
auxiliar_newclass(L, "tcp{master}", tcp_methods);
auxiliar_newclass(L, "tcp{client}", tcp_methods);
auxiliar_newclass(L, "tcp{server}", tcp_methods);
/* create class groups */
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */
luaL_openlib(L, NULL, func, 0);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -125,10 +145,16 @@ static int meth_setstats(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_getoption(L, optget, &tcp->sock);
}
static int meth_setoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_setoption(L, opt, &tcp->sock);
return opt_meth_setoption(L, optset, &tcp->sock);
}
/*-------------------------------------------------------------------------*\
@ -145,7 +171,7 @@ static int meth_getfd(lua_State *L)
static int meth_setfd(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
tcp->sock = (t_socket) luaL_checknumber(L, 2);
tcp->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
@ -157,43 +183,51 @@ static int meth_dirty(lua_State *L)
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L)
{
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
/* if successful, push client socket */
if (err == IO_DONE) {
if (err == NULL) {
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
auxiliar_setclass(L, "tcp{client}", -1);
/* initialize structure fields */
memset(clnt, 0, sizeof(t_tcp));
socket_setnonblocking(&sock);
clnt->sock = sock;
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
clnt->family = server->family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
const char *err = inet_trybind(&tcp->sock, address, port);
const char *port = luaL_checkstring(L, 3);
const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = tcp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&tcp->sock, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
@ -210,9 +244,16 @@ static int meth_connect(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
p_timeout tm = timeout_markstart(&tcp->tm);
const char *err = inet_tryconnect(&tcp->sock, address, port, tm);
const char *port = luaL_checkstring(L, 3);
struct addrinfo connecthints;
const char *err;
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = tcp->family;
timeout_markstart(&tcp->tm);
err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
&tcp->tm, &connecthints);
/* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1);
if (err) {
@ -220,13 +261,12 @@ static int meth_connect(lua_State *L)
lua_pushstring(L, err);
return 2;
}
/* turn master object into a client object */
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
@ -236,6 +276,21 @@ static int meth_close(lua_State *L)
return 1;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
if (tcp->family == PF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
}
/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
@ -260,27 +315,13 @@ static int meth_listen(lua_State *L)
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
const char *how = luaL_optstring(L, 2, "both");
switch (how[0]) {
case 'b':
if (strcmp(how, "both")) goto error;
socket_shutdown(&tcp->sock, 2);
break;
case 's':
if (strcmp(how, "send")) goto error;
socket_shutdown(&tcp->sock, 1);
break;
case 'r':
if (strcmp(how, "receive")) goto error;
socket_shutdown(&tcp->sock, 0);
break;
}
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
error:
luaL_argerror(L, 2, "invalid shutdown method");
return 0;
}
/*-------------------------------------------------------------------------*\
@ -289,13 +330,13 @@ error:
static int meth_getpeername(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getpeername(L, &tcp->sock);
return inet_meth_getpeername(L, &tcp->sock, tcp->family);
}
static int meth_getsockname(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getsockname(L, &tcp->sock);
return inet_meth_getsockname(L, &tcp->sock, tcp->family);
}
/*-------------------------------------------------------------------------*\
@ -311,25 +352,31 @@ static int meth_settimeout(lua_State *L)
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master tcp object
* Creates a master tcp object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L)
{
static int tcp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, SOCK_STREAM);
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
/* try to allocate a system socket */
if (!err) {
if (!err) {
/* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
}
tcp->sock = sock;
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->family = family;
return 1;
} else {
lua_pushnil(L);
@ -337,3 +384,106 @@ static int global_create(lua_State *L)
return 2;
}
}
static int global_create(lua_State *L) {
return tcp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return tcp_create(L, AF_INET6);
}
#if 0
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
struct addrinfo *connecthints, p_tcp tcp) {
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
/* iterate over all returned addresses trying to connect */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
p_timeout tm = timeout_markstart(&tcp->tm);
/* create new socket if necessary. if there was no
* bind, we need to create one for every new family
* that shows up while iterating. if there was a
* bind, all families will be the same and we will
* not enter this branch. */
if (tcp->family != iterator->ai_family) {
socket_destroy(&tcp->sock);
err = socket_strerror(socket_create(&tcp->sock,
iterator->ai_family, iterator->ai_socktype,
iterator->ai_protocol));
if (err != NULL) {
freeaddrinfo(resolved);
return err;
}
tcp->family = iterator->ai_family;
/* all sockets initially non-blocking */
socket_setnonblocking(&tcp->sock);
}
/* finally try connecting to remote address */
err = socket_strerror(socket_connect(&tcp->sock,
(SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
#endif
static int global_connect(lua_State *L) {
const char *remoteaddr = luaL_checkstring(L, 1);
const char *remoteserv = luaL_checkstring(L, 2);
const char *localaddr = luaL_optstring(L, 3, NULL);
const char *localserv = luaL_optstring(L, 4, "0");
int family = inet_optfamily(L, 5, "unspec");
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
struct addrinfo bindhints, connecthints;
const char *err = NULL;
/* initialize tcp structure */
memset(tcp, 0, sizeof(t_tcp));
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->sock = SOCKET_INVALID;
tcp->family = PF_UNSPEC;
/* allow user to pick local address and port */
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = family;
bindhints.ai_flags = AI_PASSIVE;
if (localaddr) {
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
tcp->family = bindhints.ai_family;
}
/* try to connect to remote address and port */
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = bindhints.ai_family;
err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
&tcp->tm, &connecthints);
if (err) {
socket_destroy(&tcp->sock);
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
auxiliar_setclass(L, "tcp{client}", -1);
return 1;
}

View File

@ -13,8 +13,6 @@
* objects are tcp objects bound to some local address. Client objects are
* tcp objects either connected to some address or returned by the accept
* method of a server object.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
@ -27,6 +25,7 @@ typedef struct t_tcp_ {
t_io io;
t_buffer buf;
t_timeout tm;
int family;
} t_tcp;
typedef t_tcp *p_tcp;

View File

@ -1,10 +1,10 @@
/*=========================================================================*\
* Timeout management functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include "lua.h"
#include "lauxlib.h"
@ -33,7 +33,7 @@
static int timeout_lua_gettime(lua_State *L);
static int timeout_lua_sleep(lua_State *L);
static luaL_reg func[] = {
static luaL_Reg func[] = {
{ "gettime", timeout_lua_gettime },
{ "sleep", timeout_lua_sleep },
{ NULL, NULL }
@ -144,7 +144,11 @@ double timeout_gettime(void) {
* Initializes module
\*-------------------------------------------------------------------------*/
int timeout_open(lua_State *L) {
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -187,13 +191,23 @@ static int timeout_lua_gettime(lua_State *L)
/*-------------------------------------------------------------------------*\
* Sleep for n seconds.
\*-------------------------------------------------------------------------*/
#ifdef _WIN32
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
#ifdef _WIN32
Sleep((int)(n*1000));
if (n < 0.0) n = 0.0;
if (n < DBL_MAX/1000.0) n *= 1000.0;
if (n > INT_MAX) n = INT_MAX;
Sleep((int)n);
return 0;
}
#else
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
struct timespec t, r;
if (n < 0.0) n = 0.0;
if (n > INT_MAX) n = INT_MAX;
t.tv_sec = (int) n;
n -= t.tv_sec;
t.tv_nsec = (int) (n * 1000000000);
@ -202,6 +216,6 @@ int timeout_lua_sleep(lua_State *L)
t.tv_sec = r.tv_sec;
t.tv_nsec = r.tv_nsec;
}
#endif
return 0;
}
#endif

View File

@ -3,8 +3,6 @@
/*=========================================================================*\
* Timeout management functions
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"

View File

@ -2,7 +2,6 @@
-- Unified SMTP/FTP subsystem
-- LuaSocket toolkit.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
@ -12,12 +11,14 @@ local base = _G
local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.tp")
socket.tp = {}
local _M = socket.tp
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
TIMEOUT = 60
_M.TIMEOUT = 60
-----------------------------------------------------------------------------
-- Implementation
@ -64,6 +65,7 @@ function metat.__index:check(ok)
end
function metat.__index:command(cmd, arg)
cmd = string.upper(cmd)
if arg then
return self.c:send(cmd .. " " .. arg.. "\r\n")
else
@ -105,14 +107,14 @@ end
-- closes the underlying c
function metat.__index:close()
self.c:close()
return 1
return 1
end
-- connect with server and return c object
function connect(host, port, timeout, create)
function _M.connect(host, port, timeout, create)
local c, e = (create or socket.tcp)()
if not c then return nil, e end
c:settimeout(timeout or TIMEOUT)
c:settimeout(timeout or _M.TIMEOUT)
local r, e = c:connect(host, port)
if not r then
c:close()
@ -121,3 +123,4 @@ function connect(host, port, timeout, create)
return base.setmetatable({c = c}, metat)
end
return _M

235
src/udp.c
View File

@ -1,10 +1,9 @@
/*=========================================================================*\
* UDP object
* UDP object
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
@ -18,36 +17,40 @@
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
#endif
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create6(lua_State *L);
static int meth_send(lua_State *L);
static int meth_sendto(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_receivefrom(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L);
static int meth_setsockname(lua_State *L);
static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
/* udp object methods */
static luaL_reg udp[] = {
static luaL_Reg udp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"close", meth_close},
{"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
@ -57,27 +60,49 @@ static luaL_reg udp[] = {
{"sendto", meth_sendto},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"getoption", meth_getoption},
{"setpeername", meth_setpeername},
{"setsockname", meth_setsockname},
{"settimeout", meth_settimeout},
{NULL, NULL}
};
/* socket options */
static t_opt opt[] = {
{"dontroute", opt_dontroute},
{"broadcast", opt_broadcast},
{"reuseaddr", opt_reuseaddr},
{"ip-multicast-ttl", opt_ip_multicast_ttl},
{"ip-multicast-loop", opt_ip_multicast_loop},
{"ip-add-membership", opt_ip_add_membership},
{"ip-drop-membership", opt_ip_drop_membersip},
{NULL, NULL}
/* socket options for setoption */
static t_opt optset[] = {
{"dontroute", opt_set_dontroute},
{"broadcast", opt_set_broadcast},
{"reuseaddr", opt_set_reuseaddr},
{"reuseport", opt_set_reuseport},
{"ip-multicast-if", opt_set_ip_multicast_if},
{"ip-multicast-ttl", opt_set_ip_multicast_ttl},
{"ip-multicast-loop", opt_set_ip_multicast_loop},
{"ip-add-membership", opt_set_ip_add_membership},
{"ip-drop-membership", opt_set_ip_drop_membersip},
{"ipv6-unicast-hops", opt_set_ip6_unicast_hops},
{"ipv6-multicast-hops", opt_set_ip6_unicast_hops},
{"ipv6-multicast-loop", opt_set_ip6_multicast_loop},
{"ipv6-add-membership", opt_set_ip6_add_membership},
{"ipv6-drop-membership", opt_set_ip6_drop_membersip},
{"ipv6-v6only", opt_set_ip6_v6only},
{NULL, NULL}
};
/* socket options for getoption */
static t_opt optget[] = {
{"ip-multicast-if", opt_get_ip_multicast_if},
{"ip-multicast-loop", opt_get_ip_multicast_loop},
{"error", opt_get_error},
{"ipv6-unicast-hops", opt_get_ip6_unicast_hops},
{"ipv6-multicast-hops", opt_get_ip6_unicast_hops},
{"ipv6-multicast-loop", opt_get_ip6_multicast_loop},
{"ipv6-v6only", opt_get_ip6_v6only},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_reg func[] = {
static luaL_Reg func[] = {
{"udp", global_create},
{"udp6", global_create6},
{NULL, NULL}
};
@ -87,15 +112,19 @@ static luaL_reg func[] = {
int udp_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "udp{connected}", udp);
auxiliar_newclass(L, "udp{unconnected}", udp);
auxiliar_newclass(L, "udp{connected}", udp_methods);
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
/* create class groups */
auxiliar_add2group(L, "udp{connected}", "udp{any}");
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
auxiliar_add2group(L, "udp{connected}", "select{able}");
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */
luaL_openlib(L, NULL, func, 0);
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
luaL_setfuncs(L, func, 0);
#else
luaL_openlib(L, NULL, func, 0);
#endif
return 0;
}
@ -125,7 +154,7 @@ static int meth_send(lua_State *L) {
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushnumber(L, sent);
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
@ -137,24 +166,31 @@ static int meth_sendto(lua_State *L) {
size_t count, sent = 0;
const char *data = luaL_checklstring(L, 2, &count);
const char *ip = luaL_checkstring(L, 3);
unsigned short port = (unsigned short) luaL_checknumber(L, 4);
const char *port = luaL_checkstring(L, 4);
p_timeout tm = &udp->tm;
struct sockaddr_in addr;
int err;
memset(&addr, 0, sizeof(addr));
if (!inet_aton(ip, &addr.sin_addr))
luaL_argerror(L, 3, "invalid ip address");
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
struct addrinfo aihint;
struct addrinfo *ai;
memset(&aihint, 0, sizeof(aihint));
aihint.ai_family = udp->family;
aihint.ai_socktype = SOCK_DGRAM;
aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
err = getaddrinfo(ip, port, &aihint, &ai);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
(socklen_t) ai->ai_addrlen, tm);
freeaddrinfo(ai);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushnumber(L, sent);
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
@ -170,6 +206,9 @@ static int meth_receive(lua_State *L) {
count = MIN(count, sizeof(buffer));
timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
@ -182,28 +221,55 @@ static int meth_receive(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Receives data and sender from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L) {
static int meth_receivefrom(lua_State *L)
{
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
int err;
p_timeout tm = &udp->tm;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
char addrstr[INET6_ADDRSTRLEN];
char portstr[6];
timeout_markstart(tm);
count = MIN(count, sizeof(buffer));
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
if (err == IO_DONE) {
lua_pushlstring(L, buffer, got);
lua_pushstring(L, inet_ntoa(addr.sin_addr));
lua_pushnumber(L, ntohs(addr.sin_port));
return 3;
} else {
err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr,
&addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
return 2;
}
lua_pushlstring(L, buffer, got);
lua_pushstring(L, addrstr);
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
return 3;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
if (udp->family == PF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
}
/*-------------------------------------------------------------------------*\
@ -234,12 +300,12 @@ static int meth_dirty(lua_State *L) {
\*-------------------------------------------------------------------------*/
static int meth_getpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
return inet_meth_getpeername(L, &udp->sock);
return inet_meth_getpeername(L, &udp->sock, udp->family);
}
static int meth_getsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return inet_meth_getsockname(L, &udp->sock);
return inet_meth_getsockname(L, &udp->sock, udp->family);
}
/*-------------------------------------------------------------------------*\
@ -247,7 +313,15 @@ static int meth_getsockname(lua_State *L) {
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_setoption(L, opt, &udp->sock);
return opt_meth_setoption(L, optset, &udp->sock);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_getoption(L, optget, &udp->sock);
}
/*-------------------------------------------------------------------------*\
@ -264,26 +338,37 @@ static int meth_settimeout(lua_State *L) {
static int meth_setpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
p_timeout tm = &udp->tm;
const char *address = luaL_checkstring(L, 2);
const char *address = luaL_checkstring(L, 2);
int connecting = strcmp(address, "*");
unsigned short port = connecting ?
(unsigned short) luaL_checknumber(L, 3) :
(unsigned short) luaL_optnumber(L, 3, 0);
const char *err = inet_tryconnect(&udp->sock, address, port, tm);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
const char *port = connecting? luaL_checkstring(L, 3): "0";
struct addrinfo connecthints;
const char *err;
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_DGRAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = udp->family;
if (connecting) {
err = inet_tryconnect(&udp->sock, &udp->family, address,
port, tm, &connecthints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
auxiliar_setclass(L, "udp{connected}", 1);
} else {
/* we ignore possible errors because Mac OS X always
* returns EAFNOSUPPORT */
inet_trydisconnect(&udp->sock, udp->family, tm);
auxiliar_setclass(L, "udp{unconnected}", 1);
}
/* change class to connected or unconnected depending on address */
if (connecting) auxiliar_setclass(L, "udp{connected}", 1);
else auxiliar_setclass(L, "udp{unconnected}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
@ -298,8 +383,14 @@ static int meth_close(lua_State *L) {
static int meth_setsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
const char *err = inet_trybind(&udp->sock, address, port);
const char *port = luaL_checkstring(L, 3);
const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_DGRAM;
bindhints.ai_family = udp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&udp->sock, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
@ -313,20 +404,26 @@ static int meth_setsockname(lua_State *L) {
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master udp object
* Creates a master udp object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
static int udp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
/* try to allocate a system socket */
if (!err) {
/* allocate tcp object */
if (!err) {
/* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
}
udp->sock = sock;
timeout_init(&udp->tm, -1, -1);
udp->family = family;
return 1;
} else {
lua_pushnil(L);
@ -334,3 +431,11 @@ static int global_create(lua_State *L) {
return 2;
}
}
static int global_create(lua_State *L) {
return udp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return udp_create(L, AF_INET6);
}

View File

@ -11,8 +11,6 @@
* originally unconnected. They can be "connected" to a given address
* with a call to the setpeername function. The same function can be used to
* break the connection.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
@ -25,6 +23,7 @@
typedef struct t_udp_ {
t_socket sock;
t_timeout tm;
int family;
} t_udp;
typedef t_udp *p_udp;

View File

@ -1,8 +1,6 @@
/*=========================================================================*\
* Unix domain socket
* LuaSocket toolkit
*
* RCS ID: $Id$
\*=========================================================================*/
#include <string.h>
@ -39,7 +37,7 @@ static const char *unix_tryconnect(p_unix un, const char *path);
static const char *unix_trybind(p_unix un, const char *path);
/* unix object methods */
static luaL_reg un[] = {
static luaL_Reg unix_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
@ -63,15 +61,17 @@ static luaL_reg un[] = {
};
/* socket option handlers */
static t_opt opt[] = {
{"keepalive", opt_keepalive},
{"reuseaddr", opt_reuseaddr},
{"linger", opt_linger},
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"linger", opt_set_linger},
{NULL, NULL}
};
/* our socket creation function */
static luaL_reg func[] = {
/* this is an ad-hoc module that returns a single function
* as such, do not include other functions in this array. */
static luaL_Reg func[] = {
{"unix", global_create},
{NULL, NULL}
};
@ -82,18 +82,22 @@ static luaL_reg func[] = {
\*-------------------------------------------------------------------------*/
int luaopen_socket_unix(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "unix{master}", un);
auxiliar_newclass(L, "unix{client}", un);
auxiliar_newclass(L, "unix{server}", un);
auxiliar_newclass(L, "unix{master}", unix_methods);
auxiliar_newclass(L, "unix{client}", unix_methods);
auxiliar_newclass(L, "unix{server}", unix_methods);
/* create class groups */
auxiliar_add2group(L, "unix{master}", "unix{any}");
auxiliar_add2group(L, "unix{client}", "unix{any}");
auxiliar_add2group(L, "unix{server}", "unix{any}");
/* make sure the function ends up in the package table */
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
lua_pushcfunction(L, global_create);
(void) func;
#else
/* set function into socket namespace */
luaL_openlib(L, "socket", func, 0);
lua_pushcfunction(L, global_create);
#endif
/* return the function instead of the 'socket' table */
lua_pushstring(L, "unix");
lua_gettable(L, -2);
return 1;
}
@ -128,7 +132,7 @@ static int meth_setstats(lua_State *L) {
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
return opt_meth_setoption(L, opt, &un->sock);
return opt_meth_setoption(L, optset, &un->sock);
}
/*-------------------------------------------------------------------------*\
@ -294,27 +298,13 @@ static int meth_listen(lua_State *L)
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
const char *how = luaL_optstring(L, 2, "both");
switch (how[0]) {
case 'b':
if (strcmp(how, "both")) goto error;
socket_shutdown(&un->sock, 2);
break;
case 's':
if (strcmp(how, "send")) goto error;
socket_shutdown(&un->sock, 1);
break;
case 'r':
if (strcmp(how, "receive")) goto error;
socket_shutdown(&un->sock, 0);
break;
}
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
error:
luaL_argerror(L, 2, "invalid shutdown method");
return 0;
}
/*-------------------------------------------------------------------------*\

View File

@ -6,8 +6,6 @@
*
* This module is just an example of how to extend LuaSocket with a new
* domain.
*
* RCS ID: $Id$
\*=========================================================================*/
#include "lua.h"
@ -15,6 +13,10 @@
#include "timeout.h"
#include "socket.h"
#ifndef UNIX_API
#define UNIX_API extern
#endif
typedef struct t_unix_ {
t_socket sock;
t_io io;
@ -23,6 +25,6 @@ typedef struct t_unix_ {
} t_unix;
typedef t_unix *p_unix;
int luaopen_socketunix(lua_State *L);
UNIX_API int luaopen_socket_unix(lua_State *L);
#endif /* UNIX_H */

Some files were not shown because too many files have changed in this diff Show More