From add079a9495d2293957f4cf21c23205a34038009 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka <valenok@gmail.com> Date: Sun, 19 May 2013 01:25:54 +0100 Subject: [PATCH] Added socket functions to lua environment --- mod_lua.c | 130 ++++++++++++++++++++++++++++++++++++++++++++--------- mongoose.c | 109 +++++++++++++++++++++++++------------------- 2 files changed, 171 insertions(+), 68 deletions(-) diff --git a/mod_lua.c b/mod_lua.c index dc3d92b8e..8e42fe1d0 100644 --- a/mod_lua.c +++ b/mod_lua.c @@ -18,11 +18,112 @@ static void *mmap(void *addr, int64_t len, int prot, int flags, int fd, #include <sys/mman.h> #endif -static void handle_request(struct mg_connection *); +static const char *LUASOCKET = "luasocket"; +// Forward declarations +static void handle_request(struct mg_connection *); static int handle_lsp_request(struct mg_connection *, const char *, struct file *, struct lua_State *); +static void reg_string(struct lua_State *L, const char *name, const char *val) { + lua_pushstring(L, name); + lua_pushstring(L, val); + lua_rawset(L, -3); +} + +static void reg_int(struct lua_State *L, const char *name, int val) { + lua_pushstring(L, name); + lua_pushinteger(L, val); + lua_rawset(L, -3); +} + +static void reg_function(struct lua_State *L, const char *name, + lua_CFunction func, struct mg_connection *conn) { + lua_pushstring(L, name); + lua_pushlightuserdata(L, conn); + lua_pushcclosure(L, func, 1); + lua_rawset(L, -3); +} + +static int lsp_sock_close(lua_State *L) { + if (lua_gettop(L) > 0 && lua_istable(L, -1)) { + lua_getfield(L, -1, "sock"); + closesocket((SOCKET) lua_tonumber(L, -1)); + } else { + return luaL_error(L, "invalid :close() call"); + } + return 1; +} + +static int lsp_sock_recv(lua_State *L) { + char buf[2000]; + int n; + + if (lua_gettop(L) > 0 && lua_istable(L, -1)) { + lua_getfield(L, -1, "sock"); + n = recv((SOCKET) lua_tonumber(L, -1), buf, sizeof(buf), 0); + if (n <= 0) { + lua_pushnil(L); + } else { + lua_pushlstring(L, buf, n); + } + } else { + return luaL_error(L, "invalid :close() call"); + } + return 1; +} + +static int lsp_sock_send(lua_State *L) { + const char *buf; + size_t len, sent = 0; + int n, sock; + + if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) { + buf = lua_tolstring(L, -1, &len); + lua_getfield(L, -2, "sock"); + sock = lua_tonumber(L, -1); + while (sent < len) { + if ((n = send(sock, buf + sent, len - sent, 0)) <= 0) { + break; + } + sent += n; + } + lua_pushnumber(L, n); + } else { + return luaL_error(L, "invalid :close() call"); + } + return 1; +} + +static const struct luaL_Reg luasocket_methods[] = { + {"close", lsp_sock_close}, + {"send", lsp_sock_send}, + {"recv", lsp_sock_recv}, + {NULL, NULL} +}; + +static int lsp_connect(lua_State *L) { + char ebuf[100]; + SOCKET sock; + + if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) { + sock = conn2(lua_tostring(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1), + ebuf, sizeof(ebuf)); + if (sock == INVALID_SOCKET) { + return luaL_error(L, ebuf); + } else { + lua_newtable(L); + reg_int(L, "sock", sock); + reg_string(L, "host", lua_tostring(L, -4)); + luaL_getmetatable(L, LUASOCKET); + lua_setmetatable(L, -2); + } + } else { + return luaL_error(L, "connect(host,port,is_ssl): invalid parameter given."); + } + return 1; +} + static int lsp_error(lua_State *L) { lua_getglobal(L, "mg"); lua_getfield(L, -1, "onerror"); @@ -141,26 +242,6 @@ static int lsp_redirect(lua_State *L) { return 0; } -static void reg_string(struct lua_State *L, const char *name, const char *val) { - lua_pushstring(L, name); - lua_pushstring(L, val); - lua_rawset(L, -3); -} - -static void reg_int(struct lua_State *L, const char *name, int val) { - lua_pushstring(L, name); - lua_pushinteger(L, val); - lua_rawset(L, -3); -} - -static void reg_function(struct lua_State *L, const char *name, - lua_CFunction func, struct mg_connection *conn) { - lua_pushstring(L, name); - lua_pushlightuserdata(L, conn); - lua_pushcclosure(L, func, 1); - lua_rawset(L, -3); -} - void mg_prepare_lua_environment(struct mg_connection *conn, lua_State *L) { const struct mg_request_info *ri = mg_get_request_info(conn); extern void luaL_openlibs(lua_State *); @@ -171,6 +252,13 @@ void mg_prepare_lua_environment(struct mg_connection *conn, lua_State *L) { { extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); } #endif + luaL_newmetatable(L, LUASOCKET); + lua_pushliteral(L, "__index"); + luaL_newlib(L, luasocket_methods); + lua_rawset(L, -3); + lua_pop(L, 1); + lua_register(L, "connect", lsp_connect); + if (conn == NULL) return; // Register mg module diff --git a/mongoose.c b/mongoose.c index 6194ded43..1c3598732 100644 --- a/mongoose.c +++ b/mongoose.c @@ -514,6 +514,13 @@ struct mg_connection { int64_t last_throttle_bytes;// Bytes sent this second }; +// Directory entry +struct de { + struct mg_connection *conn; + char *file_name; + struct file file; +}; + const char **mg_get_valid_option_names(void) { return config_options; } @@ -2508,11 +2515,36 @@ int mg_modify_passwords_file(const char *fname, const char *domain, return 1; } -struct de { - struct mg_connection *conn; - char *file_name; - struct file file; -}; +static int conn2(const char *host, int port, int use_ssl, + char *ebuf, size_t ebuf_len) { + struct sockaddr_in sin; + struct hostent *he; + SOCKET sock = INVALID_SOCKET; + + if (host == NULL) { + snprintf(ebuf, ebuf_len, "%s", "NULL host"); + } else if (use_ssl && SSLv23_client_method == NULL) { + snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized"); + // TODO(lsm): use something threadsafe instead of gethostbyname() + } else if ((he = gethostbyname(host)) == NULL) { + snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO)); + } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO)); + } else { + sin.sin_family = AF_INET; + sin.sin_port = htons((uint16_t) port); + sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; + if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { + snprintf(ebuf, ebuf_len, "connect(%s:%d): %s", + host, port, strerror(ERRNO)); + closesocket(sock); + sock = INVALID_SOCKET; + } + } + return sock; +} + + static void url_encode(const char *src, char *dst, size_t dst_len) { static const char *dont_escape = "._-$,;~()"; @@ -4641,54 +4673,37 @@ struct mg_connection *mg_connect(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len) { static struct mg_context fake_ctx; struct mg_connection *conn = NULL; - struct sockaddr_in sin; - struct hostent *he; SOCKET sock; - if (host == NULL) { - snprintf(ebuf, ebuf_len, "%s", "NULL host"); - } else if (use_ssl && SSLv23_client_method == NULL) { - snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized"); - } else if ((he = gethostbyname(host)) == NULL) { - snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO)); - } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO)); - } else { - sin.sin_family = AF_INET; - sin.sin_port = htons((uint16_t) port); - sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; - if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { - snprintf(ebuf, ebuf_len, "connect(%s:%d): %s", - host, port, strerror(ERRNO)); - closesocket(sock); - } else if ((conn = (struct mg_connection *) - calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) { - snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO)); - closesocket(sock); + if ((sock = conn2(host, port, use_ssl, ebuf, ebuf_len)) == INVALID_SOCKET) { + } else if ((conn = (struct mg_connection *) + calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) { + snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO)); + closesocket(sock); #ifndef NO_SSL - } else if (use_ssl && (conn->client_ssl_ctx = - SSL_CTX_new(SSLv23_client_method())) == NULL) { - snprintf(ebuf, ebuf_len, "SSL_CTX_new error"); - closesocket(sock); - free(conn); - conn = NULL; + } else if (use_ssl && (conn->client_ssl_ctx = + SSL_CTX_new(SSLv23_client_method())) == NULL) { + snprintf(ebuf, ebuf_len, "SSL_CTX_new error"); + closesocket(sock); + free(conn); + conn = NULL; #endif // NO_SSL - } else { - conn->buf_size = MAX_REQUEST_SIZE; - conn->buf = (char *) (conn + 1); - conn->ctx = &fake_ctx; - conn->client.sock = sock; - conn->client.rsa.sin = sin; - conn->client.is_ssl = use_ssl; + } else { + socklen_t len; + conn->buf_size = MAX_REQUEST_SIZE; + conn->buf = (char *) (conn + 1); + conn->ctx = &fake_ctx; + conn->client.sock = sock; + getsockname(sock, &conn->client.rsa.sa, &len); + conn->client.is_ssl = use_ssl; #ifndef NO_SSL - if (use_ssl) { - // SSL_CTX_set_verify call is needed to switch off server certificate - // checking, which is off by default in OpenSSL and on in yaSSL. - SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0); - sslize(conn, conn->client_ssl_ctx, SSL_connect); - } -#endif + if (use_ssl) { + // SSL_CTX_set_verify call is needed to switch off server certificate + // checking, which is off by default in OpenSSL and on in yaSSL. + SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0); + sslize(conn, conn->client_ssl_ctx, SSL_connect); } +#endif } return conn; -- GitLab