diff options
author | Steven Barth <steven@midlink.org> | 2009-04-21 16:26:45 +0000 |
---|---|---|
committer | Steven Barth <steven@midlink.org> | 2009-04-21 16:26:45 +0000 |
commit | a2b916ab736802050b19562b7c163e3f3bb1566f (patch) | |
tree | d35b68f7bcac43f66f4cdb915ef327b76856594b /libs/nixio/src | |
parent | 085a0a9ec040fc3ea5ee537d2cee724aa775747b (diff) |
Merge nixio 0.2
Diffstat (limited to 'libs/nixio/src')
-rw-r--r-- | libs/nixio/src/address.c | 198 | ||||
-rw-r--r-- | libs/nixio/src/axtls-compat.c | 297 | ||||
-rw-r--r-- | libs/nixio/src/axtls-compat.h | 149 | ||||
-rw-r--r-- | libs/nixio/src/binary.c | 313 | ||||
-rw-r--r-- | libs/nixio/src/bind.c | 57 | ||||
-rw-r--r-- | libs/nixio/src/bit.c | 125 | ||||
-rw-r--r-- | libs/nixio/src/file.c | 104 | ||||
-rw-r--r-- | libs/nixio/src/fs.c | 566 | ||||
-rw-r--r-- | libs/nixio/src/io.c | 95 | ||||
-rw-r--r-- | libs/nixio/src/mingw-compat.c | 220 | ||||
-rw-r--r-- | libs/nixio/src/mingw-compat.h | 112 | ||||
-rw-r--r-- | libs/nixio/src/nixio-tls.h | 30 | ||||
-rw-r--r-- | libs/nixio/src/nixio.c | 64 | ||||
-rw-r--r-- | libs/nixio/src/nixio.h | 66 | ||||
-rw-r--r-- | libs/nixio/src/poll.c | 32 | ||||
-rw-r--r-- | libs/nixio/src/process.c | 374 | ||||
-rw-r--r-- | libs/nixio/src/socket.c | 17 | ||||
-rw-r--r-- | libs/nixio/src/sockopt.c | 192 | ||||
-rw-r--r-- | libs/nixio/src/splice.c | 11 | ||||
-rw-r--r-- | libs/nixio/src/syslog.c | 15 | ||||
-rw-r--r-- | libs/nixio/src/tls-crypto.c | 188 | ||||
-rw-r--r-- | libs/nixio/src/tls-socket.c | 22 | ||||
-rw-r--r-- | libs/nixio/src/user.c | 257 |
23 files changed, 3217 insertions, 287 deletions
diff --git a/libs/nixio/src/address.c b/libs/nixio/src/address.c index 8b9ae2807..835a8a2f9 100644 --- a/libs/nixio/src/address.c +++ b/libs/nixio/src/address.c @@ -18,16 +18,79 @@ #include "nixio.h" #include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netinet/in.h> +#include <errno.h> #include <string.h> -#include <netdb.h> #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif +/** + * address pushing helper + */ +int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr) { + void *baddr; + + addr->family = saddr->sa_family; + if (saddr->sa_family == AF_INET) { + struct sockaddr_in *inetaddr = (struct sockaddr_in*)saddr; + addr->port = ntohs(inetaddr->sin_port); + baddr = &inetaddr->sin_addr; + } else if (saddr->sa_family == AF_INET6) { + struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)saddr; + addr->port = ntohs(inet6addr->sin6_port); + baddr = &inet6addr->sin6_addr; + } else { + errno = EAFNOSUPPORT; + return -1; + } + + if (!inet_ntop(saddr->sa_family, baddr, addr->host, sizeof(addr->host))) { + return -1; + } + + return 0; +} + +/** + * address pulling helper + */ +int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr) { + if (addr->family == AF_UNSPEC) { + if (strchr(addr->host, ':')) { + addr->family = AF_INET6; + } else { + addr->family = AF_INET; + } + } + if (addr->family == AF_INET) { + struct sockaddr_in *inetaddr = (struct sockaddr_in *)saddr; + memset(inetaddr, 0, sizeof(struct sockaddr_in)); + + if (inet_pton(AF_INET, addr->host, &inetaddr->sin_addr) < 1) { + return -1; + } + + inetaddr->sin_family = AF_INET; + inetaddr->sin_port = htons((uint16_t)addr->port); + return 0; + } else if (addr->family == AF_INET6) { + struct sockaddr_in6 *inet6addr = (struct sockaddr_in6 *)saddr; + memset(inet6addr, 0, sizeof(struct sockaddr_in6)); + + if (inet_pton(AF_INET6, addr->host, &inet6addr->sin6_addr) < 1) { + return -1; + } + + inet6addr->sin6_family = AF_INET6; + inet6addr->sin6_port = htons((uint16_t)addr->port); + return 0; + } else { + errno = EAFNOSUPPORT; + return -1; + } +} + /** * getaddrinfo(host, family, port) @@ -70,9 +133,11 @@ static int nixio_getaddrinfo(lua_State *L) { for (rp = result; rp != NULL; rp = rp->ai_next) { /* avoid duplicate results */ +#ifndef __WINNT__ if (!port && rp->ai_socktype != SOCK_STREAM) { continue; } +#endif if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) { lua_createtable(L, 0, port ? 4 : 2); @@ -101,31 +166,18 @@ static int nixio_getaddrinfo(lua_State *L) { lua_setfield(L, -2, "socktype"); } - char ip[INET6_ADDRSTRLEN]; - void *binaddr = NULL; - uint16_t binport = 0; - - if (rp->ai_family == AF_INET) { - struct sockaddr_in *v4addr = (struct sockaddr_in*)rp->ai_addr; - binport = v4addr->sin_port; - binaddr = (void *)&v4addr->sin_addr; - } else if (rp->ai_family == AF_INET6) { - struct sockaddr_in6 *v6addr = (struct sockaddr_in6*)rp->ai_addr; - binport = v6addr->sin6_port; - binaddr = (void *)&v6addr->sin6_addr; - } - - if (!inet_ntop(rp->ai_family, binaddr, ip, sizeof(ip))) { + nixio_addr addr; + if (nixio__addr_parse(&addr, rp->ai_addr)) { freeaddrinfo(result); - return nixio__perror(L); + return nixio__perror_s(L); } if (port) { - lua_pushinteger(L, ntohs(binport)); + lua_pushinteger(L, addr.port); lua_setfield(L, -2, "port"); } - lua_pushstring(L, ip); + lua_pushstring(L, addr.host); lua_setfield(L, -2, "address"); lua_rawseti(L, -2, i++); } @@ -140,37 +192,29 @@ static int nixio_getaddrinfo(lua_State *L) { * getnameinfo(address, family) */ static int nixio_getnameinfo(lua_State *L) { - const char *ip = luaL_checklstring(L, 1, NULL); - const char *family = luaL_optlstring(L, 2, "inet", NULL); + const char *ip = luaL_checkstring(L, 1); + const char *family = luaL_optstring(L, 2, NULL); char host[NI_MAXHOST]; - struct sockaddr *addr = NULL; - socklen_t alen = 0; - int res; + struct sockaddr_storage saddr; + nixio_addr addr; + memset(&addr, 0, sizeof(addr)); + strncpy(addr.host, ip, sizeof(addr.host) - 1); - if (!strcmp(family, "inet")) { - struct sockaddr_in inetaddr; - memset(&inetaddr, 0, sizeof(inetaddr)); - inetaddr.sin_family = AF_INET; - if (inet_pton(AF_INET, ip, &inetaddr.sin_addr) < 1) { - return luaL_argerror(L, 1, "invalid address"); - } - alen = sizeof(inetaddr); - addr = (struct sockaddr *)&inetaddr; + if (!family) { + addr.family = AF_UNSPEC; + } else if (!strcmp(family, "inet")) { + addr.family = AF_INET; } else if (!strcmp(family, "inet6")) { - struct sockaddr_in6 inet6addr; - memset(&inet6addr, 0, sizeof(inet6addr)); - inet6addr.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, ip, &inet6addr.sin6_addr) < 1) { - return luaL_argerror(L, 1, "invalid address"); - } - alen = sizeof(inet6addr); - addr = (struct sockaddr *)&inet6addr; + addr.family = AF_INET6; } else { return luaL_argerror(L, 2, "supported values: inet, inet6"); } - res = getnameinfo(addr, alen, host, sizeof(host), NULL, 0, NI_NAMEREQD); + nixio__addr_write(&addr, (struct sockaddr *)&saddr); + + int res = getnameinfo((struct sockaddr *)&saddr, sizeof(saddr), + host, sizeof(host), NULL, 0, NI_NAMEREQD); if (res) { lua_pushnil(L); lua_pushinteger(L, res); @@ -183,59 +227,41 @@ static int nixio_getnameinfo(lua_State *L) { } /** - * getsockname() / getpeername() helper + * getsockname() */ -static int nixio_sock__getname(lua_State *L, int sock) { +static int nixio_sock_getsockname(lua_State *L) { int sockfd = nixio__checksockfd(L); - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - char ipaddr[INET6_ADDRSTRLEN]; - void *binaddr; - uint16_t port; - - if (sock) { - if (getsockname(sockfd, (struct sockaddr*)&addr, &addrlen)) { - return nixio__perror(L); - } - } else { - if (getpeername(sockfd, (struct sockaddr*)&addr, &addrlen)) { - return nixio__perror(L); - } - } - - if (addr.ss_family == AF_INET) { - struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr; - port = inetaddr->sin_port; - binaddr = &inetaddr->sin_addr; - } else if (addr.ss_family == AF_INET6) { - struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr; - port = inet6addr->sin6_port; - binaddr = &inet6addr->sin6_addr; - } else { - return luaL_error(L, "unknown address family"); - } + struct sockaddr_storage saddr; + socklen_t addrlen = sizeof(saddr); + nixio_addr addr; - if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) { - return nixio__perror(L); + if (getsockname(sockfd, (struct sockaddr*)&saddr, &addrlen) || + nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) { + return nixio__perror_s(L); } - lua_pushstring(L, ipaddr); - lua_pushinteger(L, ntohs(port)); + lua_pushstring(L, addr.host); + lua_pushnumber(L, addr.port); return 2; } /** - * getsockname() - */ -static int nixio_sock_getsockname(lua_State *L) { - return nixio_sock__getname(L, 1); -} - -/** * getpeername() */ static int nixio_sock_getpeername(lua_State *L) { - return nixio_sock__getname(L, 0); + int sockfd = nixio__checksockfd(L); + struct sockaddr_storage saddr; + socklen_t addrlen = sizeof(saddr); + nixio_addr addr; + + if (getpeername(sockfd, (struct sockaddr*)&saddr, &addrlen) || + nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) { + return nixio__perror_s(L); + } + + lua_pushstring(L, addr.host); + lua_pushnumber(L, addr.port); + return 2; } diff --git a/libs/nixio/src/axtls-compat.c b/libs/nixio/src/axtls-compat.c new file mode 100644 index 000000000..2c5b746c2 --- /dev/null +++ b/libs/nixio/src/axtls-compat.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +static char *key_password = NULL; + +void *SSLv23_server_method(void) { return NULL; } +void *SSLv3_server_method(void) { return NULL; } +void *TLSv1_server_method(void) { return NULL; } +void *SSLv23_client_method(void) { return NULL; } +void *SSLv3_client_method(void) { return NULL; } +void *TLSv1_client_method(void) { return NULL; } +void *SSLv23_method(void) { return NULL; } +void *TLSv1_method(void) { return NULL; } + +SSL_CTX * SSL_CTX_new(void *meth) +{ + SSL_CTX *ssl_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER, 5); + return ssl_ctx; +} + +void SSL_CTX_free(SSL_CTX * ssl_ctx) +{ + ssl_ctx_free(ssl_ctx); +} + +SSL * SSL_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + + return ssl; +} + +int SSL_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +int SSL_accept(SSL *ssl) +{ + ssl->next_state = HS_CLIENT_HELLO; + while (ssl_read(ssl, NULL) == SSL_OK) + { + if (ssl->next_state == HS_CLIENT_HELLO) + return 1; /* we're done */ + } + + return -1; +} + +int SSL_connect(SSL *ssl) +{ + SET_SSL_FLAG(SSL_IS_CLIENT); + int stat = do_client_connect(ssl); + ssl_display_error(stat); + return (stat == SSL_OK) ? 1 : -1; +} + +void SSL_free(SSL *ssl) +{ + ssl_free(ssl); +} + +int SSL_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf; + int ret; + + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK) + { + memcpy(buf, read_buf, ret > num ? num : ret); + } + + return ret; +} + +int SSL_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx, + SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +int SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +void SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { + if (mode & SSL_VERIFY_PEER) { + ctx->options &= ~SSL_SERVER_VERIFY_LATER; + ctx->options |= SSL_CLIENT_AUTHENTICATION; + } else { + ctx->options |= SSL_SERVER_VERIFY_LATER; + ctx->options &= ~SSL_CLIENT_AUTHENTICATION; + } +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { } + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +void *SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +int SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +long SSL_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +int SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +int SSL_clear(SSL *ssl) +{ + return 1; +} + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str) +{ + return 1; +} + +int SSL_get_error(const SSL *ssl, int ret) +{ + ssl_display_error(ret); + return ret; /* TODO: return proper return code */ +} + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} +int SSL_library_init(void ) { return 1; } +void SSL_load_error_strings(void ) {} +void ERR_print_errors_fp(FILE *fp) {} + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { + return CONFIG_SSL_EXPIRY_TIME*3600; } +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { + return SSL_CTX_get_timeout(ssl_ctx); } +void BIO_printf(FILE *f, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); +} + +void* BIO_s_null(void) { return NULL; } +FILE *BIO_new(bio_func_type_t func) +{ + if (func == BIO_s_null) + return fopen("/dev/null", "r"); + else + return NULL; +} + +FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; } +int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } diff --git a/libs/nixio/src/axtls-compat.h b/libs/nixio/src/axtls-compat.h new file mode 100644 index 000000000..77533ef4f --- /dev/null +++ b/libs/nixio/src/axtls-compat.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "nixio.h" +#include "config.h" + +#define WITH_AXTLS 1 +#define WITHOUT_OPENSSL 1 +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_SSLv2 0x01000000L +#define SSL_FILETYPE_PEM 1 +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define SSL_VERIFY_CLIENT_ONCE 0x03 +#define MD5_DIGEST_LENGTH 16 +#define SHA_DIGEST_LENGTH 20 + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +typedef SHA1_CTX SHA_CTX; + +void *SSLv23_server_method(void); +void *SSLv3_server_method(void); +void *TLSv1_server_method(void); +void *SSLv23_client_method(void); +void *SSLv3_client_method(void); +void *TLSv1_client_method(void); +void *SSLv23_method(void); +void *TLSv1_method(void); + + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +SSL_CTX * SSL_CTX_new(void *meth); +void SSL_CTX_free(SSL_CTX * ssl_ctx); +SSL * SSL_new(SSL_CTX *ssl_ctx); +int SSL_set_fd(SSL *s, int fd); +int SSL_accept(SSL *ssl); +int SSL_connect(SSL *ssl); +void SSL_free(SSL *ssl); +int SSL_read(SSL *ssl, void *buf, int num); +int SSL_write(SSL *ssl, const void *buf, int num); +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d); +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file); +int SSL_shutdown(SSL *ssl); + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl); +int SSL_set_session(SSL *ssl, SSL_SESSION *session); +void SSL_SESSION_free(SSL_SESSION *session); +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)); + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); + +void *SSL_load_client_CA_file(const char *file); + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb); + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); + +int SSL_peek(SSL *ssl, void *buf, int num); + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio); + +long SSL_get_verify_result(const SSL *ssl); + +int SSL_state(SSL *ssl); + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl); + +int SSL_clear(SSL *ssl); + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str); + +int SSL_get_error(const SSL *ssl, int ret); + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option); +int SSL_library_init(void ); +void SSL_load_error_strings(void ); +void ERR_print_errors_fp(FILE *fp); + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx); +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t); +void BIO_printf(FILE *f, const char *format, ...); + +void* BIO_s_null(void); +FILE *BIO_new(bio_func_type_t func); + +FILE *BIO_new_fp(FILE *stream, int close_flag); +int BIO_free(FILE *a); diff --git a/libs/nixio/src/binary.c b/libs/nixio/src/binary.c new file mode 100644 index 000000000..72425b113 --- /dev/null +++ b/libs/nixio/src/binary.c @@ -0,0 +1,313 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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 <stdlib.h> + +static char nixio__bin2hex[] = { +'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static unsigned char nixio__b64encode_tbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char nixio__b64decode_tbl[] = { + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 +}; + +static const uint32_t nixio__crc32_tbl[] = { + 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, + 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, + 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, + 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, + 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, + 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, + 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, + 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, + 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, + 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, + 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, + 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, + 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, + 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, + 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, + 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, + 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, + 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, + 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, + 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, + 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, + 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, + 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, + 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, + 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, + 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, + 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, + 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, + 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, + 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, + 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, + 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, + 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, + 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, + 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, + 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, + 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, + 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, + 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, + 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, + 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, + 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, + 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, + 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, + 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, + 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, + 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, + 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, + 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, + 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, + 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, + 0x2d02ef8dU +}; + +static int nixio_bin_crc32(lua_State *L) { + size_t len; + const char *buffer = luaL_checklstring(L, 1, &len); + uint32_t value = luaL_optnumber(L, 2, 0); + + value = ~value; + for (size_t i=0; i<len; i++) { + value = nixio__crc32_tbl[(value ^ buffer[i]) & 0xffU ] ^ (value >> 8); + } + + lua_pushinteger(L, (int)(value ^ 0xffffffffU)); + return 1; +} + +static int nixio_bin_hexlify(lua_State *L) { + size_t len, lenout; + luaL_checktype(L, 1, LUA_TSTRING); + const unsigned char *data = (unsigned char*)lua_tolstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } + + lenout = len * 2; + luaL_argcheck(L, lenout > len, 1, "size overflow"); + + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + for (size_t i=0; i < len; i++) { + out[2*i] = nixio__bin2hex[(data[i] & 0xf0) >> 4]; + out[2*i+1] = nixio__bin2hex[(data[i] & 0x0f)]; + } + + lua_pushlstring(L, out, lenout); + free(out); + + return 1; +} + + +static int nixio_bin_unhexlify(lua_State *L) { + size_t len, lenout; + const char *data = luaL_checklstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (len % 2) { + errno = EINVAL; + return nixio__perror(L); + } + + lenout = len / 2; + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + for (size_t i=0; i < lenout; i++) { + char c = data[2*i]; + if (c >= '0' && c <= '9') { + out[i] = (c - '0') << 4; + } else if (c >= 'a' && c <= 'f') { + out[i] = (c - 'a' + 10) << 4; + } else if (data[2*i] >= 'A' && c <= 'F') { + out[i] = (c - 'A' + 10) << 4; + } else { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + + c = data[2*i+1]; + if (c >= '0' && c <= '9') { + out[i] += c - '0'; + } else if (c >= 'a' && c <= 'f') { + out[i] += c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + out[i] += c - 'A' + 10; + } else { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + } + + lua_pushlstring(L, out, lenout); + free(out); + + return 1; +} + +static int nixio_bin_b64encode(lua_State *L) { + size_t len, lenout, pad, i; + const char *data = luaL_checklstring(L, 1, &len); + + lenout = len / 3; + lenout *= 4; + + pad = len % 3; + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (pad) { + lenout += 4; + } + + luaL_argcheck(L, lenout > len, 1, "size overflow"); + + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + char *o = out; + for (i = 0; i < len; i += 3) { + uint32_t cv = (data[i] << 16) | (data[i+1] << 8) | data[i+2]; + *(o+3) = nixio__b64encode_tbl[ cv & 0x3f]; + *(o+2) = nixio__b64encode_tbl[(cv >> 6) & 0x3f]; + *(o+1) = nixio__b64encode_tbl[(cv >> 12) & 0x3f]; + *o = nixio__b64encode_tbl[(cv >> 18) & 0x3f]; + o += 4; + } + + if (pad) { + uint32_t cv = data[len-pad] << 16; + *(o-1) = '='; + *(o-2) = '='; + if (pad == 2) { + cv |= data[len-pad+1] << 8; + *(o-2) = nixio__b64encode_tbl[(cv >> 6) & 0x3f]; + } + *(o-3) = nixio__b64encode_tbl[(cv >> 12) & 0x3f]; + *(o-4) = nixio__b64encode_tbl[(cv >> 18) & 0x3f]; + } + + lua_pushlstring(L, out, lenout); + free(out); + return 1; +} + +static int nixio_bin_b64decode(lua_State *L) { + size_t len, lenout, i; + const char *dt = luaL_checklstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (len % 4) { + errno = EINVAL; + return nixio__perror(L); + } + + lenout = len / 4 * 3; + + unsigned char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + unsigned char *o = out; + for (i = 0; i < len; i += 4) { + uint32_t cv = 0; + for (int j = 0; j < 4; j++) { + unsigned char c = dt[i + j] - 43; + if (c > 79 || (c = nixio__b64decode_tbl[c]) == 0xff) { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + + cv |= c; + if (j != 3) { + cv <<= 6; + } + } + + *(o+2) = (unsigned char)(cv & 0xff); + *(o+1) = (unsigned char)((cv >> 8) & 0xff); + *o = (unsigned char)((cv >> 16) & 0xff); + o += 3; + } + + if (dt[len-1] == '=') { + lenout--; + } + + if (dt[len-2] == '=') { + lenout--; + } + + lua_pushlstring(L, (char*)out, lenout); + free(out); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"hexlify", nixio_bin_hexlify}, + {"unhexlify", nixio_bin_unhexlify}, + {"crc32", nixio_bin_crc32}, + {"b64encode", nixio_bin_b64encode}, + {"b64decode", nixio_bin_b64decode}, + {NULL, NULL} +}; + + +void nixio_open_bin(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_setfield(L, -2, "bin"); +} diff --git a/libs/nixio/src/bind.c b/libs/nixio/src/bind.c index 785a28d5a..7b2b719e3 100644 --- a/libs/nixio/src/bind.c +++ b/libs/nixio/src/bind.c @@ -18,15 +18,11 @@ #include "nixio.h" #include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <sys/un.h> #include <string.h> #include <unistd.h> -#include <netdb.h> #include <errno.h> + /** * connect()/bind() shortcut */ @@ -87,6 +83,9 @@ static int nixio__bind_connect(lua_State *L, int do_bind) { } if (do_bind) { + int one = 1; + setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, + (char*)&one, sizeof(one)); status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen); } else { do { @@ -103,7 +102,11 @@ static int nixio__bind_connect(lua_State *L, int do_bind) { } do { +#ifndef __WINNT__ clstat = close(sock->fd); +#else + clstat = closesocket(sock->fd); +#endif } while (clstat == -1 && errno == EINTR); } @@ -111,7 +114,7 @@ static int nixio__bind_connect(lua_State *L, int do_bind) { /* on failure */ if (status) { - return nixio__perror(L); + return nixio__perror_s(L); } luaL_getmetatable(L, NIXIO_META); @@ -183,6 +186,7 @@ static int nixio_sock__bind_connect(lua_State *L, int do_bind) { } freeaddrinfo(result); +#ifndef __WINNT__ } else if (sock->domain == AF_UNIX) { size_t pathlen; const char *path = luaL_checklstring(L, 2, &pathlen); @@ -200,10 +204,11 @@ static int nixio_sock__bind_connect(lua_State *L, int do_bind) { sizeof(addr)); } while (status == -1 && errno == EINTR); } +#endif } else { return luaL_error(L, "not supported"); } - return nixio__pstatus(L, !status); + return nixio__pstatus_s(L, !status); } /** @@ -225,8 +230,8 @@ static int nixio_sock_connect(lua_State *L) { */ static int nixio_sock_listen(lua_State *L) { int sockfd = nixio__checksockfd(L); - lua_Integer backlog = luaL_checkinteger(L, 2); - return nixio__pstatus(L, !listen(sockfd, backlog)); + int backlog = luaL_checkinteger(L, 2); + return nixio__pstatus_s(L, !listen(sockfd, backlog)); } /** @@ -234,18 +239,16 @@ static int nixio_sock_listen(lua_State *L) { */ static int nixio_sock_accept(lua_State *L) { nixio_sock *sock = nixio__checksock(L); - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - char ipaddr[INET6_ADDRSTRLEN]; - void *binaddr; - uint16_t port; + struct sockaddr_storage saddr; + nixio_addr addr; + socklen_t saddrlen = sizeof(saddr); int newfd; do { - newfd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen); + newfd = accept(sock->fd, (struct sockaddr *)&saddr, &saddrlen); } while (newfd == -1 && errno == EINTR); if (newfd < 0) { - return nixio__perror(L); + return nixio__perror_s(L); } /* create userdata */ @@ -256,25 +259,13 @@ static int nixio_sock_accept(lua_State *L) { memcpy(clsock, sock, sizeof(clsock)); clsock->fd = newfd; - if (addr.ss_family == AF_INET) { - struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr; - port = inetaddr->sin_port; - binaddr = &inetaddr->sin_addr; - } else if (addr.ss_family == AF_INET6) { - struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr; - port = inet6addr->sin6_port; - binaddr = &inet6addr->sin6_addr; + if (!nixio__addr_parse(&addr, (struct sockaddr *)&saddr)) { + lua_pushstring(L, addr.host); + lua_pushnumber(L, addr.port); + return 3; } else { - return luaL_error(L, "unknown address family"); + return 1; } - - if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) { - return nixio__perror(L); - } - - lua_pushstring(L, ipaddr); - lua_pushinteger(L, ntohs(port)); - return 3; } /* module table */ diff --git a/libs/nixio/src/bit.c b/libs/nixio/src/bit.c new file mode 100644 index 000000000..14fdecab1 --- /dev/null +++ b/libs/nixio/src/bit.c @@ -0,0 +1,125 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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 <stdint.h> +#include <stdlib.h> + +/* 52 bit maximum precision */ +#define NIXIO_BIT_BMAX 52 +#define NIXIO_BIT_NMAX 0xfffffffffffff + +#define NIXIO_BIT_XOP(BIT_XOP) \ + uint64_t oper = luaL_checknumber(L, 1); \ + const int args = lua_gettop(L); \ + \ + for (int i = 2; i <= args; i++) { \ + uint64_t oper2 = luaL_checknumber(L, i); \ + oper BIT_XOP oper2; \ + } \ + \ + lua_pushnumber(L, oper); \ + return 1; \ + + +static int nixio_bit_or(lua_State *L) { + NIXIO_BIT_XOP(|=); +} + +static int nixio_bit_and(lua_State *L) { + NIXIO_BIT_XOP(&=); +} + +static int nixio_bit_xor(lua_State *L) { + NIXIO_BIT_XOP(^=); +} + +static int nixio_bit_unset(lua_State *L) { + NIXIO_BIT_XOP(&= ~); +} + +static int nixio_bit_not(lua_State *L) { + lua_pushnumber(L, (~((uint64_t)luaL_checknumber(L, 1))) & NIXIO_BIT_NMAX); + return 1; +} + +static int nixio_bit_shl(lua_State *L) { + uint64_t oper = luaL_checknumber(L, 1); + oper <<= luaL_checkinteger(L, 2); + if (oper > NIXIO_BIT_NMAX) { + return luaL_error(L, "arithmetic overflow"); + } else { + lua_pushnumber(L, oper); + return 1; + } +} + +static int nixio_bit_ashr(lua_State *L) { + int64_t oper = luaL_checknumber(L, 1); + lua_pushnumber(L, oper >> luaL_checkinteger(L, 2)); + return 1; +} + +static int nixio_bit_shr(lua_State *L) { + uint64_t oper = luaL_checknumber(L, 1); + lua_pushnumber(L, oper >> luaL_checkinteger(L, 2)); + return 1; +} + +static int nixio_bit_div(lua_State *L) { + NIXIO_BIT_XOP(/=); +} + +static int nixio_bit_check(lua_State *L) { + uint64_t oper = luaL_checknumber(L, 1); + uint64_t oper2 = luaL_checknumber(L, 2); + lua_pushboolean(L, (oper & oper2) == oper2); + return 1; +} + +static int nixio_bit_cast(lua_State *L) { + lua_pushnumber(L, ((uint64_t)luaL_checknumber(L, 1)) & NIXIO_BIT_NMAX); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"bor", nixio_bit_or}, + {"set", nixio_bit_or}, + {"band", nixio_bit_and}, + {"bxor", nixio_bit_xor}, + {"unset", nixio_bit_unset}, + {"bnot", nixio_bit_not}, + {"rshift", nixio_bit_shr}, + {"arshift", nixio_bit_ashr}, + {"lshift", nixio_bit_shl}, + {"div", nixio_bit_div}, + {"check", nixio_bit_check}, + {"cast", nixio_bit_cast}, + {NULL, NULL} +}; + +void nixio_open_bit(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_pushnumber(L, NIXIO_BIT_BMAX); + lua_setfield(L, -2, "bits"); + lua_pushnumber(L, NIXIO_BIT_NMAX); + lua_setfield(L, -2, "max"); + lua_setfield(L, -2, "bit"); +} diff --git a/libs/nixio/src/file.c b/libs/nixio/src/file.c index 2fe00c2a8..482752522 100644 --- a/libs/nixio/src/file.c +++ b/libs/nixio/src/file.c @@ -30,12 +30,37 @@ static int nixio_open(lua_State *L) { const char *filename = luaL_checklstring(L, 1, NULL); - int flags = luaL_optint(L, 2, O_RDONLY); - int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + int flags; + + if (lua_isnoneornil(L, 2)) { + flags = O_RDONLY; + } else if (lua_isnumber(L, 2)) { + flags = lua_tointeger(L, 2); + } else if (lua_isstring(L, 2)) { + const char *str = lua_tostring(L, 2); + if (!strcmp(str, "r")) { + flags = O_RDONLY; + } else if (!strcmp(str, "r+")) { + flags = O_RDWR; + } else if (!strcmp(str, "w")) { + flags = O_WRONLY | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "w+")) { + flags = O_RDWR | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "a")) { + flags = O_WRONLY | O_CREAT | O_APPEND; + } else if (!strcmp(str, "a+")) { + flags = O_RDWR | O_CREAT | O_APPEND; + } else { + return luaL_argerror(L, 2, "supported values: r, r+, w, w+, a, a+"); + } + } else { + return luaL_argerror(L, 2, "open flags or string expected"); + } + int fd; do { - fd = open(filename, flags, mode); + fd = open(filename, flags, nixio__check_mode(L, 3, 0666)); } while (fd == -1 && errno == EINTR); if (fd == -1) { return nixio__perror(L); @@ -66,9 +91,13 @@ static int nixio_open_flags(lua_State *L) { } else if (!strcmp(flag, "excl")) { mode |= O_EXCL; } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) { +#ifndef __WINNT__ mode |= O_NONBLOCK; +#endif } else if (!strcmp(flag, "sync")) { +#ifndef __WINNT__ mode |= O_SYNC; +#endif } else if (!strcmp(flag, "trunc")) { mode |= O_TRUNC; } else if (!strcmp(flag, "rdonly")) { @@ -141,6 +170,23 @@ static int nixio_file_write(lua_State *L) { ssize_t sent; const char *data = luaL_checklstring(L, 2, &len); + if (lua_gettop(L) > 2) { + int offset = luaL_optint(L, 3, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, 4, len); + if (wlen < len) { + len = wlen; + } + } + do { sent = write(fd, data, len); } while(sent == -1 && errno == EINTR); @@ -155,7 +201,7 @@ static int nixio_file_write(lua_State *L) { static int nixio_file_read(lua_State *L) { int fd = nixio__checkfd(L, 1); char buffer[NIXIO_BUFFERSIZE]; - int req = luaL_checkinteger(L, 2); + uint req = luaL_checkinteger(L, 2); int readc; /* We limit the readsize to NIXIO_BUFFERSIZE */ @@ -208,13 +254,33 @@ static int nixio_file_tell(lua_State *L) { } } +static int nixio_file_stat(lua_State *L) { + nixio_stat_t buf; + if (fstat(nixio__checkfd(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + static int nixio_file_sync(lua_State *L) { int fd = nixio__checkfd(L, 1); -#ifndef BSD - int meta = lua_toboolean(L, 2); - return nixio__pstatus(L, (meta) ? !fsync(fd) : !fdatasync(fd)); + int stat; +#if (!defined BSD && !defined __WINNT__) + int dataonly = lua_toboolean(L, 2); + do { + stat = (dataonly) ? fdatasync(fd) : fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); #else - return nixio__pstatus(L, !fsync(fd)); + do { + stat = fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); #endif } @@ -282,6 +348,7 @@ static const luaL_reg M[] = { {"read", nixio_file_read}, {"tell", nixio_file_tell}, {"seek", nixio_file_seek}, + {"stat", nixio_file_stat}, {"sync", nixio_file_sync}, {"lock", nixio_file_lock}, {"close", nixio_file_close}, @@ -306,5 +373,26 @@ void nixio_open_file(lua_State *L) { luaL_register(L, NULL, M); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); + + int *uin = lua_newuserdata(L, sizeof(int)); + int *uout = lua_newuserdata(L, sizeof(int)); + int *uerr = lua_newuserdata(L, sizeof(int)); + + if (!uin || !uout || !uerr) { + luaL_error(L, "out of memory"); + } + + *uin = STDIN_FILENO; + *uout = STDOUT_FILENO; + *uerr = STDERR_FILENO; + + for (int i = -4; i < -1; i++) { + lua_pushvalue(L, -4); + lua_setmetatable(L, i); + } + + lua_setfield(L, -5, "stderr"); + lua_setfield(L, -4, "stdout"); + lua_setfield(L, -3, "stdin"); lua_setfield(L, -2, "meta_file"); } diff --git a/libs/nixio/src/fs.c b/libs/nixio/src/fs.c new file mode 100644 index 000000000..10727d030 --- /dev/null +++ b/libs/nixio/src/fs.c @@ -0,0 +1,566 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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 <libgen.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> +#include <dirent.h> + +/* Reads argument from given index and transforms it into a mode bitfield */ +int nixio__check_mode(lua_State *L, int idx, int def) { + if (lua_isnoneornil(L, idx) && def > 0) { + return def; + } else if (lua_isstring(L, idx) && lua_objlen(L, idx) == 9) { + int mode = 0; + const char *modestr = lua_tostring(L, idx); + int i; + for (i=0; i<9; i++) { + if (i % 3 == 0) { /* read flags */ + if (modestr[i] == 'r') { + mode |= 1 << (8 - i); + } else if (modestr[i] != '-') { + break; + } + } else if (i % 3 == 1) { /* write flags */ + if (modestr[i] == 'w') { + mode |= 1 << (8 - i); + } else if (modestr[i] != '-') { + break; + } + } else if (i == 2) { + if (modestr[i] == 'x') { + mode |= 00100; + } else if (modestr[i] == 's') { + mode |= 04100; + } else if (modestr[i] == 'S') { + mode |= 04000; + } else if (modestr[i] != '-') { + break; + } + } else if (i == 5) { + if (modestr[i] == 'x') { + mode |= 00010; + } else if (modestr[i] == 's') { + mode |= 02010; + } else if (modestr[i] == 'S') { + mode |= 02000; + } else if (modestr[i] != '-') { + break; + } + } else if (i == 8) { + if (modestr[i] == 'x') { + mode |= 00001; + } else if (modestr[i] == 't') { + mode |= 01001; + } else if (modestr[i] == 'T') { + mode |= 01000; + } else if (modestr[i] != '-') { + break; + } + } + } + if (i == 9) { /* successfully parsed */ + return mode; + } + } else if (lua_isnumber(L, idx)) { + int decmode = lua_tointeger(L, idx); + int s = (decmode % 10000) / 1000; + int u = (decmode % 1000) / 100; + int g = (decmode % 100) / 10; + int o = (decmode % 10); + + if (s>=0 && s<=7 && u>=0 && u<=7 && g>=0 && g<=7 && o>=0 && o<=7) { + return (s << 9) + (u << 6) + (g << 3) + o; + } + } + + return luaL_argerror(L, idx, "supported values: [0-7]?[0-7][0-7][0-7], " + "[-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]"); +} + +/* Transforms a mode into the modestring */ +int nixio__mode_write(int mode, char *modestr) { + if (modestr) { + modestr[0] = (mode & 00400) ? 'r' : '-'; + modestr[1] = (mode & 00200) ? 'w' : '-'; + modestr[2] = ((mode & 04100) == 04100) ? 's' : + (mode & 04000) ? 'S' : (mode & 00100) ? 'x' : '-'; + modestr[3] = (mode & 00040) ? 'r' : '-'; + modestr[4] = (mode & 00020) ? 'w' : '-'; + modestr[5] = ((mode & 02010) == 02010) ? 's' : + (mode & 02000) ? 'S' : (mode & 00010) ? 'x' : '-'; + modestr[6] = (mode & 00004) ? 'r' : '-'; + modestr[7] = (mode & 00002) ? 'w' : '-'; + modestr[8] = ((mode & 01001) == 01001) ? 't' : + (mode & 01000) ? 'T' : (mode & 00001) ? 'x' : '-'; + } + + return (mode & 00007) + ((mode & 00070) >> 3) * 10 + + ((mode & 00700) >> 6) * 100 + ((mode & 07000) >> 9) * 1000; +} + +static int nixio_access(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + int mode = F_OK; + + for (const char *s = luaL_optstring(L, 2, "f"); *s; s++) { + if (*s == 'r') { + mode |= R_OK; + } else if (*s == 'w') { + mode |= W_OK; + } else if (*s == 'x') { + mode |= X_OK; + } else if (*s != 'f') { + return luaL_argerror(L, 2, "supported values: [frwx]"); + } + } + + return nixio__pstatus(L, !access(path, mode)); +} + +static int nixio_basename(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char base[PATH_MAX]; + base[PATH_MAX-1] = 0; + + strncpy(base, path, PATH_MAX-1); + lua_pushstring(L, basename(base)); + return 1; +} + +static int nixio_dirname(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char base[PATH_MAX]; + base[PATH_MAX-1] = 0; + + strncpy(base, path, PATH_MAX-1); + lua_pushstring(L, dirname(base)); + return 1; +} + +static int nixio_realpath(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char real[PATH_MAX]; + + if (!realpath(path, real)) { + return nixio__perror(L); + } else { + lua_pushstring(L, real); + return 1; + } +} + +static int nixio_remove(lua_State *L) { + return nixio__pstatus(L, !remove(luaL_checkstring(L, 1))); +} + +static int nixio_unlink(lua_State *L) { + return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1))); +} + +static int nixio_rename(lua_State *L) { + return nixio__pstatus(L, + !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_rmdir(lua_State *L) { + return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1))); +} + +static int nixio_mkdir(lua_State *L) { + return nixio__pstatus(L, + !mkdir(luaL_checkstring(L, 1), nixio__check_mode(L, 2, 0777))); +} + +static int nixio_chmod(lua_State *L) { + return nixio__pstatus(L, + !chmod(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1))); +} + +static int nixio_dir__gc(lua_State *L) { + DIR **dirp = lua_touserdata(L, 1); + if (dirp && *dirp) { + closedir(*dirp); + *dirp = NULL; + } + return 0; +} + +static int nixio_dir__iter(lua_State *L) { + DIR **dirp = lua_touserdata(L, lua_upvalueindex(1)); + struct dirent *entry; + const char *n = NULL; + + if (*dirp) { + do { + entry = readdir(*dirp); + n = (entry) ? entry->d_name : NULL; + } while(n && n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0))); + } + + if (n) { + lua_pushstring(L, n); + } else { + if (*dirp) { + closedir(*dirp); + *dirp = NULL; + } + lua_pushnil(L); + } + + return 1; +} + +static int nixio_dir(lua_State *L) { + const char *path = luaL_optstring(L, 1, "."); + DIR **dirp = lua_newuserdata(L, sizeof(DIR *)); + + *dirp = opendir(path); + if (!*dirp) { + return nixio__perror(L); + } else { + luaL_getmetatable(L, NIXIO_DIR_META); + lua_setmetatable(L, -2); + lua_pushcclosure(L, nixio_dir__iter, 1); + return 1; + } +} + +static int nixio_link(lua_State *L) { + return nixio__pstatus(L, + !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_utimes(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + if (lua_gettop(L) < 2) { + return nixio__pstatus(L, !utimes(path, NULL)); + } else { + double atime = luaL_checknumber(L, 2); + double mtime = luaL_optnumber(L, 3, atime); + struct timeval times[2]; + + times[0].tv_sec = atime; + times[0].tv_usec = (long)((atime - (int64_t)atime) * 1000000); + times[1].tv_sec = mtime; + times[1].tv_usec = (long)((mtime - (int64_t)mtime) * 1000000); + + return nixio__pstatus(L, !utimes(path, times)); + } +} + +int nixio__push_stat(lua_State *L, nixio_stat_t *buf) { + lua_createtable(L, 0, 15); + + lua_pushinteger(L, buf->st_dev); + lua_setfield(L, -2, "dev"); + + lua_pushinteger(L, buf->st_ino); + lua_setfield(L, -2, "ino"); + + if (S_ISREG(buf->st_mode)) { + lua_pushliteral(L, "reg"); + } else if (S_ISDIR(buf->st_mode)) { + lua_pushliteral(L, "dir"); + } else if (S_ISCHR(buf->st_mode)) { + lua_pushliteral(L, "chr"); + } else if (S_ISBLK(buf->st_mode)) { + lua_pushliteral(L, "blk"); + } else if (S_ISFIFO(buf->st_mode)) { + lua_pushliteral(L, "fifo"); + } else if (S_ISLNK(buf->st_mode)) { + lua_pushliteral(L, "lnk"); + } else if (S_ISSOCK(buf->st_mode)) { + lua_pushliteral(L, "sock"); + } else { + lua_pushliteral(L, "unknown"); + } + lua_setfield(L, -2, "type"); + + char modestr[9]; + lua_pushinteger(L, nixio__mode_write(buf->st_mode, modestr)); + lua_setfield(L, -2, "modedec"); + + lua_pushlstring(L, modestr, 9); + lua_setfield(L, -2, "modestr"); + + lua_pushinteger(L, buf->st_nlink); + lua_setfield(L, -2, "nlink"); + + lua_pushinteger(L, buf->st_uid); + lua_setfield(L, -2, "uid"); + + lua_pushinteger(L, buf->st_gid); + lua_setfield(L, -2, "gid"); + + lua_pushinteger(L, buf->st_rdev); + lua_setfield(L, -2, "rdev"); + + lua_pushnumber(L, buf->st_size); + lua_setfield(L, -2, "size"); + + lua_pushinteger(L, buf->st_atime); + lua_setfield(L, -2, "atime"); + + lua_pushinteger(L, buf->st_mtime); + lua_setfield(L, -2, "mtime"); + + lua_pushinteger(L, buf->st_ctime); + lua_setfield(L, -2, "ctime"); + +#ifndef __WINNT__ + lua_pushinteger(L, buf->st_blksize); + lua_setfield(L, -2, "blksize"); + + lua_pushinteger(L, buf->st_blocks); + lua_setfield(L, -2, "blocks"); +#endif + + return 1; +} + +static int nixio_stat(lua_State *L) { + nixio_stat_t buf; + if (stat(luaL_checkstring(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +static int nixio_lstat(lua_State *L) { + nixio_stat_t buf; + if (stat(luaL_checkstring(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +#ifndef __WINNT__ + +static int nixio_chown(lua_State *L) { + return nixio__pstatus(L, + !chown( + luaL_checkstring(L, 1), + lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2), + lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3) + ) + ); +} + +static int nixio_lchown(lua_State *L) { + return nixio__pstatus(L, + !lchown( + luaL_checkstring(L, 1), + lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2), + lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3) + ) + ); +} + +static int nixio_mkfifo(lua_State *L) { + return nixio__pstatus(L, + !mkfifo(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1))); +} + +static int nixio_symlink(lua_State *L) { + return nixio__pstatus(L, + !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_readlink(lua_State *L) { + char dest[PATH_MAX]; + ssize_t res = readlink(luaL_checkstring(L, 1), dest, sizeof(dest)); + if (res < 0) { + return nixio__perror(L); + } else { + lua_pushlstring(L, dest, res); + return 1; + } +} + +#include <glob.h> + +typedef struct { + glob_t gl; + size_t pos; + int freed; +} nixio_glob_t; + +static int nixio_glob__iter(lua_State *L) { + nixio_glob_t *globres = lua_touserdata(L, lua_upvalueindex(1)); + if (!globres->freed && globres->pos < globres->gl.gl_pathc) { + lua_pushstring(L, globres->gl.gl_pathv[(globres->pos)++]); + } else { + if (!globres->freed) { + globfree(&globres->gl); + globres->freed = 1; + } + lua_pushnil(L); + } + return 1; +} + +static int nixio_glob__gc(lua_State *L) { + nixio_glob_t *globres = lua_touserdata(L, 1); + if (globres && !globres->freed) { + globres->freed = 1; + globfree(&globres->gl); + } + return 0; +} + +static int nixio_glob(lua_State *L) { + const char *pattern = luaL_optstring(L, 1, "*"); + nixio_glob_t *globres = lua_newuserdata(L, sizeof(nixio_glob_t)); + if (!globres) { + return luaL_error(L, NIXIO_OOM); + } + globres->pos = 0; + globres->freed = 0; + + int globstat = glob(pattern, 0, NULL, &globres->gl); + if (globstat == GLOB_NOMATCH) { + lua_pushcfunction(L, nixio__nulliter); + lua_pushinteger(L, 0); + } else if (globstat) { + return nixio__perror(L); + } else { + luaL_getmetatable(L, NIXIO_GLOB_META); + lua_setmetatable(L, -2); + lua_pushcclosure(L, nixio_glob__iter, 1); + lua_pushinteger(L, globres->gl.gl_pathc); + } + return 2; +} + +#include <sys/statvfs.h> + +static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) { + lua_createtable(L, 0, 12); + + lua_pushnumber(L, buf->f_bavail); + lua_setfield(L, -2, "bavail"); + + lua_pushnumber(L, buf->f_bfree); + lua_setfield(L, -2, "bfree"); + + lua_pushnumber(L, buf->f_blocks); + lua_setfield(L, -2, "blocks"); + + lua_pushnumber(L, buf->f_bsize); + lua_setfield(L, -2, "bsize"); + + lua_pushnumber(L, buf->f_frsize); + lua_setfield(L, -2, "frsize"); + + lua_pushnumber(L, buf->f_favail); + lua_setfield(L, -2, "favail"); + + lua_pushnumber(L, buf->f_ffree); + lua_setfield(L, -2, "ffree"); + + lua_pushnumber(L, buf->f_files); + lua_setfield(L, -2, "files"); + + lua_pushnumber(L, buf->f_flag); + lua_setfield(L, -2, "flag"); + + lua_pushnumber(L, buf->f_fsid); + lua_setfield(L, -2, "fsid"); + + lua_pushnumber(L, buf->f_namemax); + lua_setfield(L, -2, "namemax"); + + return 1; +} + +static int nixio_statvfs(lua_State *L) { + struct statvfs buf; + if (statvfs(luaL_optstring(L, 1, "."), &buf)) { + return nixio__perror(L); + } else { + return nixio__push_statvfs(L, &buf); + } +} + +#endif /* !__WINNT__ */ + + + +/* module table */ +static const luaL_reg R[] = { +#ifndef __WINNT__ + {"glob", nixio_glob}, + {"mkfifo", nixio_mkfifo}, + {"symlink", nixio_symlink}, + {"readlink", nixio_readlink}, + {"chown", nixio_chown}, + {"lchown", nixio_lchown}, + {"statvfs", nixio_statvfs}, +#endif + {"chmod", nixio_chmod}, + {"access", nixio_access}, + {"basename", nixio_basename}, + {"dir", nixio_dir}, + {"dirname", nixio_dirname}, + {"realpath", nixio_realpath}, + {"mkdir", nixio_mkdir}, + {"rmdir", nixio_rmdir}, + {"link", nixio_link}, + {"unlink", nixio_unlink}, + {"utimes", nixio_utimes}, + {"rename", nixio_rename}, + {"remove", nixio_remove}, + {"stat", nixio_stat}, + {"lstat", nixio_lstat}, + {NULL, NULL} +}; + +void nixio_open_fs(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_setfield(L, -2, "fs"); + + luaL_newmetatable(L, NIXIO_DIR_META); + lua_pushcfunction(L, nixio_dir__gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + +#ifndef __WINNT__ + luaL_newmetatable(L, NIXIO_GLOB_META); + lua_pushcfunction(L, nixio_glob__gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); +#endif +} diff --git a/libs/nixio/src/io.c b/libs/nixio/src/io.c index 0ce4fcc3a..8b8f25b42 100644 --- a/libs/nixio/src/io.c +++ b/libs/nixio/src/io.c @@ -18,12 +18,10 @@ #include "nixio.h" #include <errno.h> +#include <string.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netinet/in.h> /** @@ -33,34 +31,46 @@ static int nixio_sock__sendto(lua_State *L, int to) { nixio_sock *sock = nixio__checksock(L); struct sockaddr *addr = NULL; socklen_t alen = 0; + int argoff = 2; if (to) { - const char *address = luaL_checklstring(L, 3, NULL); - uint16_t port = (uint16_t)luaL_checkinteger(L, 4); + argoff += 2; + const char *address = luaL_checkstring(L, 3); struct sockaddr_storage addrstor; addr = (struct sockaddr*)&addrstor; - if (sock->domain == AF_INET) { - struct sockaddr_in *inetaddr = (struct sockaddr_in *)addr; - if (inet_pton(sock->domain, address, &inetaddr->sin_addr) < 0) { - return luaL_argerror(L, 3, "invalid address"); - } - inetaddr->sin_port = htons(port); - alen = sizeof(*inetaddr); - } else if (sock->domain == AF_INET6) { - struct sockaddr_in6 *inet6addr = (struct sockaddr_in6 *)addr; - if (inet_pton(sock->domain, address, &inet6addr->sin6_addr) < 0) { - return luaL_argerror(L, 3, "invalid address"); - } - inet6addr->sin6_port = htons(port); - alen = sizeof(*inet6addr); - } else { - return luaL_argerror(L, 1, "supported families: inet, inet6"); + + nixio_addr naddr; + memset(&naddr, 0, sizeof(naddr)); + strncpy(naddr.host, address, sizeof(naddr.host) - 1); + naddr.port = (uint16_t)luaL_checkinteger(L, 4); + naddr.family = sock->domain; + + if (nixio__addr_write(&naddr, addr)) { + return nixio__perror_s(L); } } size_t len; ssize_t sent; const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > argoff) { + int offset = luaL_optint(L, argoff + 1, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, argoff + 2, len); + if (wlen < len) { + len = wlen; + } + } + do { sent = sendto(sock->fd, data, len, 0, addr, alen); } while(sent == -1 && errno == EINTR); @@ -68,7 +78,7 @@ static int nixio_sock__sendto(lua_State *L, int to) { lua_pushinteger(L, sent); return 1; } else { - return nixio__perror(L); + return nixio__perror_s(L); } } @@ -94,7 +104,7 @@ static int nixio_sock__recvfrom(lua_State *L, int from) { nixio_sock *sock = nixio__checksock(L); char buffer[NIXIO_BUFFERSIZE]; struct sockaddr_storage addrobj; - int req = luaL_checkinteger(L, 2); + uint req = luaL_checkinteger(L, 2); int readc; if (from && sock->domain != AF_INET && sock->domain != AF_INET6) { @@ -111,38 +121,31 @@ static int nixio_sock__recvfrom(lua_State *L, int from) { readc = recvfrom(sock->fd, buffer, req, 0, addr, &alen); } while (readc == -1 && errno == EINTR); +#ifdef __WINNT__ + if (readc < 0) { + int e = WSAGetLastError(); + if (e == WSAECONNRESET || e == WSAECONNABORTED || e == WSAESHUTDOWN) { + readc = 0; + } + } +#endif + if (readc < 0) { - return nixio__perror(L); + return nixio__perror_s(L); } else { lua_pushlstring(L, buffer, readc); if (!from) { return 1; } else { - char ipaddr[INET6_ADDRSTRLEN]; - void *binaddr; - uint16_t port; - - if (addrobj.ss_family == AF_INET) { - struct sockaddr_in *inetaddr = (struct sockaddr_in*)addr; - port = inetaddr->sin_port; - binaddr = &inetaddr->sin_addr; - } else if (addrobj.ss_family == AF_INET6) { - struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)addr; - port = inet6addr->sin6_port; - binaddr = &inet6addr->sin6_addr; + nixio_addr naddr; + if (!nixio__addr_parse(&naddr, (struct sockaddr *)&addrobj)) { + lua_pushstring(L, naddr.host); + lua_pushnumber(L, naddr.port); + return 3; } else { - return luaL_error(L, "unknown address family"); - } - - if (!inet_ntop(addrobj.ss_family, binaddr, ipaddr, sizeof(ipaddr))) { - return nixio__perror(L); + return 1; } - - lua_pushstring(L, ipaddr); - lua_pushinteger(L, ntohs(port)); - - return 3; } } } diff --git a/libs/nixio/src/mingw-compat.c b/libs/nixio/src/mingw-compat.c new file mode 100644 index 000000000..02be504a1 --- /dev/null +++ b/libs/nixio/src/mingw-compat.c @@ -0,0 +1,220 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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 <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/locking.h> +#include <sys/time.h> +#include <sys/utime.h> + +void nixio_open__mingw(lua_State *L) { + _fmode = _O_BINARY; + + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2, 2), &wsa)) { + luaL_error(L, "Unable to initialize Winsock"); + } + + lua_newtable(L); + + NIXIO_WSA_CONSTANT(WSAEACCES); + NIXIO_WSA_CONSTANT(WSAEINTR); + NIXIO_WSA_CONSTANT(WSAEINVAL); + NIXIO_WSA_CONSTANT(WSAEBADF); + NIXIO_WSA_CONSTANT(WSAEFAULT); + NIXIO_WSA_CONSTANT(WSAEMFILE); + NIXIO_WSA_CONSTANT(WSAENAMETOOLONG); + NIXIO_WSA_CONSTANT(WSAELOOP); + NIXIO_WSA_CONSTANT(WSAEAFNOSUPPORT); + NIXIO_WSA_CONSTANT(WSAENOBUFS); + NIXIO_WSA_CONSTANT(WSAEPROTONOSUPPORT); + NIXIO_WSA_CONSTANT(WSAENOPROTOOPT); + NIXIO_WSA_CONSTANT(WSAEADDRINUSE); + NIXIO_WSA_CONSTANT(WSAENETDOWN); + NIXIO_WSA_CONSTANT(WSAENETUNREACH); + NIXIO_WSA_CONSTANT(WSAECONNABORTED); + NIXIO_WSA_CONSTANT(WSAECONNRESET); + + lua_setfield(L, -2, "const_sock"); +} + +const char* nixio__mgw_inet_ntop +(int af, const void *src, char *dst, socklen_t size) { + struct sockaddr_storage saddr; + memset(&saddr, 0, sizeof(saddr)); + + DWORD hostlen = size, sl; + if (af == AF_INET) { + struct sockaddr_in *saddr4 = (struct sockaddr_in *)&saddr; + memcpy(&saddr4->sin_addr, src, sizeof(saddr4->sin_addr)); + saddr4->sin_family = AF_INET; + saddr4->sin_port = 0; + sl = sizeof(struct sockaddr_in); + } else if (af == AF_INET6) { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&saddr; + memcpy(&saddr6->sin6_addr, src, sizeof(saddr6->sin6_addr)); + saddr6->sin6_family = AF_INET6; + saddr6->sin6_port = 0; + sl = sizeof(struct sockaddr_in6); + } else { + return NULL; + } + if (WSAAddressToString((struct sockaddr*)&saddr, sl, NULL, dst, &hostlen)) { + return NULL; + } + return dst; +} + +int nixio__mgw_inet_pton (int af, const char *src, void *dst) { + struct sockaddr_storage sa; + int sl = sizeof(sa); + + if (!WSAStringToAddress((char*)src, af, NULL, (struct sockaddr*)&sa, &sl)) { + if (af == AF_INET) { + struct in_addr ina = ((struct sockaddr_in *)&sa)->sin_addr; + memcpy(dst, &ina, sizeof(ina)); + return 1; + } else if (af == AF_INET6) { + struct in_addr6 ina6 = ((struct sockaddr_in6 *)&sa)->sin6_addr; + memcpy(dst, &ina6, sizeof(ina6)); + return 1; + } else { + WSASetLastError(WSAEAFNOSUPPORT); + return -1; + } + } else { + return -1; + } +} + +int nixio__mgw_nanosleep(const struct timespec *req, struct timespec *rem) { + if (rem) { + rem->tv_sec = 0; + rem->tv_nsec = 0; + } + Sleep(req->tv_sec * 1000 + req->tv_nsec * 1000000); + return 0; +} + +int nixio__mgw_poll(struct pollfd *fds, int nfds, int timeout) { + if (!fds || !nfds) { + Sleep(timeout); + return 0; + } + + struct timeval tv; + int high = 0, rf = 0, wf = 0, ef = 0; + fd_set rfds, wfds, efds; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + for (int i = 0; i < nfds; i++) { + if (fds->events & POLLIN) { + FD_SET(fds->fd, &rfds); + rf++; + } + if (fds->events & POLLOUT) { + FD_SET(fds->fd, &wfds); + wf++; + } + if (fds->events & POLLERR) { + FD_SET(fds->fd, &efds); + ef++; + } + if (fds->fd > high) { + high = fds->fd; + } + } + + int stat = select(high + 1, (rf) ? &rfds : NULL, + (wf) ? &wfds : NULL, (ef) ? &efds : NULL, &tv); + if (stat < 1) { + errno = WSAGetLastError(); + return stat; + } + + high = 0; + + for (int i = 0; i < nfds; i++) { + fds->revents = 0; + if ((fds->events & POLLIN) && FD_ISSET(fds->fd, &rfds)) { + fds->revents |= POLLIN; + } + if ((fds->events & POLLOUT) && FD_ISSET(fds->fd, &wfds)) { + fds->revents |= POLLOUT; + } + if ((fds->events & POLLERR) && FD_ISSET(fds->fd, &efds)) { + fds->revents |= POLLERR; + } + if (fds->revents) { + high++; + } + } + + return high; +} + +int nixio__mgw_lockf(int fd, int cmd, off_t len) { + int stat; + if (cmd == F_LOCK) { + do { + stat = _locking(fd, _LK_LOCK, len); + } while (stat == -1 && errno == EDEADLOCK); + } else if (cmd == F_TLOCK) { + stat = _locking(fd, _LK_NBLCK, len); + } else if (cmd == F_ULOCK) { + stat = _locking(fd, _LK_UNLCK, len); + } else { + stat = -1; + errno = EINVAL; + } + return stat; +} + +char* nixio__mgw_realpath(const char *path, char *resolved) { + if (GetFullPathName(path, PATH_MAX, resolved, NULL)) { + return resolved; + } else { + errno = GetLastError(); + return NULL; + } +} + +int nixio__mgw_link(const char *oldpath, const char *newpath) { + if (!CreateHardLink(newpath, oldpath, NULL)) { + errno = GetLastError(); + return -1; + } else { + return 0; + } +} + +int nixio__mgw_utimes(const char *filename, const struct timeval times[2]) { + struct _utimbuf timebuffer; + timebuffer.actime = times[0].tv_sec; + timebuffer.modtime = times[1].tv_sec; + + return _utime(filename, &timebuffer); +} diff --git a/libs/nixio/src/mingw-compat.h b/libs/nixio/src/mingw-compat.h new file mode 100644 index 000000000..a26a4beec --- /dev/null +++ b/libs/nixio/src/mingw-compat.h @@ -0,0 +1,112 @@ +#ifndef NIXIO_MINGW_COMPAT_H_ +#define NIXIO_MINGW_COMPAT_H_ + +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <process.h> +#include <stdint.h> +#include <sys/stat.h> +#include <errno.h> + +typedef unsigned int uint; +typedef unsigned long ulong; + +#define S_ISLNK(m) 0 +#define S_ISSOCK(m) 0 + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ENOPROTOOPT WSAENOPROTOOPT + +#define SHUT_RD SD_RECEIVE +#define SHUT_WR SD_SEND +#define SHUT_RDWR SD_BOTH + +#define pipe(fds) _pipe(fds, 65536, 0) +#define fsync _commit +#define lseek lseek64 +#define stat _stati64 +#define lstat _stati64 +#define fstat _fstati64 + + +#define F_LOCK 1 +#define F_ULOCK 0 +#define F_TLOCK 2 +#define F_TEST 3 +int nixio__mgw_lockf(int fd, int cmd, off_t len); +#define lockf nixio__mgw_lockf + +const char* nixio__mgw_inet_ntop +(int af, const void *src, char *dst, socklen_t size); +#define inet_ntop nixio__mgw_inet_ntop + +int nixio__mgw_inet_pton (int af, const char *src, void *dst); +#define inet_pton nixio__mgw_inet_pton + + +#ifndef POLLIN +#define POLLIN 0x001 +#define POLLOUT 0x004 +#define POLLERR 0x008 +struct pollfd { + int fd; + short events; + short revents; +}; +#endif + +typedef int nfds_t; +int nixio__mgw_poll(struct pollfd *fds, nfds_t nfds, int timeout); +#define poll nixio__mgw_poll + + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +int nixio__mgw_nanosleep(const struct timespec *req, struct timespec *rem); +#define nanosleep nixio__mgw_nanosleep + + +char* nixio__mgw_realpath(const char *path, char *resolved); +#define realpath nixio__mgw_realpath + + +int nixio__mgw_link(const char *oldpath, const char *newpath); +#define link nixio__mgw_link + + +int nixio__mgw_utimes(const char *filename, const struct timeval times[2]); +#define utimes nixio__mgw_utimes + + +#define setenv(k, v, o) !SetEnvironmentVariable(k, v) +#define unsetenv(k) !SetEnvironmentVariable(k, NULL) + +#define execv(p, a) execv(p, (const char* const*)a) +#define execvp(p, a) execvp(p, (const char* const*)a) +#define execve(p, a, e) execve(p, (const char* const*)a, (const char* const*)e) + +#define mkdir(p, m) mkdir(p) + + +#define nixio__perror_s(L) \ + errno = WSAGetLastError(); \ + return nixio__perror(L); + +#define nixio__pstatus_s(L, c) \ + errno = WSAGetLastError(); \ + return nixio__pstatus(L, c); + + + +#define NIXIO_WSA_CONSTANT(x) \ + lua_pushinteger(L, x); \ + lua_setfield(L, -2, #x+3); + +void nixio_open__mingw(lua_State *L); + +#endif /* NIXIO_MINGW_COMPAT_H_ */ diff --git a/libs/nixio/src/nixio-tls.h b/libs/nixio/src/nixio-tls.h index 4c58dd136..0fac5a980 100644 --- a/libs/nixio/src/nixio-tls.h +++ b/libs/nixio/src/nixio-tls.h @@ -2,9 +2,12 @@ #define NIXIO_TLS_H_ #include "nixio.h" +#include <sys/types.h> #ifndef WITHOUT_OPENSSL #include <openssl/ssl.h> +#include <openssl/md5.h> +#include <openssl/sha.h> #endif #define NIXIO_TLS_CTX_META "nixio.tls.ctx" @@ -20,4 +23,31 @@ typedef struct nixio_tls_socket { #endif } nixio_tls_sock; +#define NIXIO_CRYPTO_HASH_META "nixio.crypto.hash" +#define NIXIO_DIGEST_SIZE 64 +#define NIXIO_CRYPTO_BLOCK_SIZE 64 + +#define NIXIO_HASH_NONE 0 +#define NIXIO_HASH_MD5 0x01 +#define NIXIO_HASH_SHA1 0x02 + +#define NIXIO_HMAC_BIT 0x40 + +typedef int(*nixio_hash_initcb)(void *); +typedef int(*nixio_hash_updatecb)(void *, const void *, unsigned long); +typedef int(*nixio_hash_finalcb)(unsigned char *, void *); + +typedef struct nixio_hash_obj { + uint type; + unsigned char digest[NIXIO_DIGEST_SIZE]; + size_t digest_size; + unsigned char key[NIXIO_CRYPTO_BLOCK_SIZE]; + size_t key_size; + size_t block_size; + void *ctx; + nixio_hash_initcb init; + nixio_hash_updatecb update; + nixio_hash_finalcb final; +} nixio_hash; + #endif /* NIXIO_TLS_H_ */ diff --git a/libs/nixio/src/nixio.c b/libs/nixio/src/nixio.c index 3a70aa8da..457bbd1f2 100644 --- a/libs/nixio/src/nixio.c +++ b/libs/nixio/src/nixio.c @@ -27,7 +27,7 @@ /* pushes nil, error number and errstring on the stack */ int nixio__perror(lua_State *L) { - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { lua_pushboolean(L, 0); } else { lua_pushnil(L); @@ -85,6 +85,17 @@ int nixio__tofd(lua_State *L, int ud) { return fd; } +/* An empty iterator */ +int nixio__nulliter(lua_State *L) { + lua_pushnil(L); + return 1; +} + +static int nixio_errno(lua_State *L) { + lua_pushinteger(L, errno); + return 1; +} + static int nixio_strerror(lua_State *L) { lua_pushstring(L, strerror(luaL_checkinteger(L, 1))); return 1; @@ -92,12 +103,13 @@ static int nixio_strerror(lua_State *L) { /* object table */ static const luaL_reg R[] = { + {"errno", nixio_errno}, {"strerror", nixio_strerror}, {NULL, NULL} }; /* entry point */ -LUALIB_API int luaopen_nixio(lua_State *L) { +NIXIO_API int luaopen_nixio(lua_State *L) { /* create metatable */ luaL_newmetatable(L, NIXIO_META); @@ -113,6 +125,9 @@ LUALIB_API int luaopen_nixio(lua_State *L) { lua_setfield(L, -2, "meta_socket"); /* register methods */ +#ifdef __WINNT__ + nixio_open__mingw(L); +#endif nixio_open_file(L); nixio_open_socket(L); nixio_open_sockopt(L); @@ -123,6 +138,11 @@ LUALIB_API int luaopen_nixio(lua_State *L) { nixio_open_splice(L); nixio_open_process(L); nixio_open_syslog(L); + nixio_open_bit(L); + nixio_open_bin(L); + nixio_open_fs(L); + nixio_open_user(L); + nixio_open_tls_crypto(L); nixio_open_tls_context(L); nixio_open_tls_socket(L); @@ -131,13 +151,21 @@ LUALIB_API int luaopen_nixio(lua_State *L) { lua_setfield(L, -2, "version"); /* some constants */ - lua_createtable(L, 0, 49); + lua_newtable(L); + + lua_pushliteral(L, NIXIO_SEP); + lua_setfield(L, -2, "sep"); + + lua_pushliteral(L, NIXIO_PATHSEP); + lua_setfield(L, -2, "pathsep"); + + lua_pushinteger(L, NIXIO_BUFFERSIZE); + lua_setfield(L, -2, "buffersize"); NIXIO_PUSH_CONSTANT(EACCES); NIXIO_PUSH_CONSTANT(EINTR); NIXIO_PUSH_CONSTANT(ENOSYS); NIXIO_PUSH_CONSTANT(EINVAL); - NIXIO_PUSH_CONSTANT(EWOULDBLOCK); NIXIO_PUSH_CONSTANT(EAGAIN); NIXIO_PUSH_CONSTANT(ENOMEM); NIXIO_PUSH_CONSTANT(ENOENT); @@ -152,37 +180,51 @@ LUALIB_API int luaopen_nixio(lua_State *L) { NIXIO_PUSH_CONSTANT(EISDIR); NIXIO_PUSH_CONSTANT(EPERM); NIXIO_PUSH_CONSTANT(EEXIST); - NIXIO_PUSH_CONSTANT(ELOOP); NIXIO_PUSH_CONSTANT(EMFILE); NIXIO_PUSH_CONSTANT(ENAMETOOLONG); NIXIO_PUSH_CONSTANT(ENFILE); NIXIO_PUSH_CONSTANT(ENODEV); + NIXIO_PUSH_CONSTANT(EXDEV); NIXIO_PUSH_CONSTANT(ENOTDIR); NIXIO_PUSH_CONSTANT(ENXIO); - NIXIO_PUSH_CONSTANT(EOVERFLOW); NIXIO_PUSH_CONSTANT(EROFS); + NIXIO_PUSH_CONSTANT(EBUSY); + NIXIO_PUSH_CONSTANT(ESRCH); + NIXIO_PUSH_CONSTANT(SIGINT); + NIXIO_PUSH_CONSTANT(SIGTERM); + NIXIO_PUSH_CONSTANT(SIGSEGV); + +#ifndef __WINNT__ + NIXIO_PUSH_CONSTANT(EWOULDBLOCK); + NIXIO_PUSH_CONSTANT(ELOOP); + NIXIO_PUSH_CONSTANT(EOVERFLOW); NIXIO_PUSH_CONSTANT(ETXTBSY); NIXIO_PUSH_CONSTANT(EAFNOSUPPORT); NIXIO_PUSH_CONSTANT(ENOBUFS); NIXIO_PUSH_CONSTANT(EPROTONOSUPPORT); NIXIO_PUSH_CONSTANT(ENOPROTOOPT); - NIXIO_PUSH_CONSTANT(EBUSY); - NIXIO_PUSH_CONSTANT(ESRCH); + NIXIO_PUSH_CONSTANT(EADDRINUSE); + NIXIO_PUSH_CONSTANT(ENETDOWN); + NIXIO_PUSH_CONSTANT(ENETUNREACH); + NIXIO_PUSH_CONSTANT(SIGALRM); - NIXIO_PUSH_CONSTANT(SIGINT); - NIXIO_PUSH_CONSTANT(SIGTERM); NIXIO_PUSH_CONSTANT(SIGKILL); NIXIO_PUSH_CONSTANT(SIGHUP); NIXIO_PUSH_CONSTANT(SIGSTOP); NIXIO_PUSH_CONSTANT(SIGCONT); - NIXIO_PUSH_CONSTANT(SIGSEGV); NIXIO_PUSH_CONSTANT(SIGCHLD); NIXIO_PUSH_CONSTANT(SIGQUIT); NIXIO_PUSH_CONSTANT(SIGUSR1); NIXIO_PUSH_CONSTANT(SIGUSR2); NIXIO_PUSH_CONSTANT(SIGIO); NIXIO_PUSH_CONSTANT(SIGURG); + NIXIO_PUSH_CONSTANT(SIGPIPE); + + lua_pushvalue(L, -1); + lua_setfield(L, -3, "const_sock"); + signal(SIGPIPE, SIG_IGN); +#endif /* !__WINNT__ */ lua_setfield(L, -2, "const"); /* remove meta table */ diff --git a/libs/nixio/src/nixio.h b/libs/nixio/src/nixio.h index 23da17d44..8caa5b969 100644 --- a/libs/nixio/src/nixio.h +++ b/libs/nixio/src/nixio.h @@ -1,9 +1,12 @@ #ifndef NIXIO_H_ #define NIXIO_H_ +#define NIXIO_OOM "out of memory" + #define NIXIO_META "nixio.socket" #define NIXIO_FILE_META "nixio.file" -#define NIXIO_BUFFERSIZE 8096 +#define NIXIO_GLOB_META "nixio.glob" +#define NIXIO_DIR_META "nixio.dir" #define _FILE_OFFSET_BITS 64 #define NIXIO_PUSH_CONSTANT(x) \ @@ -17,6 +20,8 @@ #include <lualib.h> #include <lauxlib.h> +#define NIXIO_BUFFERSIZE 8192 + typedef struct nixio_socket { int fd; int domain; @@ -24,12 +29,66 @@ typedef struct nixio_socket { int protocol; } nixio_sock; +typedef struct nixio_address { + int family; + char host[128]; + int port; +} nixio_addr; + int nixio__perror(lua_State *L); int nixio__pstatus(lua_State *L, int condition); + +#ifndef __WINNT__ + +#define NIXIO_API extern + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <net/if.h> +#include <sys/un.h> +#include <netdb.h> +#include <poll.h> +#include <sys/stat.h> +#include <errno.h> + +#define NIXIO_SEP "/" +#define NIXIO_PATHSEP ":" + +#define nixio__perror_s nixio__perror +#define nixio__pstatus_s nixio__pstatus + +int nixio__check_group(lua_State *L, int idx); +int nixio__check_user(lua_State *L, int idx); + +typedef struct stat nixio_stat_t; + +#else /* __WINNT__ */ + +#define NIXIO_API extern __declspec(dllexport) +#define NIXIO_SEP "\\" +#define NIXIO_PATHSEP ";" +#include "mingw-compat.h" + +typedef struct _stati64 nixio_stat_t; + +#endif + 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); +int nixio__nulliter(lua_State *L); + +int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr); +int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr); + +int nixio__check_mode(lua_State *L, int idx, int def); +int nixio__mode_write(int mode, char *modestr); + +int nixio__push_stat(lua_State *L, nixio_stat_t *buf); /* Module functions */ void nixio_open_file(lua_State *L); @@ -42,6 +101,11 @@ void nixio_open_io(lua_State *L); void nixio_open_splice(lua_State *L); void nixio_open_process(lua_State *L); void nixio_open_syslog(lua_State *L); +void nixio_open_bit(lua_State *L); +void nixio_open_bin(lua_State *L); +void nixio_open_fs(lua_State *L); +void nixio_open_user(lua_State *L); +void nixio_open_tls_crypto(lua_State *L); void nixio_open_tls_context(lua_State *L); void nixio_open_tls_socket(lua_State *L); diff --git a/libs/nixio/src/poll.c b/libs/nixio/src/poll.c index fdec2caaf..4af32890a 100644 --- a/libs/nixio/src/poll.c +++ b/libs/nixio/src/poll.c @@ -17,12 +17,10 @@ */ #include "nixio.h" -#include <poll.h> #include <time.h> #include <errno.h> #include <string.h> #include <stdlib.h> -#include "nixio.h" /** @@ -71,11 +69,13 @@ static int nixio_poll_flags(lua_State *L) { flags = luaL_checkinteger(L, 1); lua_newtable(L); nixio_poll_flags__r(L, &flags, POLLIN, "in"); - nixio_poll_flags__r(L, &flags, POLLPRI, "pri"); nixio_poll_flags__r(L, &flags, POLLOUT, "out"); nixio_poll_flags__r(L, &flags, POLLERR, "err"); +#ifndef __WINNT__ + nixio_poll_flags__r(L, &flags, POLLPRI, "pri"); nixio_poll_flags__r(L, &flags, POLLHUP, "hup"); nixio_poll_flags__r(L, &flags, POLLNVAL, "nval"); +#endif } else { flags = 0; const int j = lua_gettop(L); @@ -83,16 +83,22 @@ static int nixio_poll_flags(lua_State *L) { const char *flag = luaL_checkstring(L, i); if (!strcmp(flag, "in")) { flags |= POLLIN; - } else if (!strcmp(flag, "pri")) { - flags |= POLLPRI; } else if (!strcmp(flag, "out")) { flags |= POLLOUT; } else if (!strcmp(flag, "err")) { flags |= POLLERR; + } else if (!strcmp(flag, "pri")) { +#ifndef __WINNT__ + flags |= POLLPRI; +#endif } else if (!strcmp(flag, "hup")) { +#ifndef __WINNT__ flags |= POLLHUP; +#endif } else if (!strcmp(flag, "nval")) { +#ifndef __WINNT__ flags |= POLLNVAL; +#endif } else { return luaL_argerror(L, i, "supported values: in, pri, out, err, hup, nval"); @@ -114,11 +120,19 @@ static int nixio_poll(lua_State *L) { /* we are being abused as sleep() replacement... */ if (lua_isnoneornil(L, 1) || len < 1) { - return nixio__pstatus(L, !poll(NULL, 0, timeout)); + if (!poll(NULL, 0, timeout)) { + lua_pushinteger(L, 0); + return 1; + } else { + return nixio__perror(L); + } } luaL_checktype(L, 1, LUA_TTABLE); struct pollfd *fds = calloc(len, sizeof(struct pollfd)); + if (!fds) { + return luaL_error(L, NIXIO_OOM); + } for (i = 0; i < len; i++) { lua_rawgeti(L, 1, i+1); @@ -145,7 +159,11 @@ static int nixio_poll(lua_State *L) { status = poll(fds, (nfds_t)len, timeout); - if (status < 1) { + if (status == 0) { + free(fds); + lua_pushboolean(L, 0); + return 1; + } else if (status < 0) { free(fds); return nixio__perror(L); } diff --git a/libs/nixio/src/process.c b/libs/nixio/src/process.c index a82e5660d..0e8ac8a29 100644 --- a/libs/nixio/src/process.c +++ b/libs/nixio/src/process.c @@ -17,15 +17,98 @@ */ #include "nixio.h" -#include <pwd.h> -#include <grp.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> -#include <sys/wait.h> +#include <sys/stat.h> #include <sys/types.h> #include <signal.h> +#define NIXIO_EXECVE 0x01 +#define NIXIO_EXECV 0x02 +#define NIXIO_EXECVP 0x03 + +int nixio__exec(lua_State *L, int m) { + const char *path = luaL_checkstring(L, 1); + const char *arg; + int argn, i; + + if (m == NIXIO_EXECVE) { + luaL_checktype(L, 2, LUA_TTABLE); + argn = lua_objlen(L, 2) + 1; + } else { + argn = lua_gettop(L); + } + + char **args = lua_newuserdata(L, sizeof(char*) * (argn + 1)); + args[argn] = NULL; + args[0] = (char *)path; + + if (m == NIXIO_EXECVE) { + for (i = 1; i < argn; i++) { + lua_rawgeti(L, 2, i); + arg = lua_tostring(L, -1); + luaL_argcheck(L, arg, 2, "invalid argument"); + args[i] = (char *)arg; + } + + if (lua_isnoneornil(L, 3)) { + execv(path, args); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + argn = 0; + lua_pushnil(L); + while (lua_next(L, 3)) { + if (!lua_checkstack(L, 1)) { + lua_settop(L, 0); + return luaL_error(L, "stack overflow"); + } + + if (!lua_type(L, -2) != LUA_TSTRING || !lua_isstring(L, -1)) { + return luaL_argerror(L, 3, "invalid environment"); + } + + lua_pushfstring(L, "%s=%s", + lua_tostring(L, -2), lua_tostring(L, -1)); + + lua_insert(L, 4); + lua_pop(L, 1); + argn++; + } + + char **env = lua_newuserdata(L, sizeof(char*) * (argn + 1)); + env[argn] = NULL; + + for (i = 1; i < argn; i++) { + env[i-1] = (char *)lua_tostring(L, -i); + } + + execve(path, args, env); + } + } else { + for (i = 2; i <= argn; i++) { + arg = luaL_checkstring(L, i); + args[i-1] = (char *)arg; + } + + if (m == NIXIO_EXECV) { + execv(path, args); + } else { + execvp(path, args); + } + } + + return nixio__perror(L); +} + +#ifndef __WINNT__ +#include <sys/utsname.h> +#include <sys/times.h> +#include <sys/wait.h> +#include <pwd.h> +#include <grp.h> + static int nixio_fork(lua_State *L) { pid_t pid = fork(); if (pid == -1) { @@ -36,16 +119,55 @@ static int nixio_fork(lua_State *L) { } } -static int nixio_signal(lua_State *L) { - int sig = luaL_checkinteger(L, 1); - const char *val = luaL_checkstring(L, 2); +static int nixio_kill(lua_State *L) { + return nixio__pstatus(L, !kill(luaL_checkint(L, 1), luaL_checkint(L, 2))); +} - if (!strcmp(val, "ign") || !strcmp(val, "ignore")) { - return nixio__pstatus(L, signal(sig, SIG_IGN) != SIG_ERR); - } else if (!strcmp(val, "dfl") || !strcmp(val, "default")) { - return nixio__pstatus(L, signal(sig, SIG_DFL) != SIG_ERR); +static int nixio_getppid(lua_State *L) { + lua_pushinteger(L, getppid()); + return 1; +} + +static int nixio_getuid(lua_State *L) { + lua_pushinteger(L, getuid()); + return 1; +} + +static int nixio_getgid(lua_State *L) { + lua_pushinteger(L, getgid()); + return 1; +} + +static int nixio_setgid(lua_State *L) { + return nixio__pstatus(L, !setgid(nixio__check_group(L, 1))); +} + +static int nixio_setuid(lua_State *L) { + return nixio__pstatus(L, !setuid(nixio__check_user(L, 1))); +} + +static int nixio_nice(lua_State *L) { + int nval = luaL_checkint(L, 1); + + errno = 0; + nval = nice(nval); + + if (nval == -1 && errno) { + return nixio__perror(L); } else { - return luaL_argerror(L, 2, "supported values: ign, dfl"); + lua_pushinteger(L, nval); + return 1; + } +} + +static int nixio_setsid(lua_State *L) { + pid_t pid = setsid(); + + if (pid == -1) { + return nixio__perror(L); + } else { + lua_pushinteger(L, pid); + return 1; } } @@ -97,103 +219,229 @@ static int nixio_wait(lua_State *L) { return 3; } -static int nixio_kill(lua_State *L) { - return nixio__pstatus(L, !kill(luaL_checkint(L, 1), luaL_checkint(L, 2))); +static int nixio_times(lua_State *L) { + struct tms buf; + if (times(&buf) == -1) { + return nixio__perror(L); + } else { + lua_createtable(L, 0, 4); + lua_pushnumber(L, buf.tms_cstime); + lua_setfield(L, -2, "cstime"); + + lua_pushnumber(L, buf.tms_cutime); + lua_setfield(L, -2, "cutime"); + + lua_pushnumber(L, buf.tms_stime); + lua_setfield(L, -2, "stime"); + + lua_pushnumber(L, buf.tms_utime); + lua_setfield(L, -2, "utime"); + + return 1; + } } -static int nixio_getpid(lua_State *L) { - lua_pushinteger(L, getpid()); +static int nixio_uname(lua_State *L) { + struct utsname buf; + if (uname(&buf)) { + return nixio__perror(L); + } + + lua_createtable(L, 0, 5); + + lua_pushstring(L, buf.machine); + lua_setfield(L, -2, "machine"); + + lua_pushstring(L, buf.version); + lua_setfield(L, -2, "version"); + + lua_pushstring(L, buf.release); + lua_setfield(L, -2, "release"); + + lua_pushstring(L, buf.nodename); + lua_setfield(L, -2, "nodename"); + + lua_pushstring(L, buf.sysname); + lua_setfield(L, -2, "sysname"); + return 1; } -static int nixio_getppid(lua_State *L) { - lua_pushinteger(L, getppid()); - return 1; +#endif /* !__WINNT__ */ + +static int nixio_chdir(lua_State *L) { + return nixio__pstatus(L, !chdir(luaL_checkstring(L, 1))); } -static int nixio_getuid(lua_State *L) { - lua_pushinteger(L, getuid()); - return 1; +static int nixio_signal(lua_State *L) { + int sig = luaL_checkinteger(L, 1); + const char *val = luaL_checkstring(L, 2); + + if (!strcmp(val, "ign") || !strcmp(val, "ignore")) { + return nixio__pstatus(L, signal(sig, SIG_IGN) != SIG_ERR); + } else if (!strcmp(val, "dfl") || !strcmp(val, "default")) { + return nixio__pstatus(L, signal(sig, SIG_DFL) != SIG_ERR); + } else { + return luaL_argerror(L, 2, "supported values: ign, dfl"); + } } -static int nixio_getgid(lua_State *L) { - lua_pushinteger(L, getgid()); +static int nixio_getpid(lua_State *L) { + lua_pushinteger(L, getpid()); return 1; } -static int nixio_setgid(lua_State *L) { - gid_t gid; - if (lua_isstring(L, 1)) { - struct group *g = getgrnam(lua_tostring(L, 1)); - gid = (!g) ? -1 : g->gr_gid; - } else if (lua_isnumber(L, 1)) { - gid = lua_tointeger(L, 1); +static int nixio_getenv(lua_State *L) { + const char *key = luaL_optstring(L, 1, NULL); + if (key) { + const char *val = getenv(key); + if (val) { + lua_pushstring(L, val); + } else { + lua_pushnil(L); + } } else { - return luaL_argerror(L, 1, "supported values: <groupname>, <gid>"); + lua_newtable(L); + extern char **environ; + for (char **c = environ; *c; c++) { + const char *delim = strchr(*c, '='); + if (!delim) { + return luaL_error(L, "invalid environment"); + } + lua_pushlstring(L, *c, delim-*c); + lua_pushstring(L, delim + 1); + lua_rawset(L, -3); + } } + return 1; +} - return nixio__pstatus(L, !setgid(gid)); +static int nixio_setenv(lua_State *L) { + const char *key = luaL_checkstring(L, 1); + const char *val = luaL_optstring(L, 2, NULL); + return nixio__pstatus(L, (val) ? !setenv(key, val, 1) : !unsetenv(key)); } -static int nixio_setuid(lua_State *L) { - uid_t uid; - if (lua_isstring(L, 1)) { - struct passwd *p = getpwnam(lua_tostring(L, 1)); - uid = (!p) ? -1 : p->pw_uid; - } else if (lua_isnumber(L, 1)) { - uid = lua_tointeger(L, 1); - } else { - return luaL_argerror(L, 1, "supported values: <username>, <uid>"); - } +static int nixio_exec(lua_State *L) { + return nixio__exec(L, NIXIO_EXECV); +} - return nixio__pstatus(L, !setuid(uid)); +static int nixio_execp(lua_State *L) { + return nixio__exec(L, NIXIO_EXECVP); } -static int nixio_nice(lua_State *L) { - int nval = luaL_checkint(L, 1); +static int nixio_exece(lua_State *L) { + return nixio__exec(L, NIXIO_EXECVE); +} - errno = 0; - nval = nice(nval); +static int nixio_getcwd(lua_State *L) { + char path[PATH_MAX]; - if (nval == -1 && errno) { - return nixio__perror(L); - } else { - lua_pushinteger(L, nval); + if (getcwd(path, sizeof(path))) { + lua_pushstring(L, path); return 1; + } else { + return nixio__perror(L); } } -static int nixio_setsid(lua_State *L) { - pid_t pid = setsid(); +static int nixio_umask(lua_State *L) { + char mask[9]; + lua_pushinteger(L, + nixio__mode_write(umask(nixio__check_mode(L, 1, -1)), mask)); + lua_pushlstring(L, mask, 9); + return 2; +} - if (pid == -1) { +#ifdef __linux__ + +#include <sys/sysinfo.h> + +static int nixio_sysinfo(lua_State *L) { + struct sysinfo info; + if (sysinfo(&info)) { return nixio__perror(L); - } else { - lua_pushinteger(L, pid); - return 1; } -} -static int nixio_chdir(lua_State *L) { - return nixio__pstatus(L, !chdir(luaL_checkstring(L, 1))); + lua_createtable(L, 0, 12); + + lua_pushnumber(L, info.bufferram); + lua_setfield(L, -2, "bufferram"); + + lua_pushnumber(L, info.freehigh); + lua_setfield(L, -2, "freehigh"); + + lua_pushnumber(L, info.freeram); + lua_setfield(L, -2, "freeram"); + + lua_pushnumber(L, info.freeswap); + lua_setfield(L, -2, "freeswap"); + + lua_createtable(L, 0, 3); + for (int i=0; i<3; i++) { + lua_pushnumber(L, info.loads[i] / 65536.); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loads"); + + lua_pushnumber(L, info.mem_unit); + lua_setfield(L, -2, "mem_unit"); + + lua_pushnumber(L, info.procs); + lua_setfield(L, -2, "procs"); + + lua_pushnumber(L, info.sharedram); + lua_setfield(L, -2, "sharedram"); + + lua_pushnumber(L, info.totalhigh); + lua_setfield(L, -2, "totalhigh"); + + lua_pushnumber(L, info.totalram); + lua_setfield(L, -2, "totalram"); + + lua_pushnumber(L, info.totalswap); + lua_setfield(L, -2, "totalswap"); + + lua_pushnumber(L, info.uptime); + lua_setfield(L, -2, "uptime"); + + return 1; } +#endif + /* module table */ static const luaL_reg R[] = { +#ifdef __linux__ + {"sysinfo", nixio_sysinfo}, +#endif +#ifndef __WINNT__ {"fork", nixio_fork}, - {"wait", nixio_wait}, {"kill", nixio_kill}, {"nice", nixio_nice}, - {"chdir", nixio_chdir}, - {"getpid", nixio_getpid}, {"getppid", nixio_getppid}, {"getuid", nixio_getuid}, {"getgid", nixio_getgid}, {"setuid", nixio_setuid}, {"setgid", nixio_setgid}, {"setsid", nixio_setsid}, + {"wait", nixio_wait}, + {"waitpid", nixio_wait}, + {"times", nixio_times}, + {"uname", nixio_uname}, +#endif + {"chdir", nixio_chdir}, {"signal", nixio_signal}, + {"getpid", nixio_getpid}, + {"getenv", nixio_getenv}, + {"setenv", nixio_setenv}, + {"putenv", nixio_setenv}, + {"exec", nixio_exec}, + {"execp", nixio_execp}, + {"exece", nixio_exece}, + {"getcwd", nixio_getcwd}, + {"umask", nixio_umask}, {NULL, NULL} }; diff --git a/libs/nixio/src/socket.c b/libs/nixio/src/socket.c index 336f34812..17c6afc79 100644 --- a/libs/nixio/src/socket.c +++ b/libs/nixio/src/socket.c @@ -17,12 +17,9 @@ */ #include "nixio.h" -#include <sys/socket.h> -#include <netinet/in.h> #include <unistd.h> #include <string.h> #include <errno.h> -#include "nixio.h" /** @@ -79,7 +76,7 @@ static int nixio_socket(lua_State *L) { sock->fd = socket(sock->domain, sock->type, sock->protocol); if (sock->fd < 0) { - return nixio__perror(L); + return nixio__perror_s(L); } return 1; @@ -95,10 +92,14 @@ static int nixio_sock_close(lua_State *L) { sock->fd = -1; do { +#ifndef __WINNT__ res = close(sockfd); +#else + res = closesocket(sockfd); +#endif } while (res == -1 && errno == EINTR); - return nixio__pstatus(L, !res); + return nixio__pstatus_s(L, !res); } /** @@ -109,7 +110,11 @@ static int nixio_sock__gc(lua_State *L) { int res; if (sock && sock->fd != -1) { do { +#ifndef __WINNT__ res = close(sock->fd); +#else + res = closesocket(sock->fd); +#endif } while (res == -1 && errno == EINTR); } return 0; @@ -141,7 +146,7 @@ static int nixio_sock_shutdown(lua_State *L) { return luaL_argerror(L, 2, "supported values: both, read, write"); } - return nixio__pstatus(L, !shutdown(sockfd, how)); + return nixio__pstatus_s(L, !shutdown(sockfd, how)); } /* module table */ diff --git a/libs/nixio/src/sockopt.c b/libs/nixio/src/sockopt.c index 2d68d12ef..7e063e4a3 100644 --- a/libs/nixio/src/sockopt.c +++ b/libs/nixio/src/sockopt.c @@ -17,17 +17,25 @@ */ #include "nixio.h" + #include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <net/if.h> #include <sys/time.h> #include <string.h> #include <fcntl.h> #include <errno.h> -#include "nixio.h" +#ifndef IPV6_ADD_MEMBERSHIP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + +#ifndef IPV6_DROP_MEMBERSHIP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + +static int nixio_sock_fileno(lua_State *L) { + lua_pushinteger(L, nixio__checkfd(L, 1)); + return 1; +} /** * setblocking() @@ -36,6 +44,9 @@ static int nixio_sock_setblocking(lua_State *L) { int fd = nixio__checkfd(L, 1); luaL_checkany(L, 2); int set = lua_toboolean(L, 2); + +#ifndef __WINNT__ + int flags = fcntl(fd, F_GETFL); if (flags == -1) { @@ -49,50 +60,64 @@ static int nixio_sock_setblocking(lua_State *L) { } return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags)); + +#else /* __WINNT__ */ + + lua_getmetatable(L, 1); + luaL_getmetatable(L, NIXIO_META); + if (lua_equal(L, -1, -2)) { /* Socket */ + unsigned long val = !set; + return nixio__pstatus_s(L, !ioctlsocket(fd, FIONBIO, &val)); + } else { /* File */ + WSASetLastError(WSAENOTSOCK); + return nixio__perror_s(L); + } + +#endif /* __WINNT__ */ } static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) { int value; socklen_t optlen = sizeof(value); if (!set) { - if (!getsockopt(fd, level, opt, &value, &optlen)) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { lua_pushinteger(L, value); return 1; } } else { value = luaL_checkinteger(L, set); - if (!setsockopt(fd, level, opt, &value, optlen)) { + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { lua_pushboolean(L, 1); return 1; } } - return nixio__perror(L); + return nixio__perror_s(L); } static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) { struct linger value; socklen_t optlen = sizeof(value); if (!set) { - if (!getsockopt(fd, level, opt, &value, &optlen)) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { lua_pushinteger(L, value.l_onoff ? value.l_linger : 0); return 1; } } else { value.l_linger = luaL_checkinteger(L, set); value.l_onoff = value.l_linger ? 1 : 0; - if (!setsockopt(fd, level, opt, &value, optlen)) { + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { lua_pushboolean(L, 1); return 1; } } - return nixio__perror(L); + return nixio__perror_s(L); } static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) { struct timeval value; socklen_t optlen = sizeof(value); if (!set) { - if (!getsockopt(fd, level, opt, &value, &optlen)) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { lua_pushinteger(L, value.tv_sec); lua_pushinteger(L, value.tv_usec); return 2; @@ -100,12 +125,12 @@ static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) { } else { value.tv_sec = luaL_checkinteger(L, set); value.tv_usec = luaL_optinteger(L, set + 1, 0); - if (!setsockopt(fd, level, opt, &value, optlen)) { + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { lua_pushboolean(L, 1); return 1; } } - return nixio__perror(L); + return nixio__perror_s(L); } #ifdef SO_BINDTODEVICE @@ -114,7 +139,7 @@ static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) { if (!set) { socklen_t optlen = IFNAMSIZ; char ifname[IFNAMSIZ]; - if (!getsockopt(fd, level, opt, ifname, &optlen)) { + if (!getsockopt(fd, level, opt, (char *)ifname, &optlen)) { lua_pushlstring(L, ifname, optlen); return 1; } @@ -122,16 +147,76 @@ static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) { size_t valuelen; const char *value = luaL_checklstring(L, set, &valuelen); luaL_argcheck(L, valuelen <= IFNAMSIZ, set, "invalid interface name"); - if (!setsockopt(fd, level, opt, value, valuelen)) { + if (!setsockopt(fd, level, opt, (char *)value, valuelen)) { lua_pushboolean(L, 1); return 1; } } - return nixio__perror(L); + return nixio__perror_s(L); } #endif /* SO_BINDTODEVICE */ +static int nixio__gso_mreq4(lua_State *L, int fd, int level, int opt, int set) { + struct ip_mreq value; + socklen_t optlen = sizeof(value); + if (!set) { + char buf[INET_ADDRSTRLEN]; + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { + if (!inet_ntop(AF_INET, &value.imr_multiaddr, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + if (!inet_ntop(AF_INET, &value.imr_interface, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + return 2; + } + } else { + const char *maddr = luaL_checkstring(L, set); + const char *iface = luaL_optstring(L, set + 1, "0.0.0.0"); + if (inet_pton(AF_INET, maddr, &value.imr_multiaddr) < 1) { + return nixio__perror_s(L); + } + if (inet_pton(AF_INET, iface, &value.imr_interface) < 1) { + return nixio__perror_s(L); + } + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +static int nixio__gso_mreq6(lua_State *L, int fd, int level, int opt, int set) { + struct ipv6_mreq val; + socklen_t optlen = sizeof(val); + if (!set) { + char buf[INET_ADDRSTRLEN]; + if (!getsockopt(fd, level, opt, (char *)&val, &optlen)) { + if (!inet_ntop(AF_INET6, &val.ipv6mr_multiaddr, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + lua_pushnumber(L, val.ipv6mr_interface); + return 2; + } + } else { + const char *maddr = luaL_checkstring(L, set); + if (inet_pton(AF_INET6, maddr, &val.ipv6mr_multiaddr) < 1) { + return nixio__perror_s(L); + } + val.ipv6mr_interface = luaL_optlong(L, set + 1, 0); + if (!setsockopt(fd, level, opt, (char *)&val, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + /** * get/setsockopt() helper */ @@ -183,9 +268,6 @@ static int nixio__getsetsockopt(lua_State *L, int set) { ); } } else if (!strcmp(level, "tcp")) { - if (sock->type != SOCK_STREAM) { - return luaL_error(L, "not a TCP socket"); - } if (!strcmp(option, "cork")) { #ifdef TCP_CORK return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_CORK, set); @@ -197,8 +279,71 @@ static int nixio__getsetsockopt(lua_State *L, int set) { } else { return luaL_argerror(L, 3, "supported values: cork, nodelay"); } + } else if (!strcmp(level, "ip")) { + if (!strcmp(option, "mtu")) { +#ifdef IP_MTU + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MTU, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "hdrincl")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_HDRINCL, + set); + } else if (!strcmp(option, "multicast_loop")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, + set); + } else if (!strcmp(option, "multicast_ttl")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_TTL, + set); + } else if (!strcmp(option, "multicast_if")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_MULTICAST_IF, + set); + } else if (!strcmp(option, "add_membership")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + set); + } else if (!strcmp(option, "drop_membership")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + set); + } else { + return luaL_argerror(L, 3, + "supported values: hdrincl, mtu, multicast_loop, " + "multicast_ttl, multicast_if, add_membership, drop_membership"); + } + } else if (!strcmp(level, "ipv6")) { + if (!strcmp(option, "mtu")) { +#ifdef IPV6_MTU + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_MTU, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "v6only")) { +#ifdef IPV6_V6ONLY + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "multicast_loop")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, set); + } else if (!strcmp(option, "multicast_hops")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_HOPS, set); + } else if (!strcmp(option, "multicast_if")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_IF, set); + } else if (!strcmp(option, "add_membership")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, set); + } else if (!strcmp(option, "drop_membership")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_DROP_MEMBERSHIP, set); + } else { + return luaL_argerror(L, 3, + "supported values: v6only, mtu, multicast_loop, multicast_hops," + " multicast_if, add_membership, drop_membership"); + } } else { - return luaL_argerror(L, 2, "supported values: socket, tcp"); + return luaL_argerror(L, 2, "supported values: socket, tcp, ip, ipv6"); } } @@ -221,6 +366,9 @@ static const luaL_reg M[] = { {"setblocking", nixio_sock_setblocking}, {"getsockopt", nixio_sock_getsockopt}, {"setsockopt", nixio_sock_setsockopt}, + {"getopt", nixio_sock_getsockopt}, + {"setopt", nixio_sock_setsockopt}, + {"fileno", nixio_sock_fileno}, {NULL, NULL} }; @@ -232,5 +380,7 @@ void nixio_open_sockopt(lua_State *L) { luaL_getmetatable(L, NIXIO_FILE_META); lua_pushcfunction(L, nixio_sock_setblocking); lua_setfield(L, -2, "setblocking"); + lua_pushcfunction(L, nixio_sock_fileno); + lua_setfield(L, -2, "fileno"); lua_pop(L, 1); } diff --git a/libs/nixio/src/splice.c b/libs/nixio/src/splice.c index f64144627..db215efb1 100644 --- a/libs/nixio/src/splice.c +++ b/libs/nixio/src/splice.c @@ -27,6 +27,9 @@ #include <unistd.h> #include <sys/param.h> + +#ifndef __WINNT__ + #ifndef BSD #include <sys/sendfile.h> #else @@ -150,6 +153,14 @@ static const luaL_reg R[] = { {NULL, NULL} }; + void nixio_open_splice(lua_State *L) { luaL_register(L, NULL, R); } + +#else /* __WINNT__ */ + +void nixio_open_splice(lua_State *L) { +} + +#endif /* !__WINNT__ */ diff --git a/libs/nixio/src/syslog.c b/libs/nixio/src/syslog.c index 9b3581df1..89f1b1dda 100644 --- a/libs/nixio/src/syslog.c +++ b/libs/nixio/src/syslog.c @@ -18,6 +18,8 @@ #include "nixio.h" #include <string.h> + +#ifndef __WINNT__ #include <syslog.h> @@ -57,7 +59,7 @@ static int nixio_closelog(lua_State *L) { return 0; } -static int nixio__syslogmasg(lua_State *L, int dolog) { +static int nixio__syslogmask(lua_State *L, int dolog) { int priority; const char *flag = luaL_checkstring(L, 1); @@ -92,11 +94,11 @@ static int nixio__syslogmasg(lua_State *L, int dolog) { } static int nixio_setlogmask(lua_State *L) { - return nixio__syslogmasg(L, 0); + return nixio__syslogmask(L, 0); } static int nixio_syslog(lua_State *L) { - return nixio__syslogmasg(L, 1); + return nixio__syslogmask(L, 1); } /* module table */ @@ -111,3 +113,10 @@ static const luaL_reg R[] = { void nixio_open_syslog(lua_State *L) { luaL_register(L, NULL, R); } + +#else /* __WINNT__ */ + +void nixio_open_syslog(lua_State *L) { +} + +#endif /* __WINNT__ */ diff --git a/libs/nixio/src/tls-crypto.c b/libs/nixio/src/tls-crypto.c new file mode 100644 index 000000000..c93b1aa18 --- /dev/null +++ b/libs/nixio/src/tls-crypto.c @@ -0,0 +1,188 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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-tls.h" +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +static char nixio__bin2hex[] = { +'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static int nixio_crypto_hash__init(lua_State *L, int hmac) { + const char *type = luaL_checkstring(L, 1); + nixio_hash *hash = lua_newuserdata(L, sizeof(nixio_hash)); + + if (!strcmp(type, "md5")) { + hash->type = NIXIO_HASH_MD5; + hash->digest_size = MD5_DIGEST_LENGTH; + hash->block_size = 64; + hash->ctx = malloc(sizeof(MD5_CTX)); + if (!hash->ctx) { + return luaL_error(L, NIXIO_OOM); + } + MD5_Init((MD5_CTX*)hash->ctx); + hash->init = (nixio_hash_initcb)MD5_Init; + hash->update = (nixio_hash_updatecb)MD5_Update; + hash->final = (nixio_hash_finalcb)MD5_Final; + } else if (!strcmp(type, "sha1")) { + hash->type = NIXIO_HASH_SHA1; + hash->digest_size = SHA_DIGEST_LENGTH; + hash->block_size = 64; + hash->ctx = malloc(sizeof(SHA_CTX)); + if (!hash->ctx) { + return luaL_error(L, NIXIO_OOM); + } + SHA1_Init((SHA_CTX*)hash->ctx); + hash->init = (nixio_hash_initcb)SHA1_Init; + hash->update = (nixio_hash_updatecb)SHA1_Update; + hash->final = (nixio_hash_finalcb)SHA1_Final; + } else { + luaL_argerror(L, 1, "supported values: md5, sha1"); + } + + luaL_getmetatable(L, NIXIO_CRYPTO_HASH_META); + lua_setmetatable(L, -2); + + if (hmac) { + const char *key = luaL_checklstring(L, 2, &hash->key_size); + if (hash->key_size > hash->block_size) { + hash->update(hash->ctx, key, hash->key_size); + hash->final(hash->digest, hash->ctx); + hash->init(hash->ctx); + hash->key_size = hash->digest_size; + memcpy(hash->key, hash->digest, hash->key_size); + } else { + memcpy(hash->key, key, hash->key_size); + } + + unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE]; + for (uint i = 0; i < hash->block_size; i++) { + pad[i] = (i < hash->key_size) ? (0x36 ^ hash->key[i]) : 0x36; + } + hash->update(hash->ctx, pad, hash->block_size); + hash->type |= NIXIO_HMAC_BIT; + } + + return 1; +} + +static int nixio_crypto_hash(lua_State *L) { + return nixio_crypto_hash__init(L, 0); +} + +static int nixio_crypto_hmac(lua_State *L) { + return nixio_crypto_hash__init(L, 1); +} + +static int nixio_crypto_hash_update(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type) { + size_t len; + const char *chunk = luaL_checklstring(L, 2, &len); + hash->update(hash->ctx, chunk, len); + lua_pushvalue(L, 1); + return 1; + } else { + return luaL_error(L, "Tried to update finalized hash object."); + } +} + +static int nixio_crypto_hash_final(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type & NIXIO_HMAC_BIT) { + hash->final(hash->digest, hash->ctx); + hash->init(hash->ctx); + + unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE]; + for (uint i = 0; i < hash->block_size; i++) { + pad[i] = (i < hash->key_size) ? (0x5c ^ hash->key[i]) : 0x5c; + } + + hash->update(hash->ctx, pad, hash->block_size); + hash->update(hash->ctx, hash->digest, hash->digest_size); + } + + if (hash->type) { + hash->type = NIXIO_HASH_NONE; + hash->final(hash->digest, hash->ctx); + free(hash->ctx); + } + + char hashdigest[NIXIO_DIGEST_SIZE*2]; + for (uint i=0; i < hash->digest_size; i++) { + hashdigest[2*i] = nixio__bin2hex[(hash->digest[i] & 0xf0) >> 4]; + hashdigest[2*i+1] = nixio__bin2hex[(hash->digest[i] & 0x0f)]; + } + + lua_pushlstring(L, hashdigest, hash->digest_size * 2); + memcpy(hashdigest, hash->digest, hash->digest_size); + lua_pushlstring(L, hashdigest, hash->digest_size); + + return 2; +} + +static int nixio_crypto_hash__gc(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type) { + hash->final(hash->digest, hash->ctx); + free(hash->ctx); + hash->type = NIXIO_HASH_NONE; + } + return 0; +} + +static int nixio_crypto_hash__tostring(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + lua_pushfstring(L, "nixio hash object: %p", hash); + return 1; +} + + +/* module table */ +static const luaL_reg R[] = { + {"hash", nixio_crypto_hash}, + {"hmac", nixio_crypto_hmac}, + {NULL, NULL} +}; + +/* hash table */ +static const luaL_reg M[] = { + {"update", nixio_crypto_hash_update}, + {"final", nixio_crypto_hash_final}, + {"__gc", nixio_crypto_hash__gc}, + {"__tostring", nixio_crypto_hash__tostring}, + {NULL, NULL} +}; + + + +void nixio_open_tls_crypto(lua_State *L) { + luaL_newmetatable(L, NIXIO_CRYPTO_HASH_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + lua_newtable(L); + luaL_register(L, NULL, R); + + lua_setfield(L, -2, "crypto"); +} diff --git a/libs/nixio/src/tls-socket.c b/libs/nixio/src/tls-socket.c index 0f504ccbb..fe4cb6075 100644 --- a/libs/nixio/src/tls-socket.c +++ b/libs/nixio/src/tls-socket.c @@ -1,4 +1,4 @@ -/* + /* * nixio - Linux I/O library for lua * * Copyright (C) 2009 Steven Barth <steven@midlink.org> @@ -65,7 +65,7 @@ static SSL* nixio__checktlssock(lua_State *L) { static int nixio_tls_sock_recv(lua_State *L) { SSL *sock = nixio__checktlssock(L); nixio_tls__check_connected(L); - int req = luaL_checkinteger(L, 2); + uint req = luaL_checkinteger(L, 2); luaL_argcheck(L, req >= 0, 2, "out of range"); @@ -172,6 +172,24 @@ static int nixio_tls_sock_send(lua_State *L) { size_t len; ssize_t sent; const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > 2) { + int offset = luaL_optint(L, 3, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, 4, len); + if (wlen < len) { + len = wlen; + } + } + sent = SSL_write(sock, data, len); if (sent > 0) { lua_pushinteger(L, sent); diff --git a/libs/nixio/src/user.c b/libs/nixio/src/user.c new file mode 100644 index 000000000..adfe1f4f6 --- /dev/null +++ b/libs/nixio/src/user.c @@ -0,0 +1,257 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * 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 <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <sys/param.h> + +#ifndef __WINNT__ + +#include <grp.h> +#include <pwd.h> + +#ifndef BSD +#include <shadow.h> +#include <crypt.h> +#endif + +int nixio__check_group(lua_State *L, int idx) { + if (lua_isnumber(L, idx)) { + return lua_tointeger(L, idx); + } else if (lua_isstring(L, idx)) { + struct group *g = getgrnam(lua_tostring(L, idx)); + return (!g) ? -1 : g->gr_gid; + } else { + return luaL_argerror(L, idx, "supported values: <groupname>, <gid>"); + } +} + +int nixio__check_user(lua_State *L, int idx) { + if (lua_isnumber(L, idx)) { + return lua_tointeger(L, idx); + } else if (lua_isstring(L, idx)) { + struct passwd *p = getpwnam(lua_tostring(L, idx)); + return (!p) ? -1 : p->pw_uid; + } else { + return luaL_argerror(L, idx, "supported values: <username>, <uid>"); + } +} + + +static int nixio__push_group(lua_State *L, struct group *gr) { + lua_createtable(L, 0, 4); + lua_pushstring(L, gr->gr_name); + lua_setfield(L, -2, "name"); + lua_pushstring(L, gr->gr_passwd); + lua_setfield(L, -2, "passwd"); + lua_pushinteger(L, gr->gr_gid); + lua_setfield(L, -2, "gid"); + lua_newtable(L); + + for (int i=0; gr->gr_mem[i]; i++) { + lua_pushstring(L, gr->gr_mem[i]); + lua_rawseti(L, -2, i+1); + } + + lua_setfield(L, -2, "mem"); + return 1; +} + +static int nixio_getgr(lua_State *L) { + struct group *gr; + errno = 0; + if (lua_isnumber(L, 1)) { + gr = getgrgid(lua_tonumber(L, 1)); + } else if (lua_isstring(L, 1)) { + gr = getgrnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setgrent(); + while ((gr = getgrent())) { + nixio__push_group(L, gr); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endgrent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <groupname>, <gid>"); + } + + if (!gr) { + return nixio__perror(L); + } else { + return nixio__push_group(L, gr); + } +} + +static int nixio__push_passwd(lua_State *L, struct passwd *pw) { + lua_createtable(L, 0, 7); + lua_pushstring(L, pw->pw_name); + lua_setfield(L, -2, "name"); + lua_pushstring(L, pw->pw_passwd); + lua_setfield(L, -2, "passwd"); + lua_pushinteger(L, pw->pw_gid); + lua_setfield(L, -2, "gid"); + lua_pushinteger(L, pw->pw_uid); + lua_setfield(L, -2, "uid"); + lua_pushstring(L, pw->pw_dir); + lua_setfield(L, -2, "dir"); + lua_pushstring(L, pw->pw_gecos); + lua_setfield(L, -2, "gecos"); + lua_pushstring(L, pw->pw_shell); + lua_setfield(L, -2, "shell"); + return 1; +} + +static int nixio_getpw(lua_State *L) { + struct passwd *pw; + errno = 0; + if (lua_isnumber(L, 1)) { + pw = getpwuid(lua_tonumber(L, 1)); + } else if (lua_isstring(L, 1)) { + pw = getpwnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setpwent(); + while ((pw = getpwent())) { + nixio__push_passwd(L, pw); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endpwent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <username>, <uid>"); + } + + if (!pw) { + return nixio__perror(L); + } else { + return nixio__push_passwd(L, pw); + } +} + +#ifndef BSD +static int nixio__push_spwd(lua_State *L, struct spwd *sp) { + lua_createtable(L, 0, 9); + lua_pushstring(L, sp->sp_namp); + lua_setfield(L, -2, "namp"); + lua_pushinteger(L, sp->sp_expire); + lua_setfield(L, -2, "expire"); + lua_pushinteger(L, sp->sp_flag); + lua_setfield(L, -2, "flag"); + lua_pushinteger(L, sp->sp_inact); + lua_setfield(L, -2, "inact"); + lua_pushinteger(L, sp->sp_lstchg); + lua_setfield(L, -2, "lstchg"); + lua_pushinteger(L, sp->sp_max); + lua_setfield(L, -2, "max"); + lua_pushinteger(L, sp->sp_min); + lua_setfield(L, -2, "min"); + lua_pushinteger(L, sp->sp_warn); + lua_setfield(L, -2, "warn"); + lua_pushstring(L, sp->sp_pwdp); + lua_setfield(L, -2, "pwdp"); + return 1; +} + +static int nixio_getsp(lua_State *L) { + struct spwd *sp; + errno = 0; + if (lua_isstring(L, 1)) { + sp = getspnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setspent(); + while ((sp = getspent())) { + nixio__push_spwd(L, sp); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endspent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <username>"); + } + + if (!sp) { + return nixio__perror(L); + } else { + return nixio__push_spwd(L, sp); + } +} +#endif /* !BSD */ + +static int nixio_crypt(lua_State *L) { + const char *key = luaL_checkstring(L, 1); + const char *salt = luaL_checkstring(L, 2); + const char *hash = crypt(key, salt); + + if (hash) { + lua_pushstring(L, hash); + } else { + lua_pushnil(L); + } + + return 1; +} + + +/* module table */ +static const luaL_reg R[] = { + {"crypt", nixio_crypt}, + {"getgr", nixio_getgr}, + {"getpw", nixio_getpw}, +#ifndef BSD + {"getsp", nixio_getsp}, +#endif + {NULL, NULL} +}; + +#else /* __WINNT__ */ + +static const luaL_reg R[] = { + {NULL, NULL} +}; + +#endif + +void nixio_open_user(lua_State *L) { + luaL_register(L, NULL, R); +} |