static err_t conn_poll(void *arg, tcp_pcb *pcb)
{
	ConnectionState *cs = (ConnectionState*)arg;
	if (cs == sendingConnection)
	{
		// Data could not be sent last time, check if the connection has to be timed out
		sendingRetries++;
		if (sendingRetries == TCP_MAX_SEND_RETRIES)
		{
			reprap.GetPlatform().MessageF(UsbMessage, "Network: Could not transmit data after %.1f seconds\n", (double)((float)TCP_WRITE_TIMEOUT / 1000.0));
			tcp_abort(pcb);
			return ERR_ABRT;
		}

		// Try to write the remaining data once again (if required)
		if (writeResult != ERR_OK)
		{
			writeResult = tcp_write(pcb, sendingWindow + (sendingWindowSize - sentDataOutstanding), sentDataOutstanding, 0);
			if (ERR_IS_FATAL(writeResult))
			{
				reprap.GetPlatform().MessageF(UsbMessage, "Network: Failed to write data in conn_poll (code %d)\n", writeResult);
				tcp_abort(pcb);
				return ERR_ABRT;
			}

			if (writeResult != ERR_OK && reprap.Debug(moduleNetwork))
			{
				reprap.GetPlatform().MessageF(UsbMessage, "Network: tcp_write resulted in error code %d\n", writeResult);
			}
		}

		// If that worked, try to output the remaining data (if required)
		if (outputResult != ERR_OK)
		{
			outputResult = tcp_output(pcb);
			if (ERR_IS_FATAL(outputResult))
			{
				reprap.GetPlatform().MessageF(UsbMessage, "Network: Failed to output data in conn_poll (code %d)\n", outputResult);
				tcp_abort(pcb);
				return ERR_ABRT;
			}

			if (outputResult != ERR_OK && reprap.Debug(moduleNetwork))
			{
				reprap.GetPlatform().MessageF(UsbMessage, "Network: tcp_output resulted in error code %d\n", outputResult);
			}
		}
	}
	else
	{
		reprap.GetPlatform().Message(UsbMessage, "Network: Mismatched pcb in conn_poll!\n");
	}
	return ERR_OK;
}
Example #2
0
/**
 * Bind a pcb contained in a netconn
 * Called from netconn_bind.
 *
 * @param msg the api_msg_msg pointing to the connection and containing
 *            the IP address and port to bind to
 */
void
do_bind(struct api_msg_msg *msg)
{
    if (ERR_IS_FATAL(msg->conn->last_err)) {
        msg->err = msg->conn->last_err;
    } else {
        msg->err = ERR_VAL;
        if (msg->conn->pcb.tcp != NULL) {
            switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
            case NETCONN_RAW:
                msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
                break;
#endif /* LWIP_RAW */
#if LWIP_UDP
            case NETCONN_UDP:
                msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
                break;
#endif /* LWIP_UDP */
#if LWIP_TCP
            case NETCONN_TCP:
                msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
                break;
#endif /* LWIP_TCP */
            default:
                break;
            }
        }
    }
    TCPIP_APIMSG_ACK(msg);
}
Example #3
0
/**
 * Join multicast groups for UDP netconns.
 * Called from netconn_join_leave_group
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_join_leave_group(struct api_msg_msg *msg)
{
    if (ERR_IS_FATAL(msg->conn->last_err)) {
        msg->err = msg->conn->last_err;
    } else {
        if (msg->conn->pcb.tcp != NULL) {
            if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP
                if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
                    msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
                } else {
                    msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
                }
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
            } else {
                msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */
            }
        } else {
            msg->err = ERR_CONN;
        }
    }
    TCPIP_APIMSG_ACK(msg);
}
Example #4
0
/**
 * Send some data on a RAW or UDP pcb contained in a netconn
 * Called from netconn_send
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_send(struct api_msg_msg *msg)
{
  if (!ERR_IS_FATAL(msg->conn->err)) {
    if (msg->conn->pcb.tcp != NULL) {
      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
      case NETCONN_RAW:
        if (msg->msg.b->addr == NULL) {
          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
        } else {
          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
        }
        break;
#endif
#if LWIP_UDP
      case NETCONN_UDP:
        if (msg->msg.b->addr == NULL) {
          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
        } else {
          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
        }
        break;
#endif /* LWIP_UDP */
      default:
        break;
      }
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
Example #5
0
/**
 * Send some data on a TCP pcb contained in a netconn
 * Called from netconn_write
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_write(struct api_msg_msg *msg)
{
  if (!ERR_IS_FATAL(msg->conn->err)) {
    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
#if LWIP_TCP
      msg->conn->state = NETCONN_WRITE;
      /* set all the variables used by do_writemore */
      LWIP_ASSERT("already writing", msg->conn->write_msg == NULL &&
        msg->conn->write_offset == 0);
      msg->conn->write_msg = msg;
      msg->conn->write_offset = 0;
#if LWIP_TCPIP_CORE_LOCKING
      msg->conn->write_delayed = 0;
      if (do_writemore(msg->conn) != ERR_OK) {
        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
        UNLOCK_TCPIP_CORE();
        sys_arch_sem_wait(msg->conn->op_completed, 0);
        LOCK_TCPIP_CORE();
        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
      }
#else
      do_writemore(msg->conn);
#endif
      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */
      return;
#endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW)
    } else {
      msg->conn->err = ERR_VAL;
#endif /* (LWIP_UDP || LWIP_RAW) */
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
Example #6
0
/**
 * Set a TCP pcb contained in a netconn into listen mode
 * Called from netconn_listen.
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
lwip_netconn_do_listen(struct api_msg_msg *msg)
{
  if (ERR_IS_FATAL(msg->conn->last_err)) {
    msg->err = msg->conn->last_err;
  } else {
    msg->err = ERR_CONN;
    if (msg->conn->pcb.tcp != NULL) {
      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
        if (msg->conn->state == NETCONN_NONE) {
          struct tcp_pcb* lpcb;
#if LWIP_IPV6
          if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) {
#if TCP_LISTEN_BACKLOG
            lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else  /* TCP_LISTEN_BACKLOG */
            lpcb = tcp_listen_dual(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
          } else
#endif /* LWIP_IPV6 */
          {
#if TCP_LISTEN_BACKLOG
            lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else  /* TCP_LISTEN_BACKLOG */
            lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
          }
          if (lpcb == NULL) {
            /* in this case, the old pcb is still allocated */
            msg->err = ERR_MEM;
          } else {
            /* delete the recvmbox and allocate the acceptmbox */
            if (sys_mbox_valid(&msg->conn->recvmbox)) {
              /** @todo: should we drain the recvmbox here? */
              sys_mbox_free(&msg->conn->recvmbox);
              sys_mbox_set_invalid(&msg->conn->recvmbox);
            }
            msg->err = ERR_OK;
            if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
              msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
            }
            if (msg->err == ERR_OK) {
              msg->conn->state = NETCONN_LISTEN;
              msg->conn->pcb.tcp = lpcb;
              tcp_arg(msg->conn->pcb.tcp, msg->conn);
              tcp_accept(msg->conn->pcb.tcp, accept_function);
            } else {
              /* since the old pcb is already deallocated, free lpcb now */
              tcp_close(lpcb);
              msg->conn->pcb.tcp = NULL;
            }
          }
        }
      } else {
        msg->err = ERR_ARG;
      }
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
Example #7
0
/**
 * Send data on a TCP pcb 
 */
static void net_do_write(void *ctx)
{
    struct tls_net_msg *net_msg = (struct tls_net_msg *)ctx;
    struct tls_netconn *conn = net_msg->conn;
	struct tls_netconn *server_conn = NULL;

    //TLS_DBGPRT_INFO("s=%d,p=0x%x\n", conn->state, conn->pcb.tcp);

#if 0
    if (ERR_IS_FATAL(conn->last_err)) {
        net_msg->err = conn->last_err;
    } 
#endif
    if (conn->proto == TLS_NETCONN_TCP) {
#if LWIP_TCP
        if (conn->state != NETCONN_STATE_CONNECTED) {
            /* netconn is connecting, closing or in blocking write */
            net_msg->err = ERR_INPROGRESS;
        } else if (conn->pcb.tcp != NULL) {
            conn->write_state = true;
            //conn->write_offset = 0;
            net_msg->err = net_skt_tcp_send(net_msg);
            /* for both cases: if do_writemore was called, don't ACK the APIMSG
               since do_writemore ACKs it! */
        } else {
            net_msg->err = ERR_CONN;
            TLS_DBGPRT_INFO("==>err=%d\n", net_msg->err);
        }
	if(conn->client && conn->idle_time > 0)
	{
		TLS_DBGPRT_INFO("conn->skt_num=%d, conn->client=%d\n", conn->skt_num, conn->client);
//		server_conn = dl_list_first(&conn->list, struct tls_netconn, list);
        server_conn = get_server_conn(conn);
		TLS_DBGPRT_INFO("server_conn=%p\n", server_conn);
		if(server_conn)
		{
			conn->idle_time = server_conn->idle_time;
			TLS_DBGPRT_INFO("update conn->idle_time %d\n", conn->idle_time);
		}
	}
#else /* LWIP_TCP */
        net_msg->err = ERR_VAL;
#endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW)
    } else {
        net_msg->err = ERR_VAL;
#endif /* (LWIP_UDP || LWIP_RAW) */
    }
        //tls_mem_free(net_msg->dataptr);
    //if(net_msg->err != ERR_OK)
    {
        //TLS_DBGPRT_INFO("conn->proto=%d, err=%d\n", conn->proto, net_msg->err);
        //TLS_DBGPRT_INFO("free net_msg->dataptr=%p\n", net_msg->dataptr);
        sys_sem_signal(conn->op_completed);
    }
#if 0
    tls_mem_free(net_msg);
#endif
}
Example #8
0
/**
 * Bind a pcb contained in a netconn
 * Called from netconn_bind.
 *
 * @param msg the api_msg_msg pointing to the connection and containing
 *            the IP address and port to bind to
 */
void
do_bind(struct api_msg_msg *msg)
{
  if (!ERR_IS_FATAL(msg->conn->err)) {
    if (msg->conn->pcb.tcp != NULL) {
      //[MS_CHANGE] - make sure we are binding to a valid address
      u8_t validAddr = ip_addr_isany(msg->msg.bc.ipaddr);

      if(!validAddr) {
        struct netif *netif;
        for(netif = netif_list; netif != NULL; netif = netif->next) {
          /* network mask matches? */
          if (netif_is_up(netif)) {
            if(ip_addr_cmp(msg->msg.bc.ipaddr, &netif->ip_addr)) {
                validAddr = 1;
                break;
            }
          }
        }
      }

      //[MS_CHANGE] - make sure we are binding to a valid address
      if(validAddr) 
      {
        switch (NETCONNTYPE_GROUP(msg->conn->type)) {
  #if LWIP_RAW
        case NETCONN_RAW:
          msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
          break;
  #endif /* LWIP_RAW */
  #if LWIP_UDP
        case NETCONN_UDP:
          msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
          break;
  #endif /* LWIP_UDP */
  #if LWIP_TCP
        case NETCONN_TCP:
          msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
          break;
  #endif /* LWIP_TCP */
        default:
          break;
        }
      }
      else {
          msg->conn->err = ERR_VAL;        
      }
    } else {
      /* msg->conn->pcb is NULL */
      msg->conn->err = ERR_VAL;
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
Example #9
0
/**
 * Send some data on a TCP pcb contained in a netconn
 * Called from netconn_write
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_write(struct api_msg_msg *msg)
{
    if (ERR_IS_FATAL(msg->conn->last_err)) {
        msg->err = msg->conn->last_err;
    } else {
        if (msg->conn->type == NETCONN_TCP) {
#if LWIP_TCP
            if (msg->conn->state != NETCONN_NONE) {
                /* netconn is connecting, closing or in blocking write */
                msg->err = ERR_INPROGRESS;
            } else if (msg->conn->pcb.tcp != NULL) {
                msg->conn->state = NETCONN_WRITE;
                /* set all the variables used by do_writemore */
                LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
                            msg->conn->write_offset == 0);
                LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
                msg->conn->current_msg = msg;
                msg->conn->write_offset = 0;
#if LWIP_TCPIP_CORE_LOCKING
                msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
                if (do_writemore(msg->conn) != ERR_OK) {
                    LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
                    UNLOCK_TCPIP_CORE();
                    sys_arch_sem_wait(&msg->conn->op_completed, 0);
                    LOCK_TCPIP_CORE();
                    LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
                }
#else /* LWIP_TCPIP_CORE_LOCKING */
                do_writemore(msg->conn);
#endif /* LWIP_TCPIP_CORE_LOCKING */
                /* for both cases: if do_writemore was called, don't ACK the APIMSG
                   since do_writemore ACKs it! */
                return;
            } else {
                msg->err = ERR_CONN;
            }
#else /* LWIP_TCP */
            msg->err = ERR_VAL;
#endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW)
        } else {
            msg->err = ERR_VAL;
#endif /* (LWIP_UDP || LWIP_RAW) */
        }
    }
    TCPIP_APIMSG_ACK(msg);
}
Example #10
0
/**
 * Send some data on a RAW or UDP pcb contained in a netconn
 * Called from netconn_send
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_send(struct api_msg_msg *msg)
{
    if (ERR_IS_FATAL(msg->conn->last_err)) {
        msg->err = msg->conn->last_err;
    } else {
        msg->err = ERR_CONN;
        if (msg->conn->pcb.tcp != NULL) {
            switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
            case NETCONN_RAW:
                if (ip_addr_isany(&msg->msg.b->addr)) {
                    msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
                } else {
                    msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
                }
                break;
#endif
#if LWIP_UDP
            case NETCONN_UDP:
#if LWIP_CHECKSUM_ON_COPY
                if (ip_addr_isany(&msg->msg.b->addr)) {
                    msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
                                               msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
                } else {
                    msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
                                                 &msg->msg.b->addr, msg->msg.b->port,
                                                 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
                }
#else /* LWIP_CHECKSUM_ON_COPY */
                if (ip_addr_isany(&msg->msg.b->addr)) {
                    msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
                } else {
                    msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
                }
#endif /* LWIP_CHECKSUM_ON_COPY */
                break;
#endif /* LWIP_UDP */
            default:
                break;
            }
        }
    }
    TCPIP_APIMSG_ACK(msg);
}
Example #11
0
/**
 * Join multicast groups for UDP netconns.
 * Called from netconn_join_leave_group
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
lwip_netconn_do_join_leave_group(struct api_msg_msg *msg)
{ 
  if (ERR_IS_FATAL(msg->conn->last_err)) {
    msg->err = msg->conn->last_err;
  } else {
    if (msg->conn->pcb.tcp != NULL) {
      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP
#if LWIP_IPV6 && LWIP_IPV6_MLD
        if (PCB_ISIPV6(msg->conn->pcb.udp)) {
          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
            msg->err = mld6_joingroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
          } else {
            msg->err = mld6_leavegroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
          }
        }
        else
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
        {
#if LWIP_IGMP
          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
            msg->err = igmp_joingroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr)));
          } else {
            msg->err = igmp_leavegroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr)));
          }
#endif /* LWIP_IGMP */
        }
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
      } else {
        msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */
      }
    } else {
      msg->err = ERR_CONN;
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
Example #12
0
/**
 * Set a TCP pcb contained in a netconn into listen mode
 * Called from netconn_listen.
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_listen(struct api_msg_msg *msg)
{
#if LWIP_TCP
  if (!ERR_IS_FATAL(msg->conn->err)) {
    if (msg->conn->pcb.tcp != NULL) {
      if (msg->conn->type == NETCONN_TCP) {
        if (msg->conn->pcb.tcp->state == CLOSED) {
#if TCP_LISTEN_BACKLOG
          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else  /* TCP_LISTEN_BACKLOG */
          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
          if (lpcb == NULL) {
            msg->conn->err = ERR_MEM;
          } else {
            /* delete the recvmbox and allocate the acceptmbox */
            if (msg->conn->recvmbox != SYS_MBOX_NULL) {
              /** @todo: should we drain the recvmbox here? */
              sys_mbox_free(msg->conn->recvmbox);
              msg->conn->recvmbox = SYS_MBOX_NULL;
            }
            if (msg->conn->acceptmbox == SYS_MBOX_NULL) {
              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {
                msg->conn->err = ERR_MEM;
              }
            }
            if (msg->conn->err == ERR_OK) {
              msg->conn->state = NETCONN_LISTEN;
              msg->conn->pcb.tcp = lpcb;
              tcp_arg(msg->conn->pcb.tcp, msg->conn);
              tcp_accept(msg->conn->pcb.tcp, accept_function);
            }
          }
        } else {
          msg->conn->err = ERR_CONN;
        }
      }
    }
  }
#endif /* LWIP_TCP */
  TCPIP_APIMSG_ACK(msg);
}
Example #13
0
/**
 * Indicate data has been received from a TCP pcb contained in a netconn
 * Called from netconn_recv
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
do_recv(struct api_msg_msg *msg)
{
#if LWIP_TCP
  if (!ERR_IS_FATAL(msg->conn->err)) {
    if (msg->conn->pcb.tcp != NULL) {
      if (msg->conn->type == NETCONN_TCP) {
#if TCP_LISTEN_BACKLOG
        if (msg->conn->pcb.tcp->state == LISTEN) {
          tcp_accepted(msg->conn->pcb.tcp);
        } else
#endif /* TCP_LISTEN_BACKLOG */
        {
          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);
        }
      }
    }
  }
#endif /* LWIP_TCP */
  TCPIP_APIMSG_ACK(msg);
}
// Send exactly one TCP window of data and return true when this transaction can be released
bool NetworkTransaction::Send()
{
	// Free up this transaction if the connection is supposed to be closed
	if (closeRequested)
	{
		reprap.GetNetwork().ConnectionClosed(cs, true);	// This will release the transaction too
		return false;
	}

	// Fill up the TCP window with some data chunks from our OutputBuffer instances
	size_t bytesBeingSent = 0, bytesLeftToSend = TCP_WND;
	while (sendBuffer != nullptr && bytesLeftToSend > 0)
	{
		size_t copyLength = min<size_t>(bytesLeftToSend, sendBuffer->BytesLeft());
		memcpy(sendingWindow + bytesBeingSent, sendBuffer->Read(copyLength), copyLength);
		bytesBeingSent += copyLength;
		bytesLeftToSend -= copyLength;

		if (sendBuffer->BytesLeft() == 0)
		{
			sendBuffer = OutputBuffer::Release(sendBuffer);
			if (sendBuffer == nullptr)
			{
				sendBuffer = sendStack->Pop();
			}
		}
	}

	// We also intend to send a file, so check if we can fill up the TCP window
	if (sendBuffer == nullptr && bytesLeftToSend != 0 && fileBeingSent != nullptr)
	{
		// For HSMCI efficiency, read from the file in multiples of 4 bytes except at the end.
		// This ensures that the second and subsequent chunks can be DMA'd directly into sendingWindow.
		size_t bytesToRead = bytesLeftToSend & (~3);
		if (bytesToRead != 0)
		{
			int bytesRead = fileBeingSent->Read(sendingWindow + bytesBeingSent, bytesToRead);
			if (bytesRead > 0)
			{
				bytesBeingSent += bytesRead;
			}

			if (bytesRead != (int)bytesToRead)
			{
				fileBeingSent->Close();
				fileBeingSent = nullptr;
			}
		}
	}

	if (bytesBeingSent == 0)
	{
		// If we have no data to send, this connection can be closed next time
		if (!cs->persistConnection && nextWrite == nullptr)
		{
			Close();
			return false;
		}

		// We want to send data from another transaction as well, so only free up this one
		cs->sendingTransaction = nextWrite;
		return true;
	}

	// The TCP window has been filled up as much as possible, so send it now. There is no need to check
	// the available space in the SNDBUF queue, because we really write only one TCP window at once.
	writeResult = tcp_write(cs->pcb, sendingWindow, bytesBeingSent, 0);
	if (ERR_IS_FATAL(writeResult))
	{
		reprap.GetPlatform().MessageF(UsbMessage, "Network: Failed to write data in Send (code %d)\n", writeResult);
		tcp_abort(cs->pcb);
		return false;
	}

	outputResult = tcp_output(cs->pcb);
	if (ERR_IS_FATAL(outputResult))
	{
		reprap.GetPlatform().MessageF(UsbMessage, "Network: Failed to output data in Send (code %d)\n", outputResult);
		tcp_abort(cs->pcb);
		return false;
	}

	if (outputResult != ERR_OK && reprap.Debug(moduleNetwork))
	{
		reprap.GetPlatform().MessageF(UsbMessage, "Network: tcp_output resulted in error code %d\n", outputResult);
	}

	// Set LwIP callbacks for ACK and retransmission handling
	tcp_poll(cs->pcb, conn_poll, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES);
	tcp_sent(cs->pcb, conn_sent);

	// Set all values for the send process
	sendingConnection = cs;
	sendingRetries = 0;
	sendingWindowSize = sentDataOutstanding = bytesBeingSent;
	return false;
}
void wanwuyun_task(void * pvParameters)
{
	//创建Queue
	SENSOR_STRUCT *pRxSensorFrame;
	portBASE_TYPE  xStatus; 
	struct ip_addr WanWuYunIPaddr;
	static err_t err,recv_err;
	
	//网络相关结构体
	struct   netbuf *inbuf;
	uint8_t  *buf;
	uint16_t buflen;
	//成功发送 = true,其他状态为 = false	
	bool wan_send_success_flag = false;	
	
	//创建Json的结构体
	cJSON   *DataUpReqJson, *RowJson, *DataUpResJson,*fld;
	char 	*DataOut;
	
	char double_string[]={0};
#if 0	
	cJSON   *SignInReqJson ,*SignInResJson;
	SignInReqJson=cJSON_CreateObject();
	cJSON_AddStringToObject(SignInReqJson, "username", "jackeyjiang");
	cJSON_AddStringToObject(SignInReqJson, "accessid", "AMFJA2V5AMLHBMCXNDI5NZE2NDIXMTMW");
	cJSON_AddStringToObject(SignInReqJson, "appid", "9785739981");
	cJSON_AddStringToObject(SignInReqJson, "dev_id", "stm32_test");
	DataOut = cJSON_Print(DataUpReqJson);
	cJSON_Delete(SignInReqJson);
	vPortFree(DataOut);
	
	DataUpReqJson=cJSON_CreateArray();
	cJSON_AddItemToObject(DataUpReqJson,NULL,fld = cJSON_CreateObject());
	cJSON_AddStringToObject(fld, "seckey", "HgqoOLTlav5jTsefyj3nL5AkRu8UAFRf");
	cJSON_AddItemToObject(fld, "row", RowJson=cJSON_CreateObject());
	cJSON_AddStringToObject(RowJson, "DEV_ID", "stm32_test");
	cJSON_AddNumberToObject(RowJson, "TEMPERATURE", 12.5);
	cJSON_AddNumberToObject(RowJson, "LATITUDE", 12.7);
	cJSON_AddNumberToObject(RowJson, "LONGITUDE", 12.8);
	//转换数据为cJSON数据
	DataOut = cJSON_Print(DataUpReqJson);
	cJSON_Delete(DataUpReqJson);
	printf("%s",DataOut);
	vPortFree(DataOut);	

	//解析返回的Json数据
	SignInResJson = cJSON_Parse(SignInResponse);
	if (!SignInResJson) 
	vPrintString("Error before: [%s]\n",cJSON_GetErrorPtr());
	else {};
	DataUpResJson = cJSON_Parse(DataUpResponse);
	if (!DataUpResJson) vPrintString("Error before: [%s]\n",cJSON_GetErrorPtr());
	else {};	
#endif	
	//创建传感器队列
	pRxSensor_xQueue = xQueueCreate( 2, sizeof(  struct _SENSOR_STRUCT * ) );

	//建立短连接,接收到队列传过来的数据,将其打包成json数据传送到万物云。
	IP4_ADDR( &WanWuYunIPaddr, WANWUYUN_IP_ADDR0, WANWUYUN_IP_ADDR1, WANWUYUN_IP_ADDR2, WANWUYUN_IP_ADDR3 );
	
	while(1)
	{
		/* Create a new connection identifier. */
		STM_EVAL_LEDOff(LED2);
		wanwuyun_clientconn = netconn_new_with_callback(NETCONN_TCP,wanwuyun_callback); //测试
		if (wanwuyun_clientconn!=NULL)
		{  
			/*built a connect to wanwuyun.com server*/
			//netconn_set_nonblocking(wanwuyun_clientconn, 1); //测试
			err = netconn_connect(wanwuyun_clientconn,&WanWuYunIPaddr,WANWUYUN_SERVER_PORT);
			if (err != ERR_OK)  netconn_delete(wanwuyun_clientconn); 
			else if (err == ERR_OK)
			{
				STM_EVAL_LEDOn(LED2);
				vPrintString("netconn_connect wanwuyun_clientconn\r\n");
				/*timeout to wait for new data to be received <Avoid death etc.> */
				netconn_set_sendtimeout(wanwuyun_clientconn,300);
				netconn_set_recvtimeout(wanwuyun_clientconn,700);
				while(!ERR_IS_FATAL(wanwuyun_clientconn->last_err)) 
				{
					STM_EVAL_LEDToggle(LED3);
					xStatus = xQueueReceive(pRxSensor_xQueue,&(pRxSensorFrame),( portTickType ) 1 );
					if(xStatus == pdPASS)
					{	
						//提取结构体中的数据
						DataUpReqJson=cJSON_CreateArray();
						cJSON_AddItemToObject(DataUpReqJson,NULL,fld = cJSON_CreateObject());
						cJSON_AddStringToObject(fld, "seckey", "HgqoOLTlav5jTsefyj3nL5AkRu8UAFRf");
						cJSON_AddItemToObject(fld, "row", RowJson=cJSON_CreateObject());
						cJSON_AddStringToObject(RowJson, "DEV_ID", "stm32_test");
						sprintf(double_string,"%f",pRxSensorFrame->temperature[0]);
						cJSON_AddStringToObject(RowJson, "TEMPERATURE", double_string);
						sprintf(double_string,"%f",pRxSensorFrame->latitude[0]);
						cJSON_AddStringToObject(RowJson, "LATITUDE", double_string);
						sprintf(double_string,"%f",pRxSensorFrame->longitude[0]);
						cJSON_AddStringToObject(RowJson, "LONGITUDE", double_string);
						//转换数据为cJSON数据
						DataOut = cJSON_Print(DataUpReqJson);
						//printf("%d",strlen(DataOut));
						cJSON_Delete(DataUpReqJson);
						vPrintString("%s\r\n",DataOut);
						//vPortFree(DataOut);					
						err=netconn_write(wanwuyun_clientconn,\
							DataOut,strlen(DataOut),\
							NETCONN_COPY);	
						if(err != ERR_OK)  
						{
							vPortFree(DataOut);
							vPrintString("StatuUploadReq erro code is %d\r\n",err);
							break;
						}	
						else
						{
							wan_send_success_flag = true; //表示数据已经发送了
							vPortFree(DataOut);	
						}
					}
					//netconn_recved(wanwuyun_clientconn,100); //测试
					recv_err = netconn_recv(wanwuyun_clientconn, &inbuf);
					if (recv_err == ERR_OK)
					{
						if (netconn_err(wanwuyun_clientconn) == ERR_OK)
						{ 
							netbuf_data(inbuf, (void**)&buf, &buflen);
							DataUpResJson = cJSON_Parse((char *)buf);
							DataOut = cJSON_Print(DataUpResJson);
							vPrintString("%s\r\n",DataOut);
							netbuf_delete(inbuf);
							wan_send_success_flag = false;
							//使用短链接,成功后跳出while(1)
							//break;
						}
						else
						{
							vPrintString("recv_err != ERR_OK \r\n");
						}
					}
					#if 1  //测试当断开连接的时候的状态
					else if((recv_err == ERR_TIMEOUT)&&(wan_send_success_flag == true)) 
					{
						wan_send_success_flag = false;
						vPrintString("recv_err == %d\r\n",recv_err);
						netconn_close(wanwuyun_clientconn);
						netbuf_delete(inbuf);
						netconn_delete(wanwuyun_clientconn);
						//为发送的数据重新入队
						xQueueSendToFront(pRxSensor_xQueue,&(pRxSensorFrame),( portTickType )1);
						break;
					}
					#endif
				}
			}
		}
	}	
}