From 5ff898e6248b668430f5f2e7d70de243f191eb04 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Thu, 12 Feb 2009 19:48:06 +0000 Subject: [PATCH] nixio next splice() still does not work correctly --- libs/nixio/Makefile | 2 +- libs/nixio/lua/nixio/util.lua | 70 ++++++++++++ libs/nixio/src/address.c | 6 +- libs/nixio/src/bind.c | 4 +- libs/nixio/src/file.c | 202 ++++++++++++++++++++++++++++++++++ libs/nixio/src/io.c | 4 +- libs/nixio/src/nixio.c | 36 +++--- libs/nixio/src/nixio.h | 12 ++ libs/nixio/src/poll.c | 4 +- libs/nixio/src/socket.c | 4 +- libs/nixio/src/sockopt.c | 6 +- libs/nixio/src/splice.c | 91 +++++++++++++++ 12 files changed, 405 insertions(+), 36 deletions(-) create mode 100644 libs/nixio/lua/nixio/util.lua create mode 100644 libs/nixio/src/file.c create mode 100644 libs/nixio/src/splice.c diff --git a/libs/nixio/Makefile b/libs/nixio/Makefile index 6cc7254c8..53869bfba 100644 --- a/libs/nixio/Makefile +++ b/libs/nixio/Makefile @@ -5,7 +5,7 @@ include ../../build/gccconfig.mk %.o: %.c $(COMPILE) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< -compile: src/nixio.o src/socket.o src/sockopt.o src/bind.o src/address.o src/poll.o src/io.o +compile: src/nixio.o src/socket.o src/sockopt.o src/bind.o src/address.o src/poll.o src/io.o src/file.o src/splice.o $(LINK) $(SHLIB_FLAGS) -o src/nixio.so src/*.o mkdir -p dist$(LUA_LIBRARYDIR) cp src/nixio.so dist$(LUA_LIBRARYDIR)/nixio.so diff --git a/libs/nixio/lua/nixio/util.lua b/libs/nixio/lua/nixio/util.lua new file mode 100644 index 000000000..962ef9d80 --- /dev/null +++ b/libs/nixio/lua/nixio/util.lua @@ -0,0 +1,70 @@ +--[[ +nixio - Linux I/O library for lua + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local nixio = require "nixio" +local setmetatable, assert = setmetatable, assert + +module "nixio.util" + +local BUFFERSIZE = 8096 +local socket = nixio.socket_meta + +function socket.sendall(self, data) + local sent, code, msg = self:send(data) + + if not sent then + return sent, code, msg, data + end + + while sent < #data do + data = data:sub(sent + 1) + sent, code, msg = self:send(data) + + if not sent then + return sent, code, msg, data + end + end + + return true +end + +function socket.linesource(self, limit) + limit = limit or BUFFERSIZE + local buffer = "" + return function(flush) + local line, endp, _ + + if flush then + line = buffer + buffer = "" + return line + end + + while not line do + _, endp, line = buffer:find("^(.-)\r?\n") + if line then + buffer = buffer:sub(endp+1) + return line + elseif #buffer < limit then + local newblock, code = self:recv(limit - #buffer) + if not newblock then + return nil, code + end + buffer = buffer .. newblock + else + return nil, 0 + end + end + end +end \ No newline at end of file diff --git a/libs/nixio/src/address.c b/libs/nixio/src/address.c index ae01c19ea..9ff063a33 100644 --- a/libs/nixio/src/address.c +++ b/libs/nixio/src/address.c @@ -16,15 +16,13 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include #include #include -#include "nixio.h" + /** * getaddrinfo(host, family, port) diff --git a/libs/nixio/src/bind.c b/libs/nixio/src/bind.c index 66337eeb5..678ae5592 100644 --- a/libs/nixio/src/bind.c +++ b/libs/nixio/src/bind.c @@ -16,9 +16,7 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include diff --git a/libs/nixio/src/file.c b/libs/nixio/src/file.c new file mode 100644 index 000000000..13a40c499 --- /dev/null +++ b/libs/nixio/src/file.c @@ -0,0 +1,202 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include +#include +#include +#include +#include + + +static int nixio_file(lua_State *L) { + const char *filename = luaL_checklstring(L, 1, NULL); + const char *mode = luaL_optlstring(L, 2, "r", NULL); + + FILE *file = fopen(filename, mode); + if (!file) { + return nixio__perror(L); + } + + FILE **udata = lua_newuserdata(L, sizeof(FILE**)); + *udata = file; + + luaL_getmetatable(L, NIXIO_FILE_META); + lua_setmetatable(L, -2); + + return 1; +} + +static int nixio_pipe(lua_State *L) { + int pipefd[2]; + FILE **udata; + if (pipe(pipefd)) { + return nixio__perror(L); + } + + luaL_getmetatable(L, NIXIO_FILE_META); + udata = lua_newuserdata(L, sizeof(FILE**)); + if (!(*udata = fdopen(pipefd[0], "r"))) { + return nixio__perror(L); + } + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); + + + udata = lua_newuserdata(L, sizeof(FILE**)); + if (!(*udata = fdopen(pipefd[1], "w"))) { + return nixio__perror(L); + } + lua_pushvalue(L, -3); + lua_setmetatable(L, -2); + + return 2; +} + +static int nixio_file_write(lua_State *L) { + FILE *fp = nixio__checkfile(L); + size_t len, written; + const char *data = luaL_checklstring(L, 2, &len); + written = fwrite(data, sizeof(char), len, fp); + if (written < 0) { + return nixio__perror(L); + } else { + return written; + } +} + + +/* Some code borrowed from Lua 5.1.4 liolib.c */ +static int nixio_file_read(lua_State *L) { + FILE *f = nixio__checkfile(L); + size_t n = (size_t)luaL_checkinteger(L, 2); + luaL_argcheck(L, 2, n >= 0, "invalid length"); + + if (n == 0) { + if (feof(f)) { + return 0; + } else { + lua_pushliteral(L, ""); + return 1; + } + } + + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_objlen(L, -1) > 0); +} + +static int nixio_file_seek(lua_State *L) { + FILE *f = nixio__checkfile(L); + off_t len = (off_t)luaL_checknumber(L, 2); + int whence; + const char *whstr = luaL_optlstring(L, 3, "set", NULL); + if (!strcmp(whstr, "set")) { + whence = SEEK_SET; + } else if (!strcmp(whstr, "cur")) { + whence = SEEK_CUR; + } else if (!strcmp(whstr, "end")) { + whence = SEEK_END; + } else { + return luaL_argerror(L, 3, "supported values: set, cur, end"); + } + return nixio__pstatus(L, !fseeko(f, len, whence)); +} + +static int nixio_file_tell(lua_State *L) { + FILE *f = nixio__checkfile(L); + off_t pos = ftello(f); + if (pos < 0) { + return nixio__perror(L); + } else { + lua_pushnumber(L, (lua_Number)pos); + return 1; + } +} + +static int nixio_file_flush(lua_State *L) { + FILE *f = nixio__checkfile(L); + return nixio__pstatus(L, !fflush(f)); +} + +static int nixio_file_close(lua_State *L) { + FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META); + luaL_argcheck(L, *fpp, 1, "invalid file object"); + int res = fclose(*fpp); + *fpp = NULL; + return nixio__pstatus(L, !res); +} + +static int nixio_file__gc(lua_State *L) { + FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META); + if (*fpp) { + fclose(*fpp); + *fpp = NULL; + } + return 0; +} + +/** + * string representation + */ +static int nixio_file__tostring(lua_State *L) { + lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1)); + return 1; +} + +/* method table */ +static const luaL_reg M[] = { + {"write", nixio_file_write}, + {"read", nixio_file_read}, + {"tell", nixio_file_tell}, + {"seek", nixio_file_seek}, + {"flush", nixio_file_flush}, + {"close", nixio_file_close}, + {"__gc", nixio_file__gc}, + {"__tostring", nixio_file__tostring}, + {NULL, NULL} +}; + +/* module table */ +static const luaL_reg R[] = { + {"open", nixio_file}, + {"pipe", nixio_pipe}, + {NULL, NULL} +}; + +void nixio_open_file(lua_State *L) { + luaL_register(L, NULL, R); + + luaL_newmetatable(L, NIXIO_FILE_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); +} diff --git a/libs/nixio/src/io.c b/libs/nixio/src/io.c index 30327b1c0..58054b2eb 100644 --- a/libs/nixio/src/io.c +++ b/libs/nixio/src/io.c @@ -16,9 +16,7 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include diff --git a/libs/nixio/src/nixio.c b/libs/nixio/src/nixio.c index f152e05ea..327f65098 100644 --- a/libs/nixio/src/nixio.c +++ b/libs/nixio/src/nixio.c @@ -16,13 +16,10 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include -#include "nixio.h" #define VERSION 0.1 @@ -52,6 +49,12 @@ nixio_sock* nixio__checksock(lua_State *L) { return sock; } +FILE* nixio__checkfile(lua_State *L) { + FILE **fpp = (FILE**)luaL_checkudata(L, 1, NIXIO_FILE_META); + luaL_argcheck(L, *fpp, 1, "invalid file object"); + return *fpp; +} + /* read fd from nixio_sock object */ int nixio__checksockfd(lua_State *L) { return nixio__checksock(L)->fd; @@ -67,15 +70,16 @@ int nixio__checkfd(lua_State *L, int ud) { int nixio__tofd(lua_State *L, int ud) { void *udata = lua_touserdata(L, ud); int fd = -1; - if (udata && lua_getmetatable(L, ud)) { + if (lua_getmetatable(L, ud)) { luaL_getmetatable(L, NIXIO_META); + luaL_getmetatable(L, NIXIO_FILE_META); luaL_getmetatable(L, LUA_FILEHANDLE); - if (lua_rawequal(L, -2, -3)) { + if (lua_rawequal(L, -3, -4)) { fd = ((nixio_sock*)udata)->fd; - } else if (lua_rawequal(L, -1, -3)) { - fd = fileno(*((FILE **)udata)); + } else if (lua_rawequal(L, -2, -4) || lua_rawequal(L, -1, -4)) { + fd = (*((FILE **)udata)) ? fileno(*((FILE **)udata)) : -1; } - lua_pop(L, 3); + lua_pop(L, 4); } return fd; } @@ -90,24 +94,26 @@ LUALIB_API int luaopen_nixio(lua_State *L) { /* create metatable */ luaL_newmetatable(L, NIXIO_META); - /* method table */ - lua_newtable(L); + /* metatable.__index = metatable */ lua_pushvalue(L, -1); - - /* metatable.__index = M */ - lua_setfield(L, -3, "__index"); - lua_remove(L, -2); + lua_setfield(L, -2, "__index"); /* register module */ luaL_register(L, "nixio", R); + /* register metatable as socket_meta */ + lua_pushvalue(L, -2); + lua_setfield(L, -2, "socket_meta"); + /* register methods */ + nixio_open_file(L); nixio_open_socket(L); nixio_open_sockopt(L); nixio_open_bind(L); nixio_open_address(L); nixio_open_poll(L); nixio_open_io(L); + nixio_open_splice(L); /* module version */ lua_pushnumber(L, VERSION); diff --git a/libs/nixio/src/nixio.h b/libs/nixio/src/nixio.h index 4b037b25e..e4bb6d6de 100644 --- a/libs/nixio/src/nixio.h +++ b/libs/nixio/src/nixio.h @@ -2,7 +2,16 @@ #define NIXIO_H_ #define NIXIO_META "nixio.socket" +#define NIXIO_FILE_META "nixio.file" #define NIXIO_BUFFERSIZE 8096 +#define _FILE_OFFSET_BITS 64 + +/* uClibc: broken as always */ +#define _LARGEFILE_SOURCE + +#include +#include +#include struct nixio_socket { int fd; @@ -19,14 +28,17 @@ nixio_sock* nixio__checksock(lua_State *L); int nixio__checksockfd(lua_State *L); int nixio__checkfd(lua_State *L, int ud); int nixio__tofd(lua_State *L, int ud); +FILE* nixio__checkfile(lua_State *L); /* Module functions */ +void nixio_open_file(lua_State *L); void nixio_open_socket(lua_State *L); void nixio_open_sockopt(lua_State *L); void nixio_open_bind(lua_State *L); void nixio_open_address(lua_State *L); void nixio_open_poll(lua_State *L); void nixio_open_io(lua_State *L); +void nixio_open_splice(lua_State *L); /* Method functions */ diff --git a/libs/nixio/src/poll.c b/libs/nixio/src/poll.c index 7a397b96e..8fd585f22 100644 --- a/libs/nixio/src/poll.c +++ b/libs/nixio/src/poll.c @@ -16,9 +16,7 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include diff --git a/libs/nixio/src/socket.c b/libs/nixio/src/socket.c index 9d4648671..f8fa3e649 100644 --- a/libs/nixio/src/socket.c +++ b/libs/nixio/src/socket.c @@ -16,9 +16,7 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include diff --git a/libs/nixio/src/sockopt.c b/libs/nixio/src/sockopt.c index f1a326c75..c92254e88 100644 --- a/libs/nixio/src/sockopt.c +++ b/libs/nixio/src/sockopt.c @@ -16,9 +16,7 @@ * limitations under the License. */ -#include -#include -#include +#include "nixio.h" #include #include #include @@ -181,7 +179,7 @@ void nixio_open_sockopt(lua_State *L) { luaL_register(L, NULL, M); lua_pop(L, 1); - luaL_getmetatable(L, LUA_FILEHANDLE); + luaL_getmetatable(L, NIXIO_FILE_META); lua_pushcfunction(L, nixio_sock_setblocking); lua_setfield(L, -2, "setblocking"); lua_pop(L, 1); diff --git a/libs/nixio/src/splice.c b/libs/nixio/src/splice.c new file mode 100644 index 000000000..37849751a --- /dev/null +++ b/libs/nixio/src/splice.c @@ -0,0 +1,91 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include "nixio.h" +#include + +/* guess what sucks... */ +#ifdef __UCLIBC__ +#include +#include +ssize_t splice(int __fdin, __off64_t *__offin, int __fdout, + __off64_t *__offout, size_t __len, unsigned int __flags) { + return syscall(__NR_splice, __fdin, __offin, __fdout, __offout, __len, __flags); +} +#endif + + +/** + * Checks whether a flag is set in the table and translates it into a bitmap + */ +static void nixio_splice_flags__w(lua_State *L, int *m, int f, const char *t) { + lua_pushstring(L, t); + lua_rawget(L, -2); + if (lua_toboolean(L, -1)) { + *m |= f; + } + lua_pop(L, 1); +} + +/** + * Translate integer to poll flags and vice versa + */ +static int nixio_splice_flags(lua_State *L) { + int flags = 0; + + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); + nixio_splice_flags__w(L, &flags, SPLICE_F_MOVE, "move"); + nixio_splice_flags__w(L, &flags, SPLICE_F_NONBLOCK, "nonblock"); + nixio_splice_flags__w(L, &flags, SPLICE_F_MORE, "more"); + lua_pushinteger(L, flags); + + return 1; +} + +static int nixio_splice(lua_State *L) { + int fd_in = nixio__checkfd(L, 1); + int fd_out = nixio__checkfd(L, 2); + size_t len = luaL_checkinteger(L, 3); + int flags = luaL_optinteger(L, 4, 0); + + + long spliced = splice(fd_in, NULL, fd_out, NULL, len, flags); + + if (spliced < 0) { + return nixio__perror(L); + } + + lua_pushnumber(L, spliced); + return 1; +} + + + +/* module table */ +static const luaL_reg R[] = { + {"splice", nixio_splice}, + {"splice_flags", nixio_splice_flags}, + {NULL, NULL} +}; + +void nixio_open_splice(lua_State *L) { + luaL_register(L, NULL, R); +} -- 2.25.1