Exemple #1
0
/******************************************************************************
 * FunctionName : espconn_tcp_delete
 * Description  : delete the server: delete a listening PCB and free it
 * Parameters   : pdeletecon -- the espconn used to delete a server
 * Returns      : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon)
{
	err_t err;
	remot_info *pinfo = NULL;
	espconn_msg *pdelete_msg = NULL;
	struct tcp_pcb *pcb = NULL;

	if (pdeletecon == NULL)
		return ESPCONN_ARG;

	espconn_get_connection_info(pdeletecon, &pinfo , 0);
	if (pdeletecon->link_cnt != 0)
		return ESPCONN_INPROGRESS;
	else {
		os_printf("espconn_tcp_delete %p\n",pdeletecon);
		pdelete_msg = pserver_list;
		while (pdelete_msg != NULL){
			if (pdelete_msg->pespconn == pdeletecon){
				/*remove the node from the client's active connection list*/
				espconn_list_delete(&pserver_list, pdelete_msg);
				pcb = pdelete_msg->preverse;
				os_printf("espconn_tcp_delete %d\n",pcb->state);
				err = tcp_close(pcb);
				os_free(pdelete_msg);
				pdelete_msg = NULL;
				break;
			}
			pdelete_msg = pdelete_msg->pnext;
		}
		if (err == ERR_OK)
			return err;
		else
			return ESPCONN_ARG;
	}
}
static void ICACHE_FLASH_ATTR
incoming_connection_callback(void *arg)
{
    struct espconn *pconnection = arg;
    remot_info *premot = NULL;
    uint8_t idx;
    int8_t value;

    espconn_regist_recvcb(pconnection, tcpserver_recv_callback);
    espconn_regist_reconcb(pconnection, tcpserver_reconnect_callback);
    espconn_regist_disconcb(pconnection, tcpserver_disconnect_callback);

    value = espconn_get_connection_info(&tcp_server, &premot, 0);
    os_printf("Incoming TCP connection. link_cnt=%d. Get connnection info result:[%d]\r\n", 
            tcp_server.link_cnt, value);

    if (value == ESPCONN_OK)
    {
        //char *testString = "Hello! This is a TCP server on ESP8266.\r\n";
        for (idx = 0; idx < tcp_server.link_cnt; idx++)
        {
            os_printf("TCP client %d: %d.%d.%d.%d:%d\r\n",
                    idx + 1,
                    premot[idx].remote_ip[0],
                    premot[idx].remote_ip[1],
                    premot[idx].remote_ip[2],
                    premot[idx].remote_ip[3],
                    premot[idx].remote_port);
        }
    }

    os_printf("\r\n");
}
Exemple #3
0
/******************************************************************************
 * FunctionName : espconn_tcp_accept
 * Description  : A new incoming connection has been accepted.
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pcb -- The connection pcb which is accepted
 *                err -- An unused error code, always ERR_OK currently
 * Returns      : acception result
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
    struct espconn *espconn = arg;
    espconn_msg *paccept = NULL;
    remot_info *pinfo = NULL;
    LWIP_UNUSED_ARG(err);

    if(system_get_free_heap_size() < 8192) return ERR_MEM; // added PV`

    paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
    tcp_arg(pcb, paccept);
	tcp_err(pcb, esponn_server_err);
	if (paccept == NULL)
		return ERR_MEM;
	/*insert the node to the active connection list*/
	espconn_list_creat(&plink_active, paccept);

    paccept->preverse = espconn;
	paccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn));
	if (paccept->pespconn == NULL)
		return ERR_MEM;
	paccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
	if (paccept->pespconn->proto.tcp == NULL)
		return ERR_MEM;

	//paccept->pcommon.timeout = 0x0a;
	//link_timer = 0x0a;

	paccept->pcommon.pcb = pcb;

	paccept->pcommon.remote_port = pcb->remote_port;
	paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip);

	os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);
	espconn->proto.tcp->remote_port = pcb->remote_port;
	espconn->state = ESPCONN_CONNECT;
	espconn_copy_partial(paccept->pespconn, espconn);
	espconn_get_connection_info(espconn, &pinfo , 0);
	espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt);
	if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn) + 1)
		return ERR_ISCONN;

	tcp_sent(pcb, espconn_server_sent);
	tcp_recv(pcb, espconn_server_recv);
	tcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */

	if (paccept->pespconn->proto.tcp->connect_callback != NULL) {
		paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn);
	}

    return ERR_OK;
}
static void ICACHE_FLASH_ATTR
tcpserver_recv_callback(void *arg, char *pdata, uint16_t length)
{
    if(os_strncmp(OTA_UPGRADE_COMMAND, pdata, length) == 0)
    {
        remot_info *phost_info = NULL;

        os_printf("Upgrade command received.\r\n");
        espconn_get_connection_info(&tcp_server, &phost_info, 0);
        ota_upgrade(phost_info);
    }
}
Exemple #5
0
static void ICACHE_FLASH_ATTR udp_received(void *arg, char *data, unsigned short len)
{
    struct espconn *udpconn= (struct espconn*)arg;
    if (len > 5 && strncmp(data, "HAP", 3) == 0)
    {
        const char* hapServer = &data[5];
        if (strcmp(settings.serverName, hapServer) != 0)
            return;

        remot_info *info = NULL;
        espconn_get_connection_info(udpconn, &info, 0);

        uint16_t port = (data[3] << 8) | data[4];
        uint32_t address = *(uint32_t*)info->remote_ip;

        if (port == hapPort && address == hapAddress)
            return;

        hapAddress = address;
        hapPort = port;

        static bool inited = false;

        DEBUG_PRINT("[HAP]Discover from "IPSTR":%d\n", IP2STR(&address), port);

        if (inited)
        {
            MQTT_Disconnect(&mqttClient);
            DEBUG_PRINT("[HAP]Disconnect MQTT\n");
        }

        char aux[20];
        os_sprintf(aux, IPSTR, IP2STR(&address));
        MQTT_InitConnection(&mqttClient, aux, hapPort);

        os_sprintf(aux, "client_%d", system_get_chip_id());
        MQTT_InitClient(&mqttClient, aux, settings.mqttUser, settings.mqttPassword, MQTT_KEEPALIVE, 1);
        MQTT_OnConnected(&mqttClient, mqttConnectedCb);
        MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
        MQTT_OnPublished(&mqttClient, mqttPublishedCb);
        MQTT_OnData(&mqttClient, mqttDataCb);
        MQTT_Connect(&mqttClient);

        inited = true;
    }
}
LOCAL void ICACHE_FLASH_ATTR
airkiss_wifilan_recv_callbk(void *arg, char *pdata, unsigned short len)
{
	uint16 i;
	remot_info* pcon_info = NULL;
		
	airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf);
	airkiss_lan_ret_t packret;
	
	switch (ret){
	case AIRKISS_LAN_SSDP_REQ:
		espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0);
		os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1],
			                                    pcon_info->remote_ip[2],pcon_info->remote_ip[3]);
		os_printf("remote port: %d \r\n",pcon_info->remote_port);
      
        pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port;
		memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4);
		ssdp_udp.remote_port = DEFAULT_LAN_PORT;
		
		lan_buf_len = sizeof(lan_buf);
		packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD,
			DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);
		
		if (packret != AIRKISS_LAN_PAKE_READY) {
			os_printf("Pack lan packet error!");
			return;
		}

		os_printf("\r\n\r\n");
		for (i=0; i<lan_buf_len; i++)
			os_printf("%c",lan_buf[i]);
		os_printf("\r\n\r\n");
		
		packret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
		if (packret != 0) {
			os_printf("LAN UDP Send err!");
		}
		
		break;
	default:
		os_printf("Pack is not ssdq req!%d\r\n",ret);
		break;
	}
}
Exemple #7
0
/******************************************************************************
 * FunctionName : espconn_tcp_accept
 * Description  : A new incoming connection has been accepted.
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pcb -- The connection pcb which is accepted
 *                err -- An unused error code, always ERR_OK currently
 * Returns      : acception result
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
    struct espconn *espconn = arg;
    espconn_msg *paccept = NULL;
    remot_info *pinfo = NULL;
    LWIP_UNUSED_ARG(err);

    if (!espconn || !espconn->proto.tcp) {
    	return ERR_ARG;
    }

    tcp_arg(pcb, paccept);
    tcp_err(pcb, esponn_server_err);
    /*Ensure the active connection is less than the count of active connections on the server*/
    espconn_get_connection_info(espconn, &pinfo , 0);
	espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt);
	if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn))
		return ERR_ISCONN;

	/*Creates a new active connect control message*/
    paccept = (espconn_msg *)malloc(sizeof(espconn_msg));
	memset(paccept, 0, sizeof(espconn_msg));
    tcp_arg(pcb, paccept);

	if (paccept == NULL)
		return ERR_MEM;
	/*Insert the node to the active connection list*/
	espconn_list_creat(&plink_active, paccept);

    paccept->preverse = espconn;
	paccept->pespconn = (struct espconn *)malloc(sizeof(struct espconn));
	if (paccept->pespconn == NULL)
		return ERR_MEM;
	paccept->pespconn->proto.tcp = (esp_tcp *)malloc(sizeof(esp_tcp));
	if (paccept->pespconn->proto.tcp == NULL)
		return ERR_MEM;

	/*Reserve the remote information for current active connection*/
	paccept->pcommon.pcb = pcb;

	paccept->pcommon.remote_port = pcb->remote_port;
	paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip.u_addr.ip4);
	paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip.u_addr.ip4);
	paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip.u_addr.ip4);
	paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip.u_addr.ip4);
	paccept->pcommon.write_flag = true;

	memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);
	espconn->proto.tcp->remote_port = pcb->remote_port;
	espconn->state = ESPCONN_CONNECT;
	espconn_copy_partial(paccept->pespconn, espconn);

	/*Set the specify function that should be called
	 * when TCP data has been successfully delivered,
	 * when active connection receives data,
	 * or periodically from active connection*/
	tcp_sent(pcb, espconn_server_sent);
	tcp_recv(pcb, espconn_server_recv);
	tcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */
	/*Disable Nagle algorithm default*/
	tcp_nagle_disable(pcb);
	/*Default set the total number of espconn_buf on the unsent lists for one*/
	espconn_tcp_set_buf_count(paccept->pespconn, 1);

	if (paccept->pespconn->proto.tcp->connect_callback != NULL) {
		paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn);
	}

	/*Enable keep alive option*/
	if (espconn_keepalive_disabled(paccept))
		espconn_keepalive_enable(pcb);

    return ERR_OK;
}
/******************************************************************************
 * FunctionName : user_devicefind_recv
 * Description  : Processing the received data from the host
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_devicefind_recv(void *arg, char *pusrdata, unsigned short length)
{
    char DeviceBuffer[40] = {0};
    char Device_mac_buffer[60] = {0};
    char hwaddr[6];

    struct ip_info ipconfig;

    if (wifi_get_opmode() != STATION_MODE) {
        wifi_get_ip_info(SOFTAP_IF, &ipconfig);
        wifi_get_macaddr(SOFTAP_IF, hwaddr);

        if (!ip_addr_netcmp((struct ip_addr *)ptrespconn.proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {
            wifi_get_ip_info(STATION_IF, &ipconfig);
            wifi_get_macaddr(STATION_IF, hwaddr);
        }
    } else {
        wifi_get_ip_info(STATION_IF, &ipconfig);
        wifi_get_macaddr(STATION_IF, hwaddr);
    }

    if (pusrdata == NULL) {
        return;
    }

    if (length == os_strlen(device_find_request) &&
        os_strncmp(pusrdata, device_find_request, os_strlen(device_find_request)) == 0) {
        length = os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok,
                   MAC2STR(hwaddr), IP2STR(&ipconfig.ip));

        DF_DBG("%s\n", DeviceBuffer);
        //length = os_strlen(DeviceBuffer);


        //==================================
        //This is add in sdk lib v1.4.0
        DF_DBG("--------DEBUG IN DEV----------\r\n");
        remote_info* pcon_info = NULL;
        DF_DBG("link num: %d \r\n",ptrespconn.link_cnt);
        espconn_get_connection_info(&ptrespconn, &pcon_info, 0);
        DF_DBG("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1],
                                                pcon_info->remote_ip[2],pcon_info->remote_ip[3]);
        DF_DBG("remote port: %d \r\n",pcon_info->remote_port);
        //=================================
        ptrespconn.proto.udp->remote_port = pcon_info->remote_port;
        os_memcpy(ptrespconn.proto.udp->remote_ip,pcon_info->remote_ip,4);
        espconn_sendto(&ptrespconn, DeviceBuffer, length);
    } else if (length == (os_strlen(device_find_request) + 18)) {
        os_sprintf(Device_mac_buffer, "%s " MACSTR , device_find_request, MAC2STR(hwaddr));
        DF_DBG("%s", Device_mac_buffer);

        if (os_strncmp(Device_mac_buffer, pusrdata, os_strlen(device_find_request) + 18) == 0) {
            length = os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok,MAC2STR(hwaddr), IP2STR(&ipconfig.ip));
            DF_DBG("%s\n", DeviceBuffer);
            espconn_sendto(&ptrespconn, DeviceBuffer, length);
        } else {
            return;
        }
    }
}
Exemple #9
0
static void ICACHE_FLASH_ATTR dnsQueryReceived(void *arg, char *data, unsigned short length)
{
   // parse incoming query domain
   char domain[30];
   char *writePos=domain;
   memset(domain,0,30);

   int offSet=12;
   int len=data[offSet];
   while(len!=0 && offSet<length)
   {
      offSet++;
      memcpy(writePos,data+offSet,len);
      writePos+=len; //advance
      offSet+=len;
      len=data[offSet];

      if(len!=0) { *writePos='.'; writePos++; }
   }

   DNS_DBG("DNS Query Received: %s",domain);
   if(!isKnownDNS(domain))
   return;

   struct espconn *conn=arg;

   remot_info *premot = NULL;

   if (espconn_get_connection_info(conn,&premot,0) == ESPCONN_OK)
   {
      os_memcpy(conn->proto.udp->remote_ip, premot->remote_ip, 4);
      conn->proto.udp->remote_port = premot->remote_port;

      uint8_t *ip1 = conn->proto.udp->remote_ip;
      NODE_DBG("UDP:\nremote_ip: %d.%d.%d.%d remote_port: %d\n",ip4_addr1_16(ip1),ip4_addr2_16(ip1), ip4_addr3_16(ip1), ip4_addr4_16(ip1), premot->remote_port);
   }
   else
      { NODE_ERR("UDP: connection_info == NULL?\n"); }

   //build response
   char response[100] = {data[0], data[1],
                        0b10000100 | (0b00000001 & data[2]), //response, authorative answer, not truncated, copy the recursion bit
                        0b00000000, //no recursion available, no errors
                        data[4], data[5], //Question count
                        data[4], data[5], //answer count
                        0x00, 0x00,       //NS record count
                        0x00, 0x00};      //Resource record count

   int idx = 12;
   memcpy(response+12, data+12, length-12); //Copy the rest of the query section
   idx += length-12;

   //Set a pointer to the domain name in the question section
   response[idx] = 0xC0;
   response[idx+1] = 0x0C;

   //Set the type to "Host Address"
   response[idx+2] = 0x00;
   response[idx+3] = 0x01;

   //Set the response class to IN
   response[idx+4] = 0x00;
   response[idx+5] = 0x01;

   //A 32 bit integer specifying TTL in seconds, 0 means no caching
   response[idx+6] = 0x00;
   response[idx+7] = 0x00;
   response[idx+8] = 0x00;
   response[idx+9] = 0x00;

   //RDATA length
   response[idx+10] = 0x00;
   response[idx+11] = 0x04; //4 byte IP address

   //The IP address
   response[idx + 12] = 192;
   response[idx + 13] = 168;
   response[idx + 14] = 4;
   response[idx + 15] = 1;

   int ret = espconn_send(conn, (uint8_t*)response, idx+16);

   uint8_t *ip = conn->proto.udp->local_ip;
   NODE_DBG("local_ip: %d.%d.%d.%d local_port: %d\n",ip4_addr1_16(ip),ip4_addr2_16(ip), ip4_addr3_16(ip), ip4_addr4_16(ip),conn->proto.udp->local_port);
   NODE_DBG("DNS reply sent\n");
}
/******************************************************************************
 * FunctionName : user_devicefind_recv
 * Description  : Processing the received data from the host
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pusrdata -- The received data (or NULL when the connection has been closed!)
 *                length -- The length of received data
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
user_devicefind_recv(void *arg, char *pusrdata, unsigned short length)
{
	os_printf("1-----------\n");
    char DeviceBuffer[40] = {0};
    char Device_mac_buffer[60] = {0};
    char hwaddr[6];
    remot_info *premot = NULL;
    struct ip_info ipconfig;

    if (wifi_get_opmode() != STATION_MODE) {
        wifi_get_ip_info(SOFTAP_IF, &ipconfig);
        wifi_get_macaddr(SOFTAP_IF, hwaddr);

        if (!ip_addr_netcmp((struct ip_addr *)ptrespconn.proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {
            wifi_get_ip_info(STATION_IF, &ipconfig);
            wifi_get_macaddr(STATION_IF, hwaddr);
        }
    } else {
        wifi_get_ip_info(STATION_IF, &ipconfig);
        wifi_get_macaddr(STATION_IF, hwaddr);
    }

    if (pusrdata == NULL) {
        return;
    }

    if (length == os_strlen(device_find_request) &&
            os_strncmp(pusrdata, device_find_request, os_strlen(device_find_request)) == 0) {
        os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok,
                   MAC2STR(hwaddr), IP2STR(&ipconfig.ip));

        os_printf("%s\n", DeviceBuffer);
        length = os_strlen(DeviceBuffer);
        if (espconn_get_connection_info(&ptrespconn, &premot, 0) != ESPCONN_OK)
        	return;
        os_memcpy(ptrespconn.proto.udp->remote_ip, premot->remote_ip, 4);
        ptrespconn.proto.udp->remote_port = premot->remote_port;
        espconn_sent(&ptrespconn, DeviceBuffer, length);
    } else if (length == (os_strlen(device_find_request) + 18)) {
        os_sprintf(Device_mac_buffer, "%s " MACSTR , device_find_request, MAC2STR(hwaddr));
        os_printf("%s", Device_mac_buffer);

        if (os_strncmp(Device_mac_buffer, pusrdata, os_strlen(device_find_request) + 18) == 0) {
            //os_printf("%s\n", Device_mac_buffer);
            length = os_strlen(DeviceBuffer);
            os_sprintf(DeviceBuffer, "%s" MACSTR " " IPSTR, device_find_response_ok,
                       MAC2STR(hwaddr), IP2STR(&ipconfig.ip));

            os_printf("%s\n", DeviceBuffer);
            length = os_strlen(DeviceBuffer);
			if (espconn_get_connection_info(&ptrespconn, &premot, 0) != ESPCONN_OK)
				return;
			os_memcpy(ptrespconn.proto.udp->remote_ip, premot->remote_ip, 4);
			ptrespconn.proto.udp->remote_port = premot->remote_port;
            espconn_sent(&ptrespconn, DeviceBuffer, length);
        } else {
            return;
        }
    }
}
Exemple #11
0
// Lua: server/socket:send( string, function(sent) )
static int net_send( lua_State* L, const char* mt )
{
  // NODE_DBG("net_send is called.\n");
  bool isserver = false;
  struct espconn *pesp_conn = NULL;
  lnet_userdata *nud;
  size_t l;
  
  nud = (lnet_userdata *)luaL_checkudata(L, 1, mt);
  luaL_argcheck(L, nud, 1, "Server/Socket expected");
  if(nud==NULL){
  	NODE_DBG("userdata is nil.\n");
  	return 0;
  }

  if(nud->pesp_conn == NULL){
    NODE_DBG("nud->pesp_conn is NULL.\n");
    return 0;
  }
  pesp_conn = nud->pesp_conn;

  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_send.\n");
    return 0;
  }

  if(isserver && nud->pesp_conn->type == ESPCONN_TCP){
    return luaL_error( L, "tcp server send not supported" );
  }

#if 0
  char temp[20] = {0};
  c_sprintf(temp, IPSTR, IP2STR( &(pesp_conn->proto.tcp->remote_ip) ) );
  NODE_DBG("remote ");
  NODE_DBG(temp);
  NODE_DBG(":");
  NODE_DBG("%d",pesp_conn->proto.tcp->remote_port);
  NODE_DBG(" sending data.\n");
#endif

  const char *payload = luaL_checklstring( L, 2, &l );
  if (l>1460 || payload == NULL)
    return luaL_error( L, "need <1460 payload" );

  if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){
    lua_pushvalue(L, 3);  // copy argument (func) to the top of stack
    if(nud->cb_send_ref != LUA_NOREF)
      luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_send_ref);
    nud->cb_send_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  }
  // SDK 1.4.0 changed behaviour, for UDP server need to look up remote ip/port
  if (isserver && pesp_conn->type == ESPCONN_UDP)
  {
    remot_info *pr = 0;
    if (espconn_get_connection_info (pesp_conn, &pr, 0) != ESPCONN_OK)
      return luaL_error (L, "remote ip/port unavailable");
    pesp_conn->proto.udp->remote_port = pr->remote_port;
    os_memmove (pesp_conn->proto.udp->remote_ip, pr->remote_ip, 4);
    // The remot_info apparently should *not* be os_free()d, fyi
  }
#ifdef CLIENT_SSL_ENABLE
  if(nud->secure)
    espconn_secure_sent(pesp_conn, (unsigned char *)payload, l);
  else
#endif
    espconn_sent(pesp_conn, (unsigned char *)payload, l);

  return 0;  
}