Example #1
0
/**
 * 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);
}
Example #2
0
/**
 * 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));
}
Example #3
0
/**
 * 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;
}
Example #4
0
/**
* @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);
  }
}