void ICACHE_FLASH_ATTR mqtt_send_keepalive(MQTT_Client *client) { INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); err_t result = ESPCONN_OK; if (client->security) { #ifdef MQTT_SSL_ENABLE result = espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); #else INFO("TCP: Do not support SSL\r\n"); #endif } else { result = espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } client->mqtt_state.outbound_message = NULL; if(ESPCONN_OK == result) { client->keepAliveTick = 0; client->connState = MQTT_DATA; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } else { client->connState = TCP_RECONNECT_DISCONNECTING; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } }
void ICACHE_FLASH_ATTR mqtt_timer(void *arg) { static bool on = true; MQTT_Client* client = (MQTT_Client*)arg; mqtt_message_t* outbound_message; #if 0 INFO("\r\nLED: %s\r\n", on ? "on" : "off"); ledOn(on); on = !on; #endif if(client->connState == MQTT_DATA){ client->keepAliveTick ++; if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ //spam INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); if(QUEUE_Puts(&client->msgQueue, outbound_message->data, outbound_message->length) == -1){ //spam INFO("MQTT: Exceed the amount of queues\r\n"); } client->keepAliveTick = 0; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } else if(client->connState == TCP_RECONNECT_REQ){ client->reconnectTick ++; if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { //spam INFO("MQTT: Recon timeout\r\n"); client->reconnectTick = 0; client->connState = TCP_RECONNECT; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } }
void ICACHE_FLASH_ATTR mqtt_timer(void *arg) { MQTT_Client* client = (MQTT_Client*)arg; if(client->connState == MQTT_DATA){ client->keepAliveTick ++; if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ INFO("MQTT: Exceed the amount of queues\r\n"); } client->keepAliveTick = 0; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } else if(client->connState == TCP_RECONNECT_REQ){ client->reconnectTick ++; if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { client->reconnectTick = 0; client->connState = TCP_RECONNECT; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } if(client->sendTimeout > 0) client->sendTimeout --; }
void ICACHE_FLASH_ATTR mqtt_timer(void *arg) { MQTT_Client* client = (MQTT_Client*)arg; INFO("%s, %d\n", __func__, client->connState); if(client->connState == MQTT_DATA){ client->keepAliveTick ++; if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ // check heart beat. if(client->heart_beat_flag == 0) { client->connState = TCP_RECONNECT_REQ; } INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); if(client->security){ espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } else{ espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } client->mqtt_state.outbound_message = NULL; client->keepAliveTick = 0; client->heart_beat_flag = 0; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } else if(client->connState == TCP_RECONNECT_REQ){ INFO("%s, client->reconnectTick:%d\n", __func__, client->reconnectTick); client->reconnectTick ++; if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { client->reconnectTick = 0; client->connState = TCP_RECONNECT; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } }else if(client->connState == TCP_CONNECTING){ client->connectTick ++; if(client->connectTick > MQTT_CONNECT_TIMEOUT) { client->connState = TCP_CONNECTING_ERROR; client->connectTick = 0; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); } } if(client->sendTimeout > 0) client->sendTimeout --; }
void FUNCTION_ATTRIBUTE mqtt_timer(void *arg) { MQTT_Client* client = (MQTT_Client*)arg; struct data_buf buffer; INFO("%s, %d\n", __func__, client->connState); if(client->connState == MQTT_DATA){ client->keepAliveTick ++; if(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){ // check heart beat. if(client->heart_beat_flag == 0) { client->connState = TCP_RECONNECT_REQ; } INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; buffer.length = client->mqtt_state.outbound_message->length; buffer.data = client->mqtt_state.outbound_message->data; INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); net_tcp_send(client->pCon, buffer, client->sendTimeout); client->mqtt_state.outbound_message = NULL; client->keepAliveTick = 0; client->heart_beat_flag = 0; MQTT_Task(client); } } else if(client->connState == TCP_RECONNECT_REQ){ INFO("%s, client->reconnectTick:%d\n", __func__, client->reconnectTick); client->reconnectTick ++; if(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { client->reconnectTick = 0; client->connState = TCP_RECONNECT; MQTT_Task(client); } }else if(client->connState == TCP_CONNECTING){ INFO("%s, client->connectTick:%d\n", __func__, client->connectTick); client->connectTick ++; if(client->connectTick > MQTT_CONNECT_TIMEOUT) { client->connState = TCP_CONNECTING_ERROR; client->connectTick = 0; MQTT_Task(client); } } if(client->sendTimeout > 0) client->sendTimeout --; }
/* * @brief: Timer function to handle timeouts */ static void ICACHE_FLASH_ATTR mqtt_timer(void* arg) { MQTT_Client* client = (MQTT_Client*)arg; //DBG_MQTT("MQTT: timer CB\n"); switch (client->connState) { default: break; case MQTT_CONNECTED: // first check whether we're timing out for an ACK if (client->pending_buffer != NULL && --client->timeoutTick == 0) { // looks like we're not getting a response in time, abort the connection mqtt_doAbort(client); client->timeoutTick = 0; // trick to make reconnect happen in 1 second return; } // check whether our last keep-alive timed out if (client->keepAliveAckTick > 0 && --client->keepAliveAckTick == 0) { os_printf("\nMQTT ERROR: Keep-alive timed out\n"); mqtt_doAbort(client); return; } // check whether we need to send a keep-alive message if (client->keepAliveTick > 0 && --client->keepAliveTick == 0) { // timeout: we need to send a ping message //DBG_MQTT("MQTT: Send keepalive\n"); mqtt_msg_pingreq(&client->mqtt_connection); PktBuf *buf = PktBuf_New(client->mqtt_connection.message.length); os_memcpy(buf->data, client->mqtt_connection.message.data, client->mqtt_connection.message.length); buf->filled = client->mqtt_connection.message.length; client->msgQueue = PktBuf_Unshift(client->msgQueue, buf); mqtt_send_message(client); client->keepAliveTick = client->connect_info.keepalive; client->keepAliveAckTick = client->sendTimeout; } break; case TCP_RECONNECT_REQ: if (client->timeoutTick == 0 || --client->timeoutTick == 0) { // it's time to reconnect! start by re-enqueueing anything pending if (client->pending_buffer != NULL) { client->msgQueue = PktBuf_Unshift(client->msgQueue, client->pending_buffer); client->pending_buffer = NULL; } client->connect_info.clean_session = 0; // ask server to keep state MQTT_Connect(client); } } }
/** * @brief MQTT ping function. * @param client: MQTT_Client reference * @retval TRUE if success queue */ BOOL ICACHE_FLASH_ATTR MQTT_Ping(MQTT_Client *client) { uint8_t dataBuffer[MQTT_BUF_SIZE]; uint16_t dataLen; client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); if(client->mqtt_state.outbound_message->length == 0){ INFO("MQTT: Queuing publish failed\r\n"); return FALSE; } INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); while(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ INFO("MQTT: Queue full\r\n"); if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { INFO("MQTT: Serious buffer error\r\n"); return FALSE; } } system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); return TRUE; }
static PT_THREAD(handle_mqtt_connection(mqtt_state_t* state)) { static struct etimer keepalive_timer; uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; PSOCK_BEGIN(&state->ps); // Initialise and send CONNECT message mqtt_msg_init(&state->mqtt_connection, state->out_buffer, state->out_buffer_length); state->outbound_message = mqtt_msg_connect(&state->mqtt_connection, state->connect_info); PSOCK_SEND(&state->ps, state->outbound_message->data, state->outbound_message->length); state->outbound_message = NULL; // Wait for CONACK message PSOCK_READBUF_LEN(&state->ps, 2); if(mqtt_get_type(state->in_buffer) != MQTT_MSG_TYPE_CONNACK) PSOCK_CLOSE_EXIT(&state->ps); // Tell the client we're connected mqtt_flags |= MQTT_FLAG_CONNECTED; complete_pending(state, MQTT_EVENT_TYPE_CONNECTED); // Setup the keep alive timer and enter main message processing loop etimer_set(&keepalive_timer, CLOCK_SECOND * state->connect_info->keepalive); while(1) { // Wait for something to happen: // new incoming data, // new outgoing data, // keep alive timer expired PSOCK_WAIT_UNTIL(&state->ps, PSOCK_NEWDATA(&state->ps) || state->outbound_message != NULL || etimer_expired(&keepalive_timer)); // If there's a new message waiting to go out, then send it if(state->outbound_message != NULL) { PSOCK_SEND(&state->ps, state->outbound_message->data, state->outbound_message->length); state->outbound_message = NULL; // If it was a PUBLISH message with QoS-0 then tell the client it's done if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == 0) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); // Reset the keepalive timer as we've just sent some data etimer_restart(&keepalive_timer); continue; } // If the keep-alive timer expired then prepare a ping for sending // and reset the timer if(etimer_expired(&keepalive_timer)) { state->outbound_message = mqtt_msg_pingreq(&state->mqtt_connection); etimer_reset(&keepalive_timer); continue; } // If we get here we must have woken for new incoming data, // read and process it. PSOCK_READBUF_LEN(&state->ps, 2); state->message_length_read = PSOCK_DATALEN(&state->ps); state->message_length = mqtt_get_total_length(state->in_buffer, state->message_length_read); msg_type = mqtt_get_type(state->in_buffer); msg_qos = mqtt_get_qos(state->in_buffer); msg_id = mqtt_get_id(state->in_buffer, state->in_buffer_length); switch(msg_type) { case MQTT_MSG_TYPE_SUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_SUBSCRIBED); break; case MQTT_MSG_TYPE_UNSUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_UNSUBSCRIBED); break; case MQTT_MSG_TYPE_PUBLISH: if(msg_qos == 1) state->outbound_message = mqtt_msg_puback(&state->mqtt_connection, msg_id); else if(msg_qos == 2) state->outbound_message = mqtt_msg_pubrec(&state->mqtt_connection, msg_id); deliver_publish(state, state->in_buffer, state->message_length_read); break; case MQTT_MSG_TYPE_PUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); break; case MQTT_MSG_TYPE_PUBREC: state->outbound_message = mqtt_msg_pubrel(&state->mqtt_connection, msg_id); break; case MQTT_MSG_TYPE_PUBREL: state->outbound_message = mqtt_msg_pubcomp(&state->mqtt_connection, msg_id); break; case MQTT_MSG_TYPE_PUBCOMP: if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); break; case MQTT_MSG_TYPE_PINGREQ: state->outbound_message = mqtt_msg_pingresp(&state->mqtt_connection); break; case MQTT_MSG_TYPE_PINGRESP: // Ignore break; } // NOTE: this is done down here and not in the switch case above // because the PSOCK_READBUF_LEN() won't work inside a switch // statement due to the way protothreads resume. if(msg_type == MQTT_MSG_TYPE_PUBLISH) { uint16_t len; // adjust message_length and message_length_read so that // they only account for the publish data and not the rest of the // message, this is done so that the offset passed with the // continuation event is the offset within the publish data and // not the offset within the message as a whole. len = state->message_length_read; mqtt_get_publish_data(state->in_buffer, &len); len = state->message_length_read - len; state->message_length -= len; state->message_length_read -= len; while(state->message_length_read < state->message_length) { PSOCK_READBUF_LEN(&state->ps, state->message_length - state->message_length_read); deliver_publish_continuation(state, state->message_length_read, state->in_buffer, PSOCK_DATALEN(&state->ps)); state->message_length_read += PSOCK_DATALEN(&state->ps); } } } PSOCK_END(&state->ps); }
void mqtt_socket_timer(void *arg) { NODE_DBG("enter mqtt_socket_timer.\n"); lmqtt_userdata *mud = (lmqtt_userdata*) arg; if(mud == NULL) return; if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); os_timer_disarm(&mud->mqttTimer); return; } NODE_DBG("timer, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); if(mud->event_timeout > 0){ NODE_DBG("event_timeout: %d.\n", mud->event_timeout); mud->event_timeout --; if(mud->event_timeout > 0){ return; } else { NODE_DBG("event timeout. \n"); if(mud->connState == MQTT_DATA) msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); // should remove the head of the queue and re-send with DUP = 1 // Not implemented yet. } } if(mud->connState == MQTT_INIT){ // socket connect time out. NODE_DBG("Can not connect to broker.\n"); // Never goes here. } else if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT send time out. NODE_DBG("sSend MQTT_CONNECT failed.\n"); mud->connState = MQTT_INIT; if(mud->secure) espconn_secure_disconnect(mud->pesp_conn); else espconn_disconnect(mud->pesp_conn); mud->keep_alive_tick = 0; // not need count anymore } else if(mud->connState == MQTT_CONNECT_SENT){ // wait for CONACK time out. NODE_DBG("MQTT_CONNECT failed.\n"); } else if(mud->connState == MQTT_DATA){ msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q)); if(pending_msg){ mud->event_timeout = MQTT_SEND_TIMEOUT; if(mud->secure) espconn_secure_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); else espconn_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); mud->keep_alive_tick = 0; NODE_DBG("id: %d - qos: %d, length: %d\n", pending_msg->msg_id, pending_msg->publish_qos, pending_msg->msg.length); } else { // no queued event. mud->keep_alive_tick ++; if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ mud->event_timeout = MQTT_SEND_TIMEOUT; uint8_t temp_buffer[MQTT_BUF_SIZE]; mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg, 0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) ); // only one message in queue, send immediately. if(mud->secure) espconn_secure_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); else espconn_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); mud->keep_alive_tick = 0; } } } NODE_DBG("leave mqtt_socket_timer.\n"); }