luacurl源码阅读3 - binding函数(成员函数)
注册在curlT表下,可以看作curlT类的成员函数
static const struct luaL_reg luacurl_meths[] = { {"close", lcurl_easy_close}, {"setopt", lcurl_easy_setopt}, {"perform", lcurl_easy_perform}, {"getinfo", lcurl_easy_getinfo}, {"__gc", lcurl_gc}, {0, 0}, }; LUACURL_API int luaopen_luacurl (lua_State *L) { //...... createmeta(L); luaL_openlib (L, 0, luacurl_meths, 0); //将函数注册到curlT表下 //...... return 1; //栈顶弹出1个元素, 作为lua层拿到的返回值 }
lcurl_easy_getinfo函数
/* Request internal information from the curl session */ static int lcurl_easy_getinfo(lua_State* L) { printf("lcurl_easy_getinfo begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, -1)) ); // 2, number curlT* c=tocurl(L, 1); //将栈底元素转换为curlT类型 CURLINFO nInfo; CURLcode code=-1; luaL_checktype(L, 2, LUA_TNUMBER); /* accept info code number only, 函数参数只能是CURLINFO枚举值, CURLINFO_Xxx */ nInfo=lua_tonumber(L, 2); if (nInfo>CURLINFO_SLIST) //信息结果是列表 { /* string list */ struct curl_slist *slist=0; if (CURLE_OK == (code=curl_easy_getinfo(c->curl, nInfo, &slist))) { if (slist) { /*相当于 local infoTab = {} infoTab[i] = "xxx" */ int i; lua_newtable(L); //这个是操作对象infoTab for (i=1; slist; i++, slist=slist->next) { lua_pushnumber(L, i); //这个是key lua_pushstring(L, slist->data); //这个是value lua_settable(L, -3); //infoTab[key] = value, 执行完后栈顶弹出2个元素 } curl_slist_free_all(slist); } else { lua_pushnil(L); } return 1; //栈顶弹出1个元素, 作为lua层拿到的返回值 } else { /* curl_easy_getinfo returns error */ } } else if (nInfo>CURLINFO_DOUBLE) //信息结果是double { /* double */ double value; if (CURLE_OK == (code=curl_easy_getinfo(c->curl, nInfo, &value))) { lua_pushnumber(L, value); return 1; } else { /* curl_easy_getinfo returns error */ } } else if (nInfo>CURLINFO_LONG) //信息结果是long { /* long */ long value; if (CURLE_OK == (code=curl_easy_getinfo(c->curl, nInfo, &value))) { lua_pushinteger(L, (lua_Integer)value); return 1; } else { /* curl_easy_getinfo returns error */ } } else if (nInfo>CURLINFO_STRING) //信息结果是string { /* string */ char* value; if (CURLE_OK == (code=curl_easy_getinfo(c->curl, nInfo, &value))) { lua_pushstring(L, value); return 1; } else { /* curl_easy_getinfo returns error */ } } /* on error */ /* return nil, error message, error code */ lua_pushnil(L); if (code>CURLE_OK) { #if CURL_NEWER(7,11,2) lua_pushstring(L, curl_easy_strerror(code)); //根据错误码, 获取错误描述 #else lua_pushfstring(L, "Curl error: #%d", (code)); #endif lua_pushnumber(L, code); return 3; //栈顶弹出3个元素, 作为lua层拿到的返回值: nil, 错误描述, 错误码 } else { lua_pushfstring(L, "Invalid CURLINFO number: %d", nInfo); return 2; //栈顶弹出3个元素, 作为lua层拿到的返回值: nil, 错误描述 } }
下面的lua代码,就会调用c层的lcurl_easy_getinfo
local curl = require("luacurl") local obj = curl.new() local size = obj:getinfo(curl.INFO_FILETIME) print(size)
lcurl_gc函数
/* garbage collect the curl object */ static int lcurl_gc(lua_State* L) { printf("lcurl_gc begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, -1))); curlT* c = (curlT*)luaL_checkudata(L, 1, CURLHANDLE); //尝试将栈底元素转换为curlT类型 if (c && c->curl) { curl_easy_cleanup(c->curl); } printf("lcurl_gc end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, -1))); return 0; }
lua虚拟机回收lua对象时,会调用该函数
lcurl_easy_setopt函数
/* set any supported curl option (see also ALL_CURL_OPT) */ static int lcurl_easy_setopt(lua_State* L) { //调用这个函数的时候, 需要保证栈上至少有3个元素: curl对象, CURL_OPT_名字, opt值 printf("lcurl_easy_setopt begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); // 3, userdata union luaValueT v; /* the result option value, 会存放到curlT的xud字段上 */ int curlOpt; /* the provided option code */ CURLcode code; /* return error code from curl */ curlT* c = tocurl(L, 1); /* get self object, 将栈底元素转换为curlT类型 */ luaL_checktype(L, 2, LUA_TNUMBER); /* accept only number option codes, 检查CURL_OPT_名字参数类型是否合法 */ if (lua_gettop(L)<3) /* option value is always required */ { luaL_error(L, "Invalid number of arguments %d to `setopt' method", lua_gettop(L)); } curlOpt=(int)lua_tonumber(L, 2); /* get the curl option code */ v.nval=0; switch (curlOpt) { case CURLOPT_PROGRESSFUNCTION: case CURLOPT_READFUNCTION: case CURLOPT_WRITEFUNCTION: case CURLOPT_HEADERFUNCTION: case CURLOPT_IOCTLFUNCTION: luaL_checktype(L, 3, LUA_TFUNCTION); /* callback options require Lua function value */ case CURLOPT_READDATA: case CURLOPT_WRITEDATA: case CURLOPT_PROGRESSDATA: case CURLOPT_HEADERDATA: #if CURL_NEWER(7,12,3) case CURLOPT_IOCTLDATA: //io control data #endif switch (lua_type(L, 3)) /* handle table, userdata and funtion callback params specially */ { case LUA_TTABLE: case LUA_TUSERDATA: case LUA_TTHREAD: case LUA_TFUNCTION: { int ref; lua_pushvalue(L, 3); //栈[3]处的元素(即: lua层调用setopt的第2个参数)再压入栈顶 //弹出栈顶元素, 分配一个refId, 将弹出的元素存放在: 栈[LUA_REGISTRYINDEX][refId]处 ref=luaL_ref(L, LUA_REGISTRYINDEX); /* get reference to the lua object in registry */ if (curlOpt == CURLOPT_READFUNCTION) { //先将之前存放在栈[LUA_REGISTRYINDEX][freaderRef]处的元素置为nil luaL_unref(L, LUA_REGISTRYINDEX, c->freaderRef); /* unregister previous reference to reader if any */ c->freaderRef=ref; /* keep the reader function reference in self */ v.rcb=(curl_read_callback)readerCallback; /* redirect the option value to readerCallback */ //CURLOPT_READDATA的值会在readerCallback的最后一个参数拿到 if (CURLE_OK != (code=curl_easy_setopt(c->curl, CURLOPT_READDATA, c))) goto on_error; } else if (curlOpt == CURLOPT_WRITEFUNCTION) { luaL_unref(L, LUA_REGISTRYINDEX, c->fwriterRef); c->fwriterRef=ref; v.wcb=(curl_write_callback)writerCallback; //CURLOPT_WRITEDATA的值会在writeCallback的最后一个参数上拿到 if (CURLE_OK != (code=curl_easy_setopt(c->curl, CURLOPT_WRITEDATA, c))) goto on_error; } else if (curlOpt == CURLOPT_PROGRESSFUNCTION) { luaL_unref(L, LUA_REGISTRYINDEX, c->fprogressRef); c->fprogressRef=ref; v.pcb=(curl_progress_callback)progressCallback; if (CURLE_OK != (code=curl_easy_setopt(c->curl, CURLOPT_PROGRESSDATA, c))) goto on_error; } else if (curlOpt == CURLOPT_HEADERFUNCTION) { luaL_unref(L, LUA_REGISTRYINDEX, c->fheaderRef); c->fheaderRef=ref; v.wcb=(curl_write_callback)headerCallback; if (CURLE_OK != (code=curl_easy_setopt(c->curl, CURLOPT_HEADERDATA, c))) goto on_error; } #if CURL_NEWER(7,12,3) else if (curlOpt == CURLOPT_IOCTLFUNCTION) { luaL_unref(L, LUA_REGISTRYINDEX, c->fioctlRef); c->fioctlRef=ref; v.icb=ioctlCallback; if (CURLE_OK != (code=curl_easy_setopt(c->curl, CURLOPT_IOCTLDATA, c))) goto on_error; } #endif else { /* When the option code is any of CURLOPT_xxxDATA and the argument is table, /* userdata or function set the curl option value to the lua object reference */ //CURLOPT_WRITEDATA这种 printf("setopt: nval:%x\n", ref); v.nval=ref; } }break; default: { //nothing }break; }break; //其他的CURLOPT_Xxx, 这边使用宏的方式来写 /* Handle all supported curl options differently according the specific option argument type */ #undef C_OPT // 例如: case CURLOPT_URL: get_string(L, 3); #define C_OPT(n, t) \ case CURLOPT_##n: \ v=get_##t(L, 3); \ break; #undef C_OPT_SL // 例如: case CURLOPT_HTTPHEADER: get_slist(L, 3, &KEY_HTTPHEADER); KEY_##n是一个标识符, 在一开始定义的static const char* KEY_##n #define C_OPT_SL(n) \ case CURLOPT_##n: \ { \ v=get_slist(L, 3, &KEY_##n); \ }break; /* Expands all the list of switch-case's here, 剩余的case */ ALL_CURL_OPT default: luaL_error(L, "Not supported curl option %d", curlOpt); } /* additional check if the option value has compatible type with the option code */ switch (lua_type(L, 3)) { case LUA_TFUNCTION: /* allow function argument only for the special option codes */ if (curlOpt == CURLOPT_READFUNCTION || curlOpt == CURLOPT_WRITEFUNCTION || curlOpt == CURLOPT_PROGRESSFUNCTION || curlOpt == CURLOPT_HEADERFUNCTION || curlOpt == CURLOPT_IOCTLFUNCTION ) break; case LUA_TTABLE: /* allow table or userdata only for the callback parameter option */ case LUA_TUSERDATA: if (curlOpt != CURLOPT_READDATA && curlOpt != CURLOPT_WRITEDATA && curlOpt != CURLOPT_PROGRESSDATA && curlOpt != CURLOPT_HEADERDATA #if CURL_NEWER(7,12,3) && curlOpt != CURLOPT_IOCTLDATA #endif ) luaL_error(L, "argument #2 type %s is not compatible with this option", lua_typename(L, 3)); break; } /* handle curl option for setting callback parameter */ switch (curlOpt) { case CURLOPT_READDATA: //lua层多次调用的情况: obj:setopt(curl.OPT_WRITEDATA, userData_X) if (c->rudtype == LUA_TFUNCTION || c->rudtype == LUA_TUSERDATA || c->rudtype == LUA_TTABLE || c->rudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->rud.nval); /* unref previously referenced read data */ c->rudtype=lua_type(L, 3); /* set the read data type */ c->rud=v; /* set the read data value (it can be reference) */ v.ptr=c; /* set the real read data to curl as our self object */ break; case CURLOPT_WRITEDATA: printf("lcurl_easy_setopt: writedata: %d\n", c->wud.nval); if (c->wudtype == LUA_TFUNCTION || c->wudtype == LUA_TUSERDATA || c->wudtype == LUA_TTABLE || c->wudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->wud.nval); c->wudtype=lua_type(L, 3); c->wud=v; v.ptr=c; break; case CURLOPT_PROGRESSDATA: if (c->pudtype == LUA_TFUNCTION || c->pudtype == LUA_TUSERDATA || c->pudtype == LUA_TTABLE || c->pudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->pud.nval); c->pudtype=lua_type(L, 3); c->pud=v; v.ptr=c; break; case CURLOPT_HEADERDATA: if (c->hudtype == LUA_TFUNCTION || c->hudtype == LUA_TUSERDATA || c->hudtype == LUA_TTABLE || c->hudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->hud.nval); c->hudtype=lua_type(L, 3); c->hud=v; v.ptr=c; break; #if CURL_NEWER(7,12,3) case CURLOPT_IOCTLDATA: if (c->iudtype == LUA_TFUNCTION || c->iudtype == LUA_TUSERDATA || c->iudtype == LUA_TTABLE || c->iudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->iud.nval); c->iudtype=lua_type(L, 3); c->iud=v; v.ptr=c; break; #endif } /* set easy the curl option with the processed value */ int opt = (int)lua_tonumber(L, 2); //CURLOPT_WRITEDATA时, opt值为curlT指针, v.ptr //CURLOPT_WRITEFUNCTION时, opt值为回调函数指针, v.wcb //CURLOPT_URL时, opt值为v.sval if (CURLE_OK == (code=curl_easy_setopt(c->curl, opt, v.ptr))) { /* on success return true */ lua_pushboolean(L, 1); printf("lcurl_easy_setopt end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); // 4, userdata return 1; //栈顶弹出1个元素, 作为lua层拿到的返回值: true } on_error: /* on fail return nil, error message, error code */ lua_pushnil(L); #if CURL_NEWER(7,11,2) lua_pushstring(L, curl_easy_strerror(code)); #else lua_pushfstring(L, "Curl error: #%d", (code)); #endif lua_pushnumber(L, code); printf("lcurl_easy_setopt end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); return 3; //栈顶弹出3个元素, 作为lua层拿到的返回值: nil, 错误描述, 错误码 }
lcurl_easy_perform函数
/* perform the curl commands */ static int lcurl_easy_perform(lua_State* L) { printf("lcurl_easy_perform begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); // 1, userdata CURLcode code; /* return error code from curl */ curlT* c = tocurl(L, 1); /* get self object, 将栈底元素转换为curlT类型 */ code = curl_easy_perform(c->curl); /* do the curl perform */ if (CURLE_OK == code) { /* on success return true */ lua_pushboolean(L, 1); printf("lcurl_easy_perform end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); // 3, userdata return 1; //栈顶弹出1个元素, 作为lua层拿到的返回值: true } /* on fail return nil, error message, error code */ lua_pushnil(L); #if CURL_NEWER(7,11,2) lua_pushstring(L, curl_easy_strerror(code)); #else lua_pushfstring(L, "Curl error: #%d", (code)); #endif lua_pushnumber(L, code); return 3; //栈顶弹出3个元素, 作为lua层拿到的返回值: nil, 错误描述, 错误码 }
lcurl_easy_close函数
/* Finalizes CURL */ static int lcurl_easy_close(lua_State* L) { printf("lcurl_easy_close begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); // 1, userdata curlT* c=tocurl(L, 1); //将栈底元素转换为curlT类型 curl_easy_cleanup(c->curl); luaL_unref(L, LUA_REGISTRYINDEX, c->freaderRef); //栈[LUA_REGISTRYINDEX][xxxRefId]设为nil, 即: CURLOPT_XxxFUNCTION关联的lua对象 luaL_unref(L, LUA_REGISTRYINDEX, c->fwriterRef); luaL_unref(L, LUA_REGISTRYINDEX, c->fprogressRef); luaL_unref(L, LUA_REGISTRYINDEX, c->fheaderRef); luaL_unref(L, LUA_REGISTRYINDEX, c->fioctlRef); //栈[LUA_REGISTRYINDEX][nval]设为nil, 即: CURLOPT_XxxDATA关联的lua对象 if (c->rudtype == LUA_TFUNCTION || c->rudtype == LUA_TUSERDATA || c->rudtype == LUA_TTABLE || c->rudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->rud.nval); if (c->wudtype == LUA_TFUNCTION || c->wudtype == LUA_TUSERDATA || c->wudtype == LUA_TTABLE || c->wudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->wud.nval); if (c->pudtype == LUA_TFUNCTION || c->pudtype == LUA_TUSERDATA || c->pudtype == LUA_TTABLE || c->pudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->pud.nval); if (c->hudtype == LUA_TFUNCTION || c->hudtype == LUA_TUSERDATA || c->hudtype == LUA_TTABLE || c->hudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->hud.nval); if (c->iudtype == LUA_TFUNCTION || c->iudtype == LUA_TUSERDATA || c->iudtype == LUA_TTABLE || c->iudtype == LUA_TTHREAD) luaL_unref(L, LUA_REGISTRYINDEX, c->iud.nval); #undef C_OPT #undef C_OPT_SL #undef C_OPT_SPECIAL #define C_OPT(n, t) #define C_OPT_SL(n) free_slist(L, &KEY_##n); #define C_OPT_SPECIAL(n) //宏展开 ALL_CURL_OPT c->curl=0; lua_pushboolean(L, 1); return 1; //栈顶弹出1个元素, 作为lua层拿到的返回值 }

浙公网安备 33010602011771号