/** * ESP8266 callback function that is invoked when new data has arrived over * the TCP/IP connection. */ static void esp8266_callback_recvCB( void *arg, //!< A pointer to a `struct espconn`. char *pData, //!< A pointer to data received over the socket. unsigned short len //!< The length of the data. ) { struct espconn *pEspconn = (struct espconn *)arg; struct socketData *pSocketData = (struct socketData *)pEspconn->reverse; if (pSocketData == NULL) return; // we closed this socket //if (pEspconn != pSocketData->pEspconn) DBG("%s: pEspconn changed in recvCB ***\n", DBG_LIB); assert(pSocketData->state != SOCKET_STATE_UNUSED); //DBG("%s: socket %d recv %d\n", DBG_LIB, pSocketData->socketId, len); //DBG("%s: recv data: %p\n", DBG_LIB, pData); // if this is a dead connection then just ignore the callback if (pSocketData->state == SOCKET_STATE_ABORTING || pSocketData->state == SOCKET_STATE_TO_ABORT || pSocketData->state == SOCKET_STATE_CLOSED || pSocketData->state == SOCKET_STATE_DISCONNECTING) { return; } // Allocate a buffer and add to the receive queue PktBuf *buf = PktBuf_New(len); if (!buf) { // handle out of memory condition DBG("%s: Out of memory allocating %d for recv\n", DBG_LIB, len); // at this point we're gonna deallocate all receive buffers as a panic measure while (pSocketData->rxBufQ != NULL) pSocketData->rxBufQ = PktBuf_ShiftFree(pSocketData->rxBufQ); // save the error setSocketInError(pSocketData, ESPCONN_MEM); // now reset the connection //espconn_abort(pEspconn); // can't do this: espconn crashes! pSocketData->state = SOCKET_STATE_TO_ABORT; // some function called from socket lib will abort //DBG("%s: ret from recvCB\n", DBG_LIB); return; } // if this is the second buffer then stop the flood! if (pSocketData->rxBufQ != NULL) espconn_recv_hold(pEspconn); // got buffer, fill it os_memcpy(buf->data, pData, len); buf->filled = len; pSocketData->rxBufQ = PktBuf_Push(pSocketData->rxBufQ, buf); }
/** * Release the socket and return it to the free pool. * The connection (espconn) must be closed and deallocated before calling releaseSocket. */ static void releaseSocket( struct socketData *pSocketData //!< The socket to release ) { assert(pSocketData != NULL); //DBG("%s: freeing socket %d\n", DBG_LIB, pSocketData->socketId); assert(pSocketData->state != SOCKET_STATE_UNUSED); assert(pSocketData->pEspconn == NULL); // free any unconsumed receive buffers while (pSocketData->rxBufQ != NULL) pSocketData->rxBufQ = PktBuf_ShiftFree(pSocketData->rxBufQ); if (pSocketData->currentTx != NULL) { //DBG("%s: freeing tx buf %p\n", DBG_LIB, pSocketData->currentTx); os_free(pSocketData->currentTx); pSocketData->currentTx = NULL; } os_memset(pSocketData, 0, sizeof(struct socketData)); }
/** * Receive data from the network device. * Returns the number of bytes received which may be 0 and <0 if there was an error. */ int net_ESP8266_BOARD_recv( JsNetwork *net, //!< The Network we are going to use to create the socket. int sckt, //!< The socket from which we are to receive data. void *buf, //!< The storage buffer into which we will receive data. size_t len //!< The length of the buffer. ) { //DBG("%s:recv\n", DBG_LIB); struct socketData *pSocketData = getSocketData(sckt); assert(pSocketData); assert(pSocketData->state != SOCKET_STATE_UNUSED); // handle socket that needs aborting if (pSocketData->state == SOCKET_STATE_TO_ABORT) { espconn_abort(pSocketData->pEspconn); return pSocketData->errorCode; } // If there is no data in the receive buffer, then all we need do is return // 0 bytes as the length of data moved or -1 if the socket is actually closed. if (pSocketData->rxBufQ == NULL) { switch (pSocketData->state) { case SOCKET_STATE_CLOSED: return pSocketData->errorCode != 0 ? pSocketData->errorCode : SOCKET_ERR_CLOSED; case SOCKET_STATE_DISCONNECTING: case SOCKET_STATE_ABORTING: return pSocketData->errorCode; case SOCKET_STATE_HOST_RESOLVING: case SOCKET_STATE_CONNECTING: return SOCKET_ERR_NO_CONN; default: return 0; // we just have no data } } PktBuf *rxBuf = pSocketData->rxBufQ; // If the receive buffer is able to completely fit in the buffer // passed into us then we can copy all the data and the receive buffer will be clear. if (rxBuf->filled <= len) { os_memcpy(buf, rxBuf->data, rxBuf->filled); int retLen = rxBuf->filled; pSocketData->rxBufQ = PktBuf_ShiftFree(rxBuf); // if we now have exactly one buffer enqueued we need to re-enable the flood if (pSocketData->rxBufQ != NULL && pSocketData->rxBufQ->next == NULL) espconn_recv_unhold(pSocketData->pEspconn); //DBG("%s: socket %d JS recv %d\n", DBG_LIB, sckt, retLen); return retLen; } // If we are here, then we have more data in the receive buffer than is available // to be returned in this request for data. So we have to copy the amount of data // that is allowed to be returned and then strip that from the beginning of the // receive buffer. // First we copy the data we are going to return. os_memcpy(buf, rxBuf->data, len); // Next we shift up the remaining data uint16_t newLen = rxBuf->filled - len; os_memmove(rxBuf->data, rxBuf->data + len, newLen); rxBuf->filled = newLen; //DBG("%s: socket %d JS recv %d\n", DBG_LIB, sckt, len); return len; }
/** * @brief Client received callback function. * @param arg: contain the ip link information * @param pdata: received data * @param len: the length of received data * @retval None */ static void ICACHE_FLASH_ATTR mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { //os_printf("MQTT: recv CB\n"); uint8_t msg_type; uint16_t msg_id; uint16_t msg_len; struct espconn* pCon = (struct espconn*)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; if (client == NULL) return; // aborted connection //os_printf("MQTT: Data received %d bytes\n", len); do { // append data to our buffer int avail = client->in_buffer_size - client->in_buffer_filled; if (len <= avail) { os_memcpy(client->in_buffer + client->in_buffer_filled, pdata, len); client->in_buffer_filled += len; len = 0; } else { os_memcpy(client->in_buffer + client->in_buffer_filled, pdata, avail); client->in_buffer_filled += avail; len -= avail; pdata += avail; } // check out what's at the head of the buffer msg_type = mqtt_get_type(client->in_buffer); msg_id = mqtt_get_id(client->in_buffer, client->in_buffer_size); msg_len = mqtt_get_total_length(client->in_buffer, client->in_buffer_size); if (msg_len > client->in_buffer_size) { // oops, too long a message for us to digest, disconnect and hope for a miracle os_printf("MQTT: Too long a message (%d bytes)\n", msg_len); mqtt_doAbort(client); return; } // check whether what's left in the buffer is a complete message if (msg_len > client->in_buffer_filled) break; if (client->connState != MQTT_CONNECTED) { // why are we receiving something?? DBG_MQTT("MQTT ERROR: recv in invalid state %d\n", client->connState); mqtt_doAbort(client); return; } // we are connected and are sending/receiving data messages uint8_t pending_msg_type = 0; uint16_t pending_msg_id = 0; if (client->pending_buffer != NULL) { pending_msg_type = mqtt_get_type(client->pending_buffer->data); pending_msg_id = mqtt_get_id(client->pending_buffer->data, client->pending_buffer->filled); } DBG_MQTT("MQTT: Recv type=%s id=%04X len=%d; Pend type=%s id=%02X\n", mqtt_msg_type[msg_type], msg_id, msg_len, mqtt_msg_type[pending_msg_type],pending_msg_id); switch (msg_type) { case MQTT_MSG_TYPE_CONNACK: //DBG_MQTT("MQTT: Connect successful\n"); // callbacks for internal and external clients if (client->connectedCb) client->connectedCb((uint32_t*)client); if (client->cmdConnectedCb) client->cmdConnectedCb((uint32_t*)client); client->reconTimeout = 1; // reset the reconnect backoff break; case MQTT_MSG_TYPE_SUBACK: if (pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: Subscribe successful\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_UNSUBACK: if (pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: Unsubscribe successful\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBACK: // ack for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: QoS1 Publish successful\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBREC: // rec for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: QoS2 publish cont\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBREL mqtt_msg_pubrel(&client->mqtt_connection, msg_id); mqtt_enq_message(client, client->mqtt_connection.message.data, client->mqtt_connection.message.length); } break; case MQTT_MSG_TYPE_PUBCOMP: // comp for a pubrel we sent (originally publish we sent) if (pending_msg_type == MQTT_MSG_TYPE_PUBREL && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: QoS2 Publish successful\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBLISH: { // incoming publish // we may need to ACK the publish uint8_t msg_qos = mqtt_get_qos(client->in_buffer); #ifdef MQTT_DBG uint16_t topic_length = msg_len; os_printf("MQTT: Recv PUBLISH qos=%d %s\n", msg_qos, mqtt_get_publish_topic(client->in_buffer, &topic_length)); #endif if (msg_qos == 1) mqtt_msg_puback(&client->mqtt_connection, msg_id); if (msg_qos == 2) mqtt_msg_pubrec(&client->mqtt_connection, msg_id); if (msg_qos == 1 || msg_qos == 2) { mqtt_enq_message(client, client->mqtt_connection.message.data, client->mqtt_connection.message.length); } // send the publish message to clients deliver_publish(client, client->in_buffer, msg_len); } break; case MQTT_MSG_TYPE_PUBREL: // rel for a rec we sent (originally publish received) if (pending_msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg_id == msg_id) { //DBG_MQTT("MQTT: Cont QoS2 recv\n"); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBCOMP mqtt_msg_pubcomp(&client->mqtt_connection, msg_id); mqtt_enq_message(client, client->mqtt_connection.message.data, client->mqtt_connection.message.length); } break; case MQTT_MSG_TYPE_PINGRESP: client->keepAliveAckTick = 0; break; } // Shift out the message and see whether we have another one if (msg_len < client->in_buffer_filled) os_memcpy(client->in_buffer, client->in_buffer+msg_len, client->in_buffer_filled-msg_len); client->in_buffer_filled -= msg_len; } while(client->in_buffer_filled > 0 || len > 0); // Send next packet out, if possible if (!client->sending && client->pending_buffer == NULL && client->msgQueue != NULL) { mqtt_send_message(client); } }