From 78a4a03e23329178d5b81d903d9279a8d1565b30 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Wed, 28 Sep 2016 15:52:22 +0300 Subject: [PATCH] Fix. `easy:close` removes self from `multi` handle. Change. Do not reset Lua state back to NULL. --- lakefile | 7 +++-- src/lceasy.c | 17 ++++++++++++ src/lcmulti.c | 77 +++++++++++++++++++++++++++++++++++++++++++-------- src/lcmulti.h | 2 ++ 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/lakefile b/lakefile index 1a2530b..3421276 100644 --- a/lakefile +++ b/lakefile @@ -2,8 +2,9 @@ PROJECT = 'cURL' INITLAKEFILE() -DEFINES = L{DEFINES, +DEFINES = L{DEFINES, IF(WINDOWS, 'DLL_EXPORT', ''); + IF(DEBUG, 'LCURL_RESET_NULL_LUA', ''); } cURL = c.shared{'lcurl', @@ -18,7 +19,7 @@ cURL = c.shared{'lcurl', target('build', cURL) install = target('install', { - file.group{odir=LIBDIR; src = cURL }; + file.group{odir=LIBDIR; src = cURL }; file.group{odir=LIBDIR; src = J("src", "lua") ; recurse = true }; file.group{odir=J(ROOT, 'examples'); src = 'examples'; recurse = true }; file.group{odir=TESTDIR; src = 'test'; recurse = true }; @@ -30,6 +31,8 @@ target('test', install, function() run_test('test_form.lua') run_test('test_pause02.c.lua') run_test('test_curl.lua') + run_test('test_multi_callback.lua') + run_test('test_multi_nested_callback.lua') if not test_summary() then quit("test fail") diff --git a/src/lceasy.c b/src/lceasy.c index f02aeca..b237884 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -40,6 +40,8 @@ static const char *LCURL_EASY = LCURL_EASY_NAME; * end) * ``` * So we have to restore previews Lua state in callback contexts. + * But if previews Lua state is NULL then we can just do not set it back. + * But set it to NULL make esier debug code. */ void lcurl__easy_assign_lua(lua_State *L, lcurl_easy_t *p, lua_State *value, int assign_multi){ if(p->multi && assign_multi){ @@ -107,6 +109,12 @@ static int lcurl_easy_cleanup(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); int i; + if(p->multi){ + CURLMcode code = lcurl__multi_remove_handle(L, p->multi, p); + + //! @todo what I can do if I can not remove it??? + } + if(p->curl){ lua_State *curL; @@ -114,6 +122,9 @@ static int lcurl_easy_cleanup(lua_State *L){ // timerfunction called only for single multi handle. curL = p->L; lcurl__easy_assign_lua(L, p, L, 1); curl_easy_cleanup(p->curl); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__easy_assign_lua(L, p, curL, 1); p->curl = NULL; @@ -163,6 +174,9 @@ static int lcurl_easy_perform(lua_State *L){ // User should not call `perform` if handle assign to multi curL = p->L; lcurl__easy_assign_lua(L, p, L, 0); code = curl_easy_perform(p->curl); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__easy_assign_lua(L, p, curL, 0); if(p->rbuffer.ref != LUA_NOREF){ @@ -1070,6 +1084,9 @@ static int lcurl_easy_pause(lua_State *L){ curL = p->L; lcurl__easy_assign_lua(L, p, L, 1); code = curl_easy_pause(p->curl, mask); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__easy_assign_lua(L, p, curL, 1); if(code != CURLE_OK){ diff --git a/src/lcmulti.c b/src/lcmulti.c index 925535c..1e86e4a 100644 --- a/src/lcmulti.c +++ b/src/lcmulti.c @@ -28,7 +28,35 @@ #define LCURL_MULTI_NAME LCURL_PREFIX" Multi" static const char *LCURL_MULTI = LCURL_MULTI_NAME; +#if defined(DEBUG) || defined(_DEBUG) +static void lcurl__multi_validate_sate(lua_State *L, lcurl_multi_t *p){ + int top = lua_gettop(L); + + lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref); + assert(lua_istable(L, -1)); + + lua_pushnil(L); + while(lua_next(L, -2)){ + lcurl_easy_t *e = lcurl_geteasy_at(L, -1); + void *ptr = lua_touserdata(L, -2); + + assert(e->curl == ptr); + assert(e->multi == p); + assert(e->L == p->L); + + lua_pop(L, 1); + } + + lua_pop(L, 1); + assert(lua_gettop(L) == top); +} +#else +# define lcurl__multi_validate_sate(L, p) (void*)(0) +#endif + void lcurl__multi_assign_lua(lua_State *L, lcurl_multi_t *p, lua_State *value, int assign_easy){ + lcurl__multi_validate_sate(L, p); + if((assign_easy)&&(p->L != value)){ lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref); lua_pushnil(L); @@ -145,10 +173,16 @@ static int lcurl_multi_add_handle(lua_State *L){ lua_rawsetp(L, -2, e->curl); lua_settop(L, 1); + // all `esay` handles have to have same L + lcurl__easy_assign_lua(L, e, p->L, 0); + e->multi = p; curL = p->L; lcurl__multi_assign_lua(L, p, L, 1); code = curl_multi_add_handle(p->curl, e->curl); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__multi_assign_lua(L, p, curL, 1); if(code != CURLM_OK){ @@ -166,30 +200,42 @@ static int lcurl_multi_add_handle(lua_State *L){ static int lcurl_multi_remove_handle(lua_State *L){ lcurl_multi_t *p = lcurl_getmulti(L); lcurl_easy_t *e = lcurl_geteasy_at(L, 2); + CURLMcode code = lcurl__multi_remove_handle(L, p, e); + + if(code != CURLM_OK){ + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code); + } + + lua_settop(L, 1); + return 1; +} + +CURLMcode lcurl__multi_remove_handle(lua_State *L, lcurl_multi_t *p, lcurl_easy_t *e){ CURLMcode code; lua_State *curL; if(e->multi != p){ // cURL returns CURLM_OK for such call so we do the same. // tested on 7.37.1 - lua_settop(L, 1); - return 1; + return CURLM_OK; } curL = p->L; lcurl__multi_assign_lua(L, p, L, 1); code = curl_multi_remove_handle(p->curl, e->curl); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__multi_assign_lua(L, p, curL, 1); - if(code != CURLM_OK){ - lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code); + if(code == CURLM_OK){ + e->multi = NULL; + lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref); + lua_pushnil(L); + lua_rawsetp(L, -2, e->curl); + lua_pop(L, 1); } - - e->multi = NULL; - lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref); - lua_pushnil(L); - lua_rawsetp(L, -2, e->curl); - lua_settop(L, 1); - return 1; + + return code; } static int lcurl_multi_perform(lua_State *L){ @@ -200,6 +246,9 @@ static int lcurl_multi_perform(lua_State *L){ curL = p->L; lcurl__multi_assign_lua(L, p, L, 1); while((code = curl_multi_perform(p->curl, &running_handles)) == CURLM_CALL_MULTI_PERFORM); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__multi_assign_lua(L, p, curL, 1); if(code != CURLM_OK){ @@ -232,6 +281,9 @@ static int lcurl_multi_info_read(lua_State *L){ curL = p->L; lcurl__multi_assign_lua(L, p, L, 1); code = curl_multi_remove_handle(p->curl, e->curl); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__multi_assign_lua(L, p, curL, 1); if(CURLM_OK == code){ @@ -337,6 +389,9 @@ static int lcurl_multi_socket_action(lua_State *L){ curL = p->L; lcurl__multi_assign_lua(L, p, L, 1); code = curl_multi_socket_action(p->curl, s, mask, &n); +#ifndef LCURL_RESET_NULL_LUA + if(curL != NULL) +#endif lcurl__multi_assign_lua(L, p, curL, 1); if(code != CURLM_OK){ diff --git a/src/lcmulti.h b/src/lcmulti.h index 16e6d7c..a49f832 100644 --- a/src/lcmulti.h +++ b/src/lcmulti.h @@ -33,4 +33,6 @@ void lcurl_multi_initlib(lua_State *L, int nup); void lcurl__multi_assign_lua(lua_State *L, lcurl_multi_t *p, lua_State *value, int assign_easy); +CURLMcode lcurl__multi_remove_handle(lua_State *L, lcurl_multi_t *p, lcurl_easy_t *e); + #endif