// Lua: s = net.create(type, secure/timeout, function(conn)) static int net_create( lua_State* L, const char* mt ) { NODE_DBG("net_create is called.\n"); struct espconn *pesp_conn = NULL; lnet_userdata *nud, *temp = NULL; unsigned type; #ifdef CLIENT_SSL_ENABLE unsigned secure = 0; #endif uint8_t stack = 1; bool isserver = false; if (mt!=NULL && c_strcmp(mt, "net.server")==0) isserver = true; else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) isserver = false; else { NODE_DBG("wrong metatable for net_create.\n"); return 0; } type = luaL_checkinteger( L, stack ); if ( type != ESPCONN_TCP && type != ESPCONN_UDP ) return luaL_error( L, "wrong arg type" ); stack++; #ifdef CLIENT_SSL_ENABLE if(!isserver){ if ( lua_isnumber(L, stack) ) { secure = lua_tointeger(L, stack); stack++; if ( secure != 0 && secure != 1 ){ return luaL_error( L, "wrong arg type" ); } } else { secure = 0; // default to 0 } } #endif if(isserver && type == ESPCONN_TCP){ if ( lua_isnumber(L, stack) ) { unsigned to = lua_tointeger(L, stack); stack++; if ( to < 1 || to > 28800 ){ return luaL_error( L, "wrong arg type" ); } tcp_server_timeover = (uint16_t)to; } else { tcp_server_timeover = 30; // default to 30 } } // create a object nud = (lnet_userdata *)lua_newuserdata(L, sizeof(lnet_userdata)); // pre-initialize it, in case of errors nud->self_ref = LUA_NOREF; nud->cb_connect_ref = LUA_NOREF; nud->cb_reconnect_ref = LUA_NOREF; nud->cb_disconnect_ref = LUA_NOREF; nud->cb_receive_ref = LUA_NOREF; nud->cb_send_ref = LUA_NOREF; nud->cb_dns_found_ref = LUA_NOREF; nud->pesp_conn = NULL; #ifdef CLIENT_SSL_ENABLE nud->secure = secure; #endif // set its metatable luaL_getmetatable(L, mt); lua_setmetatable(L, -2); // create the espconn struct if(isserver && type==ESPCONN_TCP && pTcpServer){ if(tcpserver_cb_connect_ref != LUA_NOREF){ // self_ref should be unref in close() lua_pop(L,1); return luaL_error(L, "only one tcp server allowed"); } pesp_conn = nud->pesp_conn = pTcpServer; } else if(isserver && type==ESPCONN_UDP && pUdpServer){ temp = (lnet_userdata *)pUdpServer->reverse; if(temp && temp->self_ref != LUA_NOREF){ lua_pop(L,1); return luaL_error(L, "only one udp server allowed"); } pesp_conn = nud->pesp_conn = pUdpServer; } else { pesp_conn = nud->pesp_conn = (struct espconn *)c_zalloc(sizeof(struct espconn)); if(!pesp_conn) return luaL_error(L, "not enough memory"); pesp_conn->proto.tcp = NULL; pesp_conn->proto.udp = NULL; pesp_conn->reverse = NULL; if( type==ESPCONN_TCP ) { pesp_conn->proto.tcp = (esp_tcp *)c_zalloc(sizeof(esp_tcp)); if(!pesp_conn->proto.tcp){ c_free(pesp_conn); pesp_conn = nud->pesp_conn = NULL; return luaL_error(L, "not enough memory"); } NODE_DBG("TCP server/socket is set.\n"); } else if( type==ESPCONN_UDP ) { pesp_conn->proto.udp = (esp_udp *)c_zalloc(sizeof(esp_udp)); if(!pesp_conn->proto.udp){ c_free(pesp_conn); pesp_conn = nud->pesp_conn = NULL; return luaL_error(L, "not enough memory"); } NODE_DBG("UDP server/socket is set.\n"); } } pesp_conn->type = type; pesp_conn->state = ESPCONN_NONE; // reverse is for the callback function pesp_conn->reverse = nud; if(isserver && type==ESPCONN_TCP && pTcpServer==NULL){ pTcpServer = pesp_conn; } else if(isserver && type==ESPCONN_UDP && pUdpServer==NULL){ pUdpServer = pesp_conn; } gL = L; // global L for net module. // if call back function is specified, call it with para userdata // luaL_checkanyfunction(L, 2); if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack lua_pushvalue(L, -2); // copy the self_ref(userdata) to the top lua_call(L, 1, 0); } return 1; }
// Lua: mqtt.Client(clientid, keepalive, user, pass) static int mqtt_socket_client( lua_State* L ) { NODE_DBG("enter mqtt_socket_client.\n"); lmqtt_userdata *mud; char tempid[20] = {0}; c_sprintf(tempid, "%s%x", "NodeMCU_", system_get_chip_id() ); NODE_DBG_(tempid); NODE_DBG("\n"); const char *clientId = tempid, *username = NULL, *password = NULL; size_t idl = c_strlen(tempid); size_t unl = 0, pwl = 0; int keepalive = 0; int stack = 1; unsigned secure = 0; int top = lua_gettop(L); // create a object mud = (lmqtt_userdata *)lua_newuserdata(L, sizeof(lmqtt_userdata)); // pre-initialize it, in case of errors mud->L = NULL; mud->self_ref = LUA_NOREF; mud->cb_connect_ref = LUA_NOREF; mud->cb_disconnect_ref = LUA_NOREF; mud->cb_message_ref = LUA_NOREF; mud->cb_suback_ref = LUA_NOREF; mud->cb_puback_ref = LUA_NOREF; mud->pesp_conn = NULL; mud->secure = 0; mud->keep_alive_tick = 0; mud->event_timeout = 0; mud->connState = MQTT_INIT; mud->connected = false; c_memset(&mud->mqttTimer, 0, sizeof(ETSTimer)); c_memset(&mud->mqtt_state, 0, sizeof(mqtt_state_t)); c_memset(&mud->connect_info, 0, sizeof(mqtt_connect_info_t)); // set its metatable luaL_getmetatable(L, "mqtt.socket"); lua_setmetatable(L, -2); mud->L = L; // L for mqtt module. if( lua_isstring(L,stack) ) // deal with the clientid string { clientId = luaL_checklstring( L, stack, &idl ); stack++; } if(lua_isnumber( L, stack )) { keepalive = luaL_checkinteger( L, stack); stack++; } if(keepalive == 0){ keepalive = MQTT_DEFAULT_KEEPALIVE; } if(lua_isstring( L, stack )){ username = luaL_checklstring( L, stack, &unl ); stack++; } if(username == NULL) unl = 0; NODE_DBG("lengh username: %d\r\n", unl); if(lua_isstring( L, stack )){ password = luaL_checklstring( L, stack, &pwl ); stack++; } if(password == NULL) pwl = 0; NODE_DBG("lengh password: %d\r\n", pwl); // TODO: check the zalloc result. mud->connect_info.client_id = (uint8_t *)c_zalloc(idl+1); mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1); mud->connect_info.password = (uint8_t *)c_zalloc(pwl + 1); if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password){ if(mud->connect_info.client_id) { c_free(mud->connect_info.client_id); mud->connect_info.client_id = NULL; } if(mud->connect_info.username) { c_free(mud->connect_info.username); mud->connect_info.username = NULL; } if(mud->connect_info.password) { c_free(mud->connect_info.password); mud->connect_info.password = NULL; } return luaL_error(L, "not enough memory"); } c_memcpy(mud->connect_info.client_id, clientId, idl); mud->connect_info.client_id[idl] = 0; c_memcpy(mud->connect_info.username, username, unl); mud->connect_info.username[unl] = 0; c_memcpy(mud->connect_info.password, password, pwl); mud->connect_info.password[pwl] = 0; NODE_DBG("MQTT: Init info: %s, %s, %s\r\n", mud->connect_info.client_id, mud->connect_info.username, mud->connect_info.password); mud->connect_info.clean_session = 1; mud->connect_info.will_qos = 0; mud->connect_info.will_retain = 0; mud->connect_info.keepalive = keepalive; mud->mqtt_state.pending_msg_q = NULL; mud->mqtt_state.auto_reconnect = 0; mud->mqtt_state.port = 1883; mud->mqtt_state.connect_info = &mud->connect_info; NODE_DBG("leave mqtt_socket_client.\n"); return 1; }
// Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) static int mqtt_socket_connect( lua_State* L ) { NODE_DBG("enter mqtt_socket_connect.\n"); lmqtt_userdata *mud = NULL; unsigned port = 1883; size_t il; ip_addr_t ipaddr; const char *domain; int stack = 1; unsigned secure = 0, auto_reconnect = 0; int top = lua_gettop(L); mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket"); luaL_argcheck(L, mud, stack, "mqtt.socket expected"); stack++; if(mud == NULL) return 0; if(mud->connected){ return luaL_error(L, "already connected"); } if(mud->pesp_conn){ //TODO: should I free tcp struct directly or ask user to call close()??? mud->pesp_conn->reverse = NULL; if(mud->pesp_conn->proto.tcp) c_free(mud->pesp_conn->proto.tcp); mud->pesp_conn->proto.tcp = NULL; c_free(mud->pesp_conn); mud->pesp_conn = NULL; } struct espconn *pesp_conn = NULL; pesp_conn = mud->pesp_conn = (struct espconn *)c_zalloc(sizeof(struct espconn)); if(!pesp_conn) return luaL_error(L, "not enough memory"); pesp_conn->proto.udp = NULL; pesp_conn->proto.tcp = (esp_tcp *)c_zalloc(sizeof(esp_tcp)); if(!pesp_conn->proto.tcp){ c_free(pesp_conn); pesp_conn = mud->pesp_conn = NULL; return luaL_error(L, "not enough memory"); } // reverse is for the callback function pesp_conn->reverse = mud; pesp_conn->type = ESPCONN_TCP; pesp_conn->state = ESPCONN_NONE; mud->connected = false; if( (stack<=top) && lua_isstring(L,stack) ) // deal with the domain string { domain = luaL_checklstring( L, stack, &il ); stack++; if (domain == NULL) { domain = "127.0.0.1"; } ipaddr.addr = ipaddr_addr(domain); c_memcpy(pesp_conn->proto.tcp->remote_ip, &ipaddr.addr, 4); NODE_DBG("TCP ip is set: "); NODE_DBG(IPSTR, IP2STR(&ipaddr.addr)); NODE_DBG("\n"); } if ( (stack<=top) && lua_isnumber(L, stack) ) { port = lua_tointeger(L, stack); stack++; NODE_DBG("TCP port is set: %d.\n", port); } pesp_conn->proto.tcp->remote_port = port; pesp_conn->proto.tcp->local_port = espconn_port(); mud->mqtt_state.port = port; if ( (stack<=top) && lua_isnumber(L, stack) ) { secure = lua_tointeger(L, stack); stack++; if ( secure != 0 && secure != 1 ){ secure = 0; // default to 0 } } else { secure = 0; // default to 0 } mud->secure = secure; // save if ( (stack<=top) && lua_isnumber(L, stack) ) { auto_reconnect = lua_tointeger(L, stack); stack++; if ( auto_reconnect != 0 && auto_reconnect != 1 ){ auto_reconnect = 0; // default to 0 } } else { auto_reconnect = 0; // default to 0 } mud->mqtt_state.auto_reconnect = auto_reconnect; // call back function when a connection is obtained, tcp only if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack if(mud->cb_connect_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref); mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); stack++; } lua_pushvalue(L, 1); // copy userdata to the top of stack if(mud->self_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref); mud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); espconn_regist_connectcb(pesp_conn, mqtt_socket_connected); espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected); os_timer_disarm(&mud->mqttTimer); os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); // timer started in socket_connect() if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) { host_ip.addr = 0; dns_reconn_count = 0; if(ESPCONN_OK == espconn_gethostbyname(pesp_conn, domain, &host_ip, socket_dns_found)){ socket_dns_found(domain, &host_ip, pesp_conn); // ip is returned in host_ip. } } else { socket_connect(pesp_conn); } NODE_DBG("leave mqtt_socket_connect.\n"); return 0; }
// Lua: mqtt:lwt( topic, message, qos, retain, function(client) ) static int mqtt_socket_lwt( lua_State* L ) { NODE_DBG("enter mqtt_socket_lwt.\n"); uint8_t stack = 1; size_t topicSize, msgSize; NODE_DBG("mqtt_socket_lwt.\n"); lmqtt_userdata *mud = NULL; const char *lwtTopic, *lwtMsg; uint8_t lwtQoS, lwtRetain; mud = (lmqtt_userdata *)luaL_checkudata( L, stack, "mqtt.socket" ); luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); if(mud == NULL) return 0; stack++; lwtTopic = luaL_checklstring( L, stack, &topicSize ); if (lwtTopic == NULL) { return luaL_error( L, "need lwt topic"); } stack++; lwtMsg = luaL_checklstring( L, stack, &msgSize ); if (lwtMsg == NULL) { return luaL_error( L, "need lwt message"); } if(mud->connect_info.will_topic){ // free the previous one if there is any c_free(mud->connect_info.will_topic); mud->connect_info.will_topic = NULL; } if(mud->connect_info.will_message){ c_free(mud->connect_info.will_message); mud->connect_info.will_message = NULL; } mud->connect_info.will_topic = (uint8_t*) c_zalloc( topicSize + 1 ); mud->connect_info.will_message = (uint8_t*) c_zalloc( msgSize + 1 ); if(!mud->connect_info.will_topic || !mud->connect_info.will_message){ if(mud->connect_info.will_topic){ c_free(mud->connect_info.will_topic); mud->connect_info.will_topic = NULL; } if(mud->connect_info.will_message){ c_free(mud->connect_info.will_message); mud->connect_info.will_message = NULL; } return luaL_error( L, "not enough memory"); } c_memcpy(mud->connect_info.will_topic, lwtTopic, topicSize); mud->connect_info.will_topic[topicSize] = 0; c_memcpy(mud->connect_info.will_message, lwtMsg, msgSize); mud->connect_info.will_message[msgSize] = 0; if ( lua_isnumber(L, stack) ) { mud->connect_info.will_qos = lua_tointeger(L, stack); stack++; } if ( lua_isnumber(L, stack) ) { mud->connect_info.will_retain = lua_tointeger(L, stack); stack++; } NODE_DBG("mqtt_socket_lwt: topic: %s, message: %s, qos: %d, retain: %d\n", mud->connect_info.will_topic, mud->connect_info.will_message, mud->connect_info.will_qos, mud->connect_info.will_retain); NODE_DBG("leave mqtt_socket_lwt.\n"); return 0; }