2 nixio - Linux I/O library for lua
4 Copyright 2009 Steven Barth <steven@midlink.org>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
15 local table = require "table"
16 local nixio = require "nixio"
17 local getmetatable, assert, pairs, type = getmetatable, assert, pairs, type
21 local BUFFERSIZE = nixio.const.buffersize
22 local ZIOBLKSIZE = 65536
23 local socket = nixio.meta_socket
24 local tls_socket = nixio.meta_tls_socket
25 local file = nixio.meta_file
26 local uname = nixio.uname()
27 local ZBUG = uname.sysname == "Linux" and uname.release:sub(1, 3) == "2.4"
29 function consume(iter, append)
30 local tbl = append or {}
39 function meta.is_socket(self)
40 return (getmetatable(self) == socket)
43 function meta.is_tls_socket(self)
44 return (getmetatable(self) == tls_socket)
47 function meta.is_file(self)
48 return (getmetatable(self) == file)
51 function meta.readall(self, len)
52 local block, code, msg = self:read(len or BUFFERSIZE)
55 return nil, code, msg, ""
56 elseif #block == 0 then
57 return "", nil, nil, ""
60 local data, total = {block}, #block
62 while not len or len > total do
63 block, code, msg = self:read(len and (len - total) or BUFFERSIZE)
66 return nil, code, msg, table.concat(data)
67 elseif #block == 0 then
71 data[#data+1], total = block, total + #block
74 local data = #data > 1 and table.concat(data) or data[1]
75 return data, nil, nil, data
77 meta.recvall = meta.readall
79 function meta.writeall(self, data)
80 local sent, code, msg = self:write(data)
83 return nil, code, msg, 0
88 while total < #data do
89 sent, code, msg = self:write(data, total)
92 return nil, code, msg, total
98 return total, nil, nil, total
100 meta.sendall = meta.writeall
102 function meta.linesource(self, limit)
103 limit = limit or BUFFERSIZE
106 return function(flush)
110 line = buffer:sub(bpos + 1)
111 buffer = type(flush) == "string" and flush or ""
117 _, endp, line = buffer:find("(.-)\r?\n", bpos + 1)
121 elseif #buffer < limit + bpos then
122 local newblock, code, msg = self:read(limit + bpos - #buffer)
124 return nil, code, msg
125 elseif #newblock == 0 then
128 buffer = buffer:sub(bpos + 1) .. newblock
137 function meta.blocksource(self, bs, limit)
138 bs = bs or BUFFERSIZE
144 elseif limit < toread then
149 local block, code, msg = self:read(toread)
152 return nil, code, msg
153 elseif #block == 0 then
157 limit = limit - #block
165 function meta.sink(self, close)
166 return function(chunk, src_err)
167 if not chunk and not src_err and close then
168 if self.shutdown then
172 elseif chunk and #chunk > 0 then
173 return self:writeall(chunk)
179 function meta.copy(self, fdout, size)
180 local source = self:blocksource(nil, size)
181 local sink = fdout:sink()
182 local sent, chunk, code, msg = 0
185 chunk, code, msg = source()
186 sink(chunk, code, msg)
187 sent = chunk and (sent + #chunk) or sent
189 return not code and sent or nil, code, msg, sent
192 function meta.copyz(self, fd, size)
193 local sent, lsent, code, msg = 0
196 if not ZBUG and self:is_file() then
197 local ftype = self:stat("type")
198 if nixio.sendfile and fd:is_socket() and ftype == "reg" then
200 lsent, code, msg = nixio.sendfile(fd, self, size or ZIOBLKSIZE)
203 size = size and (size - lsent)
205 until (not lsent or lsent == 0 or (size and size == 0))
206 if lsent or (not lsent and sent == 0 and
207 code ~= nixio.const.ENOSYS and code ~= nixio.const.EINVAL) then
208 return lsent and sent, code, msg, sent
210 elseif nixio.splice and not fd:is_tls_socket() and ftype == "fifo" then
215 if nixio.splice and fd:is_file() and not splicable then
216 splicable = not self:is_tls_socket() and fd:stat("type") == "fifo"
221 lsent, code, msg = nixio.splice(self, fd, size or ZIOBLKSIZE)
224 size = size and (size - lsent)
226 until (not lsent or lsent == 0 or (size and size == 0))
227 if lsent or (not lsent and sent == 0 and
228 code ~= nixio.const.ENOSYS and code ~= nixio.const.EINVAL) then
229 return lsent and sent, code, msg, sent
233 return self:copy(fd, size)
236 function tls_socket.close(self)
237 return self.socket:close()
240 function tls_socket.getsockname(self)
241 return self.socket:getsockname()
244 function tls_socket.getpeername(self)
245 return self.socket:getpeername()
248 function tls_socket.getsockopt(self, ...)
249 return self.socket:getsockopt(...)
251 tls_socket.getopt = tls_socket.getsockopt
253 function tls_socket.setsockopt(self, ...)
254 return self.socket:setsockopt(...)
256 tls_socket.setopt = tls_socket.setsockopt
258 for k, v in pairs(meta) do