LwIP之協議棧接口

先了解應用層和協議棧是怎麼交互消息的

先看內核消息數據結構

/* tcp/ip內核消息類型 */
enum tcpip_msg_type 
{
  TCPIP_MSG_API,            //調用API
  TCPIP_MSG_INPKT,          //底層數據包輸入
  TCPIP_MSG_TIMEOUT,        //註冊一個定時事件
  TCPIP_MSG_UNTIMEOUT,      //刪除一個定時事件
  TCPIP_MSG_CALLBACK,       //上層回調函數
  TCPIP_MSG_CALLBACK_STATIC //上層回調函數(消息爲靜態)
};

/* tcp/ip內核消息 */
struct tcpip_msg 
{
  enum tcpip_msg_type type;		//消息類型
  sys_sem_t *sem;				//信號量指針
  
  union 
  {
    /* API消息 */
    struct api_msg *apimsg;
		
    /* 底層數據包輸入消息 */
    struct 
    {
      struct pbuf *p;		    //數據包pbuf指針
      struct netif *netif;	    //網絡接口指針
    }inp;
		
    /* 上層回調函數消息 */
    struct 
    {
      tcpip_callback_fn function;    //回調函數
      void *ctx;                     //回調函數參數
    }cb;
		
    /* 定時事件 */
    struct 
    {
      u32_t msecs;                //時間
      sys_timeout_handler h;      //回調函數
      void *arg;                  //回調函數參數
    }tmo;
  }msg;
};

在看一下,內核是怎麼分類處理應用層消息的

static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox;

/* tcp/ip線程 */
static void tcpip_thread(void *arg)
{
  struct tcpip_msg *msg;

  /* 用戶自定義初始化函數 */
  if(tcpip_init_done != NULL) 
  {
    tcpip_init_done(tcpip_init_done_arg);
  }

  while(1) 
  {
	/* 所有的超時事件和郵箱消息都在這裏處理 */
    sys_timeouts_mbox_fetch(&mbox, (void **)&msg);

	/* 接收到消息 */
    switch(msg->type) 
    {
	  /* API消息 */
	  case TCPIP_MSG_API:
		/* 調用API */
		msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
		break;

	  /* 底層數據包輸入 */
	  case TCPIP_MSG_INPKT:
		/* 以太網設備 */
		/* 支持ARP協議 */
		if(msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) 
		{
		  /* 以太網數據包輸入處理 */
		  ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
		}
		/* 不支持ARP協議 */
		else
		{
		  /* IP數據包輸入處理 */
		  ip_input(msg->msg.inp.p, msg->msg.inp.netif);
		}
				
		/* 釋放該消息內存空間 */
		memp_free(MEMP_TCPIP_MSG_INPKT, msg);
		break;

	  /* 註冊一個定時事件 */
	  case TCPIP_MSG_TIMEOUT:
        /* 啓動定時事件 */
        sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
				
        /* 釋放該消息內存空間 */
        memp_free(MEMP_TCPIP_MSG_API, msg);
		break;
			
	  /* 刪除一個定時事件 */
	  case TCPIP_MSG_UNTIMEOUT:
		/* 取消定時事件 */
		sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
				
		/* 釋放該消息內存空間 */
		memp_free(MEMP_TCPIP_MSG_API, msg);
		break;

	  /* 上層回調函數 */
	  case TCPIP_MSG_CALLBACK:
		/* 調用回調函數 */
		msg->msg.cb.function(msg->msg.cb.ctx);
			
		/* 釋放該消息內存空間 */
		memp_free(MEMP_TCPIP_MSG_API, msg);
		break;

	  /* 上層回調函數(消息爲靜態) */
      case TCPIP_MSG_CALLBACK_STATIC:
		/* 調用回調函數 */
		msg->msg.cb.function(msg->msg.cb.ctx);
		break;

	  default:
		break;
    }
  }
}

/* 底層數據包輸入處理函數 */
err_t tcpip_input(struct pbuf *p, struct netif *inp)
{
  struct tcpip_msg *msg;

  /* 郵箱無效 */
  if(!sys_mbox_valid(&mbox)) 
  {
    return ERR_VAL;
  }

  /* 爲底層數據包輸入消息從內存池申請內存 */
  msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
  if(msg == NULL) 
  {
    return ERR_MEM;
  }

  /* 底層數據包輸入消息 */
  msg->type = TCPIP_MSG_INPKT;
  /* 數據包內容 */
  msg->msg.inp.p = p;
  /* 網絡接口指針 */
  msg->msg.inp.netif = inp;

  /* 發送消息 */
  if(sys_mbox_trypost(&mbox, msg) != ERR_OK) 
  {
    memp_free(MEMP_TCPIP_MSG_INPKT, msg);
    return ERR_MEM;
  }

  return ERR_OK;
}

/* 上層回調函數 */
err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
{
  struct tcpip_msg *msg;

  /* 郵箱有效 */
  if(sys_mbox_valid(&mbox)) 
  {
	/* 爲上層回調函數消息從內存池申請內存 */
    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
    if(msg == NULL) 
	{
      return ERR_MEM;
    }

	/* 上層回調函數 */
    msg->type = TCPIP_MSG_CALLBACK;
	/* 回調函數 */
    msg->msg.cb.function = function;
	/* 回調函數參數 */
    msg->msg.cb.ctx = ctx;
		
	/* 發送消息(阻塞) */
    if(block) 
	{
      sys_mbox_post(&mbox, msg);
    }
	/* 發送消息(非阻塞) */
	else 
	{
      if(sys_mbox_trypost(&mbox, msg) != ERR_OK) 
	  {
        memp_free(MEMP_TCPIP_MSG_API, msg);
        return ERR_MEM;
      }
    }

    return ERR_OK;
  }

  return ERR_VAL;
}

/* 註冊一個定時事件 */
err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
  struct tcpip_msg *msg;

  /* 郵箱爲有效 */
  if(sys_mbox_valid(&mbox)) 
  {
	/* 爲註冊一個定時事件消息從內存池申請內存 */
    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
    if(msg == NULL) 
	{
      return ERR_MEM;
    }

	/* 註冊一個定時事件 */
    msg->type = TCPIP_MSG_TIMEOUT;
	/* 定時事件 */
    msg->msg.tmo.msecs = msecs;
	/* 回調函數 */
    msg->msg.tmo.h = h;
	/* 回調函數參數 */
    msg->msg.tmo.arg = arg;
		
	/* 發送消息 */
    sys_mbox_post(&mbox, msg);
		
    return ERR_OK;
  }

  return ERR_VAL;
}

/* 刪除一個定時事件 */
err_t tcpip_untimeout(sys_timeout_handler h, void *arg)
{
  struct tcpip_msg *msg;

  /* 郵箱爲有效 */
  if(sys_mbox_valid(&mbox)) 
  {
	/* 爲刪除一個定時事件消息從內存池申請內存 */
    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
    if(msg == NULL) 
	{
      return ERR_MEM;
    }

	/* 刪除一個定時事件 */
    msg->type = TCPIP_MSG_UNTIMEOUT;
	/* 回調函數 */
    msg->msg.tmo.h = h;
	/* 回調函數參數 */
    msg->msg.tmo.arg = arg;
		
	/* 發送消息 */
    sys_mbox_post(&mbox, msg);

    return ERR_OK;
  }

  return ERR_VAL;
}

/* API調用 */
err_t tcpip_apimsg(struct api_msg *apimsg)
{
  struct tcpip_msg msg;
 
  /* 郵箱爲有效 */
  if(sys_mbox_valid(&mbox)) 
  {
	/* 調用API */
    msg.type = TCPIP_MSG_API;
    
	/* API消息 */
	msg.msg.apimsg = apimsg;
		
	/* 發送消息 */
    sys_mbox_post(&mbox, &msg);
		
	/* 等待API調用完成 */
    sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);

    return apimsg->msg.err;
  }

  return ERR_VAL;
}

/* 創建上層回調函數消息 */
struct tcpip_callback_msg *tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
{
  /* 爲上層回調函數消息從內存池申請內存 */
  struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  if(msg == NULL) 
  {
    return NULL;
  }

  /* 上層回調函數 */
  msg->type = TCPIP_MSG_CALLBACK_STATIC;
  /* 回調函數 */
  msg->msg.cb.function = function;
  /* 回調函數參數 */
  msg->msg.cb.ctx = ctx;

  /* 返回消息指針 */
  return (struct tcpip_callback_msg *)msg;
}

/* 釋放上層回調函數消息 */
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
{
  memp_free(MEMP_TCPIP_MSG_API, msg);
}

/* 發送上層回調函數消息 */
err_t tcpip_trycallback(struct tcpip_callback_msg* msg)
{
  if(!sys_mbox_valid(&mbox)) 
  {
    return ERR_VAL;
  }

  return sys_mbox_trypost(&mbox, msg);
}

/* tcp/ip初始化 */
void tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
  /* 初始化協議棧 */
  lwip_init();

  /* 自定義初始化函數 */
  tcpip_init_done = initfunc;
  tcpip_init_done_arg = arg;
	
  /* 創建郵箱 */
  if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) 
  {
  }

  /* 創建線程 */
  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}

/* 釋放pbuf上層回調函數 */
static void pbuf_free_int(void *p)
{
  struct pbuf *q = (struct pbuf *)p;
  pbuf_free(q);
}

/* 使用上層回調函數消息釋放pbuf */
err_t pbuf_free_callback(struct pbuf *p)
{
  /* 使用上層回調函數消息釋放pbuf */
  return tcpip_callback_with_block(pbuf_free_int, p, 0);
}

/* 使用上層回調函數消息釋放到內存堆 */
err_t mem_free_callback(void *m)
{
  /* 使用上層回調函數消息釋放到內存堆 */
  return tcpip_callback_with_block(mem_free, m, 0);
}

接下來看一下內核收到消息後具體是怎麼工作的

/* API消息 */
struct api_msg_msg 
{
  /* 連接結構 */
  struct netconn *conn;
	
  /* 錯誤 */
  err_t err;

  union 
  {
	/* do_send時需要的參數 */
    struct netbuf *b;

	/* do_newconn時需要的參數 */
    struct 
	{
      u8_t proto;	//協議類型
    }n;

	/* do_bind和do_connect時需要的參數 */
    struct 
	{
      ip_addr_t *ipaddr;	//IP地址
      u16_t port;			//端口號
    }bc;

	/* do_getaddr時需要的參數 */
    struct 
	{
      ip_addr_t *ipaddr;	//IP地址
      u16_t *port;			//端口號
      u8_t local;			//1本地IP、0遠程IP
    }ad;

	/* do_write時需要的參數 */
    struct 
	{
      const void *dataptr;	//數據
      size_t len;			//長度
      u8_t apiflags;		//標誌位
    }w;

	/* do_recv時需要的參數 */
    struct 
	{
      u32_t len;	//長度
    }r;

	/* do_close時需要的參數 */
    struct 
	{
      u8_t shut;	//關閉方向
    }sd;
  }msg;
};

/* API消息 */
struct api_msg 
{
  void (*function)(struct api_msg_msg *msg);	//回調函數
  struct api_msg_msg msg;    //回調函數參數
};
/* 設置是否爲阻塞態 */
#define SET_NONBLOCKING_CONNECT(conn, val)  do { if(val) { \
  (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
} else { \
  (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
/* 非阻塞態 */
#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)

static err_t do_writemore(struct netconn *conn);
static void do_close_internal(struct netconn *conn);

/* 原始IP接口接收回調函數 */
static u8_t recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
{
  struct pbuf *q;
  struct netbuf *buf;
  struct netconn *conn;

  /* 參數 */
  conn = (struct netconn *)arg;

  /* 接收郵箱有效 */
  if((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) 
  {
	/* 將數據放到netbuf中 */
    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
    if(q != NULL) 
	{
      if(pbuf_copy(q, p) != ERR_OK) 
	  {
        pbuf_free(q);
        q = NULL;
      }
    }

    if(q != NULL) 
	{
      u16_t len;
      buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
      if(buf == NULL) 
	  {
        pbuf_free(q);
        return 0;
      }

      buf->p = q;
      buf->ptr = q;
      ip_addr_copy(buf->addr, *ip_current_src_addr());
      buf->port = pcb->protocol;

      len = q->tot_len;
			
	  /* 發送接收郵箱消息 */
      if(sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) 
	  {
        netbuf_delete(buf);
        return 0;
      } 
	  else 
	  {
		/* 調用連接回調函數 */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
      }
    }
  }

  return 0;
}

/* UDP接口接收回調函數 */
static void recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
  struct netbuf *buf;
  struct netconn *conn;
  u16_t len;

  conn = (struct netconn *)arg;

  /* 郵箱無效 */
  if((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) 
  {
	pbuf_free(p);
	return;
  }

  /* 將數據放到netbuf中 */
  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
  if(buf == NULL) 
  {
	pbuf_free(p);
	return;
  } 
  else 
  {
	buf->p = p;
	buf->ptr = p;
	ip_addr_set(&buf->addr, addr);
	buf->port = port;
  }

  len = p->tot_len;
	
  /* 發送接收郵箱消息 */
  if(sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) 
  {
	netbuf_delete(buf);
	return;
  } 
  else 
  {
	/* 調用連接回調函數 */
	API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
  }
}

/* 接收回調函數 */ 
static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  struct netconn *conn;
  u16_t len;

  conn = (struct netconn *)arg;

  if(conn == NULL) 
  {
    return ERR_VAL;
  }
	
  /* 郵箱無效 */
  if(!sys_mbox_valid(&conn->recvmbox)) 
  {
    if(p != NULL) 
	{
      tcp_recved(pcb, p->tot_len);
      pbuf_free(p);
    }
	
    return ERR_OK;
  }

  /* 設置致命錯誤 */
  NETCONN_SET_SAFE_ERR(conn, err);

  if(p != NULL) 
  {
    len = p->tot_len;
  } 
  else 
  {
    len = 0;
  }

  /* 發送接收郵箱消息 */
  if(sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) 
  {
    return ERR_MEM;
  }
  else 
  {
	/* 調用連接回調函數 */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
  }

  return ERR_OK;
}

/* poll回調函數 */
static err_t poll_tcp(void *arg, struct tcp_pcb *pcb)
{
  struct netconn *conn = (struct netconn *)arg;

  /* 正在發送數據 */
  if(conn->state == NETCONN_WRITE) 
  {
    do_writemore(conn);
  }
  /* 關閉狀態 */
  else if(conn->state == NETCONN_CLOSE) 
  {
    do_close_internal(conn);
  }

  /* 需要再次檢查是否可寫 */
  if(conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) 
  {
    /* 判斷是否可寫 */
    if((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) 
	{
      conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
			
	  /* 調用連接回調函數 */
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
    }
  }

  return ERR_OK;
}

/* 發送回調函數 */
static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct netconn *conn = (struct netconn *)arg;

  /* 正在發送數據 */
  if(conn->state == NETCONN_WRITE) 
  {
    do_writemore(conn);
  } 
  /* 關閉狀態 */
  else if(conn->state == NETCONN_CLOSE) 
  {
    do_close_internal(conn);
  }

  if(conn) 
  {
	/* 需要再次檢查是否可寫 */
    if((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
       (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) 
	{
      conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
			
	  /* 調用連接回調函數 */
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
    }
  }
  
  return ERR_OK;
}

/* 錯誤回調函數 */
static void err_tcp(void *arg, err_t err)
{
  struct netconn *conn;
  enum netconn_state old_state;

  conn = (struct netconn *)arg;

  conn->pcb.tcp = NULL;

  /* 記錄錯誤 */
  conn->last_err = err;

  /* 復位連接 */
  old_state = conn->state;
  conn->state = NETCONN_NONE;

  /* 調用連接回調函數 */
  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);

  /* 發送接收郵箱消息 */
  if(sys_mbox_valid(&conn->recvmbox)) 
  {
    sys_mbox_trypost(&conn->recvmbox, NULL);
  }
  
  /* 發送接受連接郵箱消息 */
  if(sys_mbox_valid(&conn->acceptmbox)) 
  {
    sys_mbox_trypost(&conn->acceptmbox, NULL);
  }

  if((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
     (old_state == NETCONN_CONNECT)) 
  {
	/* 清空阻塞態 */
    int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
    SET_NONBLOCKING_CONNECT(conn, 0);

	/* 阻塞態 */
    if(!was_nonblocking_connect) 
	{
      conn->current_msg->err = err;
      conn->current_msg = NULL;
	  /* 釋放操作完成信號量 */
      sys_sem_signal(&conn->op_completed);
    }
  } 
}

/* 設置TCP回調函數 */
static void setup_tcp(struct netconn *conn)
{
  struct tcp_pcb *pcb;

  pcb = conn->pcb.tcp;
	/* 設置用戶自定義參數 */ 
  tcp_arg(pcb, conn);
	/* 設置接收回調函數 */ 
  tcp_recv(pcb, recv_tcp);
	/* 設置發送成功回調函數 */
  tcp_sent(pcb, sent_tcp);
	/* 設置poll回調函數和週期 */
  tcp_poll(pcb, poll_tcp, 4);
	/* 設置連接錯誤回調函數 */ 
  tcp_err(pcb, err_tcp);
}

/* 接受連接回調函數 */
static err_t accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
  struct netconn *newconn;
  struct netconn *conn = (struct netconn *)arg;

  if(!sys_mbox_valid(&conn->acceptmbox)) 
  {
    return ERR_VAL;
  }

  /* 爲新連接創建一個連接結構體,設置TCP回調函數 */
  newconn = netconn_alloc(conn->type, conn->callback);
  if(newconn == NULL) 
  {
    return ERR_MEM;
  }
  newconn->pcb.tcp = newpcb;
  setup_tcp(newconn);

  newconn->last_err = err;

  /* 發送接受連接消息 */
  if(sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) 
	{
    struct tcp_pcb* pcb = newconn->pcb.tcp;
    tcp_arg(pcb, NULL);
    tcp_recv(pcb, NULL);
    tcp_sent(pcb, NULL);
    tcp_poll(pcb, NULL, 4);
    tcp_err(pcb, NULL);
    newconn->pcb.tcp = NULL;
    sys_mbox_free(&newconn->recvmbox);
    sys_mbox_set_invalid(&newconn->recvmbox);
    netconn_free(newconn);

    return ERR_MEM;
  } 
  else 
  {
		/* 調用連接事件回調函數 */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
  }

  return ERR_OK;
}

/* 創建控制塊 */
static void pcb_new(struct api_msg_msg *msg)
{
  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

	/* 判斷協議類型 */
  switch(NETCONNTYPE_GROUP(msg->conn->type)) 
  {
	/* 原始IP連接 */
	case NETCONN_RAW:
	  /* 創建IP原始接口控制塊 */
	  msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
	  if(msg->conn->pcb.raw == NULL) 
	  {
	    msg->err = ERR_MEM;
		break;
	  }
	  /* IP原始接口設置接收回調函數 */
	  raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
	  break;

	/* UDP */
	case NETCONN_UDP:
	  /* 創建一個UDP控制塊 */
	  msg->conn->pcb.udp = udp_new();
	  if(msg->conn->pcb.udp == NULL) 
	  {
        msg->err = ERR_MEM;
		break;
	  }

	  /* 無校驗UDP */
	  if(msg->conn->type == NETCONN_UDPNOCHKSUM) 
	  {
		udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
	  }
	  /* 設置UDP控制塊回調函數 */
	  udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
	  break;

	/* TCP */
	case NETCONN_TCP:
	  /* 新建TCP控制塊 */
	  msg->conn->pcb.tcp = tcp_new();
	  if(msg->conn->pcb.tcp == NULL) 
	  {
		msg->err = ERR_MEM;
		break;
	  }
	  /* 設置TCP回調函數 */
	  setup_tcp(msg->conn);
	  break;

	/* 不支持 */
	default:
	  msg->err = ERR_VAL;
	  break;
  }
}

/* 創建一個連接PCB */
void do_newconn(struct api_msg_msg *msg)
{
  msg->err = ERR_OK;
	
  /* 控制塊還未創建 */
  if(msg->conn->pcb.tcp == NULL) 
  {
	/* 創建控制塊 */
    pcb_new(msg);
  }

  /* 釋放API調用完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 創建一個連接結構體 */
struct netconn *netconn_alloc(enum netconn_type t, netconn_callback callback)
{
  struct netconn *conn;
  int size;

  /* 爲連接申請內存空間 */
  conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
  if(conn == NULL) 
  {
    return NULL;
  }

  /* 清空最近一個錯誤 */
  conn->last_err = ERR_OK;
  /* 連接類型 */
  conn->type = t;
  /* 清空控制塊指針 */
  conn->pcb.tcp = NULL;

  size = DEFAULT_RAW_RECVMBOX_SIZE;

  /* 創建API調用完成信號量 */
  if(sys_sem_new(&conn->op_completed, 0) != ERR_OK) 
  {
    goto free_and_return;
  }
	
  /* 創建接收郵箱 */
  if(sys_mbox_new(&conn->recvmbox, size) != ERR_OK) 
  {
    sys_sem_free(&conn->op_completed);
    goto free_and_return;
  }

  /* 接受連接郵箱設置爲無效 */ 
  sys_mbox_set_invalid(&conn->acceptmbox);
  /* 不處於任何連接狀態 */
  conn->state = NETCONN_NONE;
  /* 套接字描述符 */
  conn->socket = -1;
  /* 回調函數 */
  conn->callback = callback;
  /* 寫數據緩存不足時,數據暫時封裝在current_msg中,
  write_offset是下一次發送的索引 */
  conn->current_msg = NULL;
  conn->write_offset = 0;
  /* 清空標誌位 */
  conn->flags = 0;
	
  return conn;

free_and_return:
  memp_free(MEMP_NETCONN, conn);
  return NULL;
}

/* 釋放連接結構體 */
void netconn_free(struct netconn *conn)
{
  /* 刪除API調用完成信號量 */
  sys_sem_free(&conn->op_completed);
  /* API信號量設置爲無效 */  
  sys_sem_set_invalid(&conn->op_completed);

  /* 釋放連接內存空間 */
  memp_free(MEMP_NETCONN, conn);
}

/* 刪除接收郵箱和接受連接郵箱 */
static void netconn_drain(struct netconn *conn)
{
  void *mem;
  struct pbuf *p;
	
  /* 接收郵箱有效 */
  if(sys_mbox_valid(&conn->recvmbox)) 
  {
	/* 接收消息並處理 */
    while(sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) 
	{
	  /* TCP連接 */
      if(conn->type == NETCONN_TCP) 
	  {
		/* pbuf處理 */
        if(mem != NULL) 
		{
          p = (struct pbuf *)mem;
          if(conn->pcb.tcp != NULL) 
		  {
			/* 應用層接收對方傳來的數據 */
            tcp_recved(conn->pcb.tcp, p->tot_len);
          }
		  /* 釋放數據pbuf */
          pbuf_free(p);
        }
      }
	  else
      {
		/* 刪除netbuf */
        netbuf_delete((struct netbuf *)mem);
      }
    }
		
	/* 刪除接收郵箱 */
    sys_mbox_free(&conn->recvmbox);
    sys_mbox_set_invalid(&conn->recvmbox);
  }

  /* 接受連接郵箱有效 */
  if(sys_mbox_valid(&conn->acceptmbox)) 
  {
	/* 接收消息並處理 */
    while(sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) 
	{
	  /* 新連接處理 */
      struct netconn *newconn = (struct netconn *)mem;
      if(conn->pcb.tcp != NULL) 
	  {
		/* 接受新連接 */
        tcp_accepted(conn->pcb.tcp);
      }
      /* 刪除每一個新連接接收郵箱 */
      netconn_drain(newconn);
	  /* 刪除TCP控制塊,併發送TCP復位報文 */
      if(newconn->pcb.tcp != NULL) 
	  {
        tcp_abort(newconn->pcb.tcp);
        newconn->pcb.tcp = NULL;
      }
	  /* 釋放連接結構體 */
      netconn_free(newconn);
    }
    /* 刪除接受連接郵箱 */
    sys_mbox_free(&conn->acceptmbox);
    sys_mbox_set_invalid(&conn->acceptmbox);
  }
}

/* 關閉連接 */
static void do_close_internal(struct netconn *conn)
{
  err_t err;
  u8_t shut, shut_rx, shut_tx, close;

  /* 關閉方向 */
  shut = conn->current_msg->msg.sd.shut;
  shut_rx = shut & NETCONN_SHUT_RD;
  shut_tx = shut & NETCONN_SHUT_WR;

  /* 關閉 */
  close = shut == NETCONN_SHUT_RDWR;

  /* 清空用戶自定義參數 */ 
  if(close) 
  {
    tcp_arg(conn->pcb.tcp, NULL);
  }
	
  /* 偵聽狀態,清空接受連接回調函數 */
  if(conn->pcb.tcp->state == LISTEN) 
  {
    tcp_accept(conn->pcb.tcp, NULL);
  } 
  /* 非偵聽狀態 */
  else
  {
    /* 關閉接收方向,清空接收和接受連接回調函數 */
    if(shut_rx) 
	{
      tcp_recv(conn->pcb.tcp, NULL);
      tcp_accept(conn->pcb.tcp, NULL);
    }
		
	/* 關閉發送方向,清空發送回調函數 */
    if(shut_tx) 
	{
      tcp_sent(conn->pcb.tcp, NULL);
    }
		
	/* 清空poll和錯誤回調函數 */
    if(close) 
	{
      tcp_poll(conn->pcb.tcp, NULL, 4);
      tcp_err(conn->pcb.tcp, NULL);
    }
  }
	
  /* 關閉連接 */
  if(close) 
  {
    err = tcp_close(conn->pcb.tcp);
  } 
  else 
  {
    err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
  }
	
  /* 調用連接API回調函數 */
  if(err == ERR_OK) 
	{
    conn->current_msg->err = ERR_OK;
    conn->current_msg = NULL;
    conn->state = NETCONN_NONE;
    if(close) 
	{
      conn->pcb.tcp = NULL;
      API_EVENT(conn, NETCONN_EVT_ERROR, 0);
    }
    if(shut_rx) 
	{
      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    }
    if(shut_tx) 
	{
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
    }
    sys_sem_signal(&conn->op_completed);
  }
  /* 關閉失敗 */
  else 
  {
    tcp_sent(conn->pcb.tcp, sent_tcp);
    tcp_poll(conn->pcb.tcp, poll_tcp, 4);
    tcp_err(conn->pcb.tcp, err_tcp);
    tcp_arg(conn->pcb.tcp, conn);
  }
}

/* 刪除控制塊 */
void do_delconn(struct api_msg_msg *msg)
{
  if((msg->conn->state != NETCONN_NONE) && 
	 (msg->conn->state != NETCONN_LISTEN) && 
     (msg->conn->state != NETCONN_CONNECT)) 
  {
    msg->err = ERR_INPROGRESS;
  } 
  else 
  {
    /* 刪除接收郵箱和接受連接郵箱 */
	netconn_drain(msg->conn);

	/* 判斷連接類型 */
    if(msg->conn->pcb.tcp != NULL) 
	{
      switch(NETCONNTYPE_GROUP(msg->conn->type)) 
	  {
		/* 原始IP連接 */
		case NETCONN_RAW:
		  /* 移除IP原始接口控制塊 */
		  raw_remove(msg->conn->pcb.raw);
		  break;

		/* UDP */
		case NETCONN_UDP:
		  /* 刪除UDP控制塊 */
		  msg->conn->pcb.udp->recv_arg = NULL;
		  udp_remove(msg->conn->pcb.udp);
		  break;

		/* TCP */
		case NETCONN_TCP:
		  msg->conn->state = NETCONN_CLOSE;
		  msg->msg.sd.shut = NETCONN_SHUT_RDWR;
		  msg->conn->current_msg = msg;
		  /* 關閉連接 */
		  do_close_internal(msg->conn);
		  return;
      
		default:
		  break;
      }

      msg->conn->pcb.tcp = NULL;
    }

	/* 調用連接API回調函數 */
    API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
    API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
  }

  /* 釋放操作完成信號量 */
  if(sys_sem_valid(&msg->conn->op_completed)) 
  {
    sys_sem_signal(&msg->conn->op_completed);
  }
}

/* 綁定本地端口 */
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)) 
	  {
	    case NETCONN_RAW:
		  msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
		  break;
			
		case NETCONN_UDP:
		  msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
		  break;
				
		case NETCONN_TCP:
		  msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
		  break;
				
		default:
		  break;
      }
    }
  }

  /* 釋放API調用完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 連接完成 */
static err_t do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
  struct netconn *conn;
  int was_blocking;

  conn = (struct netconn *)arg;
  if(conn == NULL) 
  {
    return ERR_VAL;
  }

  if(conn->current_msg != NULL) 
  {
    conn->current_msg->err = err;
  }
	
  /* 設置TCP回調函數 */
  if((conn->type == NETCONN_TCP) && (err == ERR_OK))
  {
    setup_tcp(conn);
  }
  /* 是否爲阻塞態 */
  was_blocking = !IN_NONBLOCKING_CONNECT(conn);
  /* 清空非阻塞態 */
  SET_NONBLOCKING_CONNECT(conn, 0);
  /* 清空消息 */
  conn->current_msg = NULL;
  /* 清空狀態 */
  conn->state = NETCONN_NONE;
  if(!was_blocking) 
  {
    NETCONN_SET_SAFE_ERR(conn, ERR_OK);
  }
  /* 調用連接API回調函數 */
  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
  /* 阻塞態,釋放操作完成信號量 */
  if(was_blocking) 
  {
    sys_sem_signal(&conn->op_completed);
  }

  return ERR_OK;
}

/* 連接遠程端口 */
void do_connect(struct api_msg_msg *msg)
{
  /* 根據連接類型調用連接 */
  if(msg->conn->pcb.tcp == NULL) 
  {
    msg->err = ERR_CLSD;
  } 
  else 
  {
    switch(NETCONNTYPE_GROUP(msg->conn->type)) 
	{
	  case NETCONN_RAW:
		msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
		break;

	  case NETCONN_UDP:
		msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
		break;

	  case NETCONN_TCP:
		if(msg->conn->state != NETCONN_NONE) 
		{
		  msg->err = ERR_ISCONN;
		} 
		else 
		{
		  setup_tcp(msg->conn);
		  msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, do_connected);
		  if(msg->err == ERR_OK) 
		  {
			u8_t non_blocking = netconn_is_nonblocking(msg->conn);
			msg->conn->state = NETCONN_CONNECT;
			SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
			if(non_blocking) 
			{
			  msg->err = ERR_INPROGRESS;
			} 
			else 
			{
			  msg->conn->current_msg = msg;
			  return;
			}
		  }
		}
		break;
				
	  default:
		break;
    }
  }

  /* 釋放操作完成信號量 */
  sys_sem_signal(&msg->conn->op_completed);
}

/* 斷開連接 */
void do_disconnect(struct api_msg_msg *msg)
{
  if(NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) 
  {
    udp_disconnect(msg->conn->pcb.udp);
    msg->err = ERR_OK;
  } 
  else
  {
    msg->err = ERR_VAL;
  }

  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 偵聽 */
void 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(msg->conn->type == NETCONN_TCP) 
	  {
        if(msg->conn->state == NETCONN_NONE) 
		{
          struct tcp_pcb *lpcb = tcp_listen(msg->conn->pcb.tcp);

		  /* 刪除接收郵箱,創建接受連接郵箱 */
          if(lpcb == NULL) 
		  {
            msg->err = ERR_MEM;
          }
		  else 
		  {
            if(sys_mbox_valid(&msg->conn->recvmbox)) 
			{
              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 
			{
              tcp_close(lpcb);
              msg->conn->pcb.tcp = NULL;
            }
          }
        }
      } 
	  else 
	  {
        msg->err = ERR_ARG;
      }
    }
  }
	
  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 非TCP發送數據 */
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)) 
	  {
		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;

		case NETCONN_UDP:
		  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);
		  }
		  break;
					
		default:
		  break;
      }
    }
  }
	
  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

#if LWIP_TCP
/* TCP接收數據 */
void do_recv(struct api_msg_msg *msg)
{
  msg->err = ERR_OK;
  if(msg->conn->pcb.tcp != NULL) 
  {
    if(msg->conn->type == NETCONN_TCP) 
	{
      u32_t remaining = msg->msg.r.len;
      do 
      {
        u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
        tcp_recved(msg->conn->pcb.tcp, recved);
        remaining -= recved;
      }while(remaining != 0);
    }
  }
	
  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* TCP發送沒發完的數據 */
static err_t do_writemore(struct netconn *conn)
{
  err_t err;
  void *dataptr;
  u16_t len, available;
  u8_t write_finished = 0;
  size_t diff;
  u8_t dontblock = netconn_is_nonblocking(conn) || (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
  u8_t apiflags = conn->current_msg->msg.w.apiflags;

  {
	/* 判斷一次能不能寫完 */
    dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
    diff = conn->current_msg->msg.w.len - conn->write_offset;
    if(diff > 0xffffUL) 
	{
      len = 0xffff;
      apiflags |= TCP_WRITE_FLAG_MORE;
    } 
	else 
	{
      len = (u16_t)diff;
    }
    available = tcp_sndbuf(conn->pcb.tcp);
	/* 寫不完 */
    if(available < len) 
	{
      len = available;
      /* 非阻塞,報錯 */
	  if(dontblock)
	  {
        if(!len) 
		{
          err = ERR_WOULDBLOCK;
          goto err_mem;
        }
      } 
	  /* 阻塞,還有剩餘數據 */
	  else 
	  {
        apiflags |= TCP_WRITE_FLAG_MORE;
      }
    }
    
	/* 組建發送數據 */
	err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
    if((err == ERR_OK) || (err == ERR_MEM)) 
	{
err_mem:
	  /* 非阻塞態,並且沒寫完 */
      if(dontblock && (len < conn->current_msg->msg.w.len)) 
	  {
		/* 調用連接API回調函數 */
        API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
		/* 需要再次檢查是否可寫 */
        conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
      } 
	  /* 發送數據成功 */
	  else if((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) 
	  {
		/* 調用連接API回調函數 */
        API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
      }
    }

	/* 將數據發送出去 */
    if(err == ERR_OK) 
	{
      conn->write_offset += len;
      if((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) 
	  {
        conn->current_msg->msg.w.len = conn->write_offset;
        write_finished = 1;
        conn->write_offset = 0;
      }
      tcp_output(conn->pcb.tcp);
    } 
	else if((err == ERR_MEM) && !dontblock) 
	{
      tcp_output(conn->pcb.tcp);
    } 
	else 
	{
      write_finished = 1;
      conn->current_msg->msg.w.len = 0;
    }
  }
	
  /* 發送完成 */
  if(write_finished) 
  {
    conn->current_msg->err = err;
    conn->current_msg = NULL;
    conn->state = NETCONN_NONE;

    {
	  /* 釋放操作完成信號量 */
      sys_sem_signal(&conn->op_completed);
    }
  }

  return ERR_OK;
}

/* TCP發送數據 */
void do_write(struct api_msg_msg *msg)
{
  if(ERR_IS_FATAL(msg->conn->last_err)) 
  {
    msg->err = msg->conn->last_err;
  } 
  else 
  {
	/* TCP連接 */
    if(msg->conn->type == NETCONN_TCP) 
	{
      if(msg->conn->state != NETCONN_NONE) 
	  {
        msg->err = ERR_INPROGRESS;
      }
	  else if(msg->conn->pcb.tcp != NULL) 
	  {
        msg->conn->state = NETCONN_WRITE;
        msg->conn->current_msg = msg;
        msg->conn->write_offset = 0;
        do_writemore(msg->conn);
        return;
      } 
	  else 
	  {
        msg->err = ERR_CONN;
      }
    } 
	/* 非TCP連接 */
	else 
	{
      msg->err = ERR_VAL;
    }
  }

  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 獲取本地或者遠程IP和端口號 */
void do_getaddr(struct api_msg_msg *msg)
{
  if(msg->conn->pcb.ip != NULL) 
  {
    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : msg->conn->pcb.ip->remote_ip);

    msg->err = ERR_OK;
    switch(NETCONNTYPE_GROUP(msg->conn->type)) 
	{
	  case NETCONN_RAW:
		if(msg->msg.ad.local) 
		{
		  *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
		} 
		else 
		{
		  msg->err = ERR_CONN;
		}
		break;
				
	  case NETCONN_UDP:
		if(msg->msg.ad.local) 
		{
		  *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
		} 
		else 
		{
		  if((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) 
		  {
			msg->err = ERR_CONN;
		  } 
		  else 
		  {
			*(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
		  }
		}
		break;
				
	  case NETCONN_TCP:
		*(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
		break;
			
	  default:
		break;
    }
  } 
  else 
  {
    msg->err = ERR_CONN;
  }

  /* 釋放操作完成信號量 */
  TCPIP_APIMSG_ACK(msg);
}

/* 關閉連接 */
void do_close(struct api_msg_msg *msg)
{
  if((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) 
  {
    msg->err = ERR_INPROGRESS;
  } 
  /* TCP連接 */
  else if((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) 
  {
    if((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) 
	{
      msg->err = ERR_CONN;
    } 
	else 
	{
	  /* 關閉接收方向 */
      if(msg->msg.sd.shut & NETCONN_SHUT_RD) 
	  {
		/* 刪除接收郵箱和接受連接郵箱 */
        netconn_drain(msg->conn);
      }

      msg->conn->state = NETCONN_CLOSE;
      msg->conn->current_msg = msg;
      /* 關閉連接 */
	  do_close_internal(msg->conn);
      return;
    }
  } 
  else
  {
    msg->err = ERR_VAL;
  }
	
  /* 釋放操作完成信號量 */
  sys_sem_signal(&msg->conn->op_completed);
}

最後,看一下應用程序接口

/* 創建一個新的連接並且設置回調函數 */
struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
{
  struct netconn *conn;
  struct api_msg msg;

  /* 創建一個連接結構體 */
  conn = netconn_alloc(t, callback);
  if(conn != NULL) 
  {
	/* 請求創建一個連接PCB */
    msg.function = do_newconn;
    msg.msg.msg.n.proto = proto;
    msg.msg.conn = conn;
    if(TCPIP_APIMSG(&msg) != ERR_OK) 
	{
      sys_sem_free(&conn->op_completed);
      sys_mbox_free(&conn->recvmbox);
      memp_free(MEMP_NETCONN, conn);
      return NULL;
    }
  }

  return conn;
}

/* 刪除連接 */
err_t netconn_delete(struct netconn *conn)
{
  struct api_msg msg;

  if(conn == NULL) 
  {
    return ERR_OK;
  }

  /* 請求刪除控制塊 */
  msg.function = do_delconn;
  msg.msg.conn = conn;
  tcpip_apimsg(&msg);

  /* 釋放連接結構體 */
  netconn_free(conn);

  return ERR_OK;
}

/* 獲取本地或者遠程IP和端口號 */
err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
  struct api_msg msg;
  err_t err;

  /* 請求獲取本地或者遠程IP和端口號 */
  msg.function = do_getaddr;
  msg.msg.conn = conn;
  msg.msg.msg.ad.ipaddr = addr;
  msg.msg.msg.ad.port = port;
  msg.msg.msg.ad.local = local;
  err = TCPIP_APIMSG(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* 綁定本地端口 */
err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
  struct api_msg msg;
  err_t err;

  /* 請求綁定本地端口 */
  msg.function = do_bind;
  msg.msg.conn = conn;
  msg.msg.msg.bc.ipaddr = addr;
  msg.msg.msg.bc.port = port;
  err = TCPIP_APIMSG(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);
  return err;
}

/* 連接遠程端口 */
err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
  struct api_msg msg;
  err_t err;

  /* 請求連接遠程端口 */
  msg.function = do_connect;
  msg.msg.conn = conn;
  msg.msg.msg.bc.ipaddr = addr;
  msg.msg.msg.bc.port = port;
  err = tcpip_apimsg(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* 斷開連接 */
err_t netconn_disconnect(struct netconn *conn)
{
  struct api_msg msg;
  err_t err;

  /* 請求斷開連接 */
  msg.function = do_disconnect;
  msg.msg.conn = conn;
  err = TCPIP_APIMSG(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* 開始偵聽 */
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
  struct api_msg msg;
  err_t err;

  /* 請求偵聽 */
  msg.function = do_listen;
  msg.msg.conn = conn;
  err = TCPIP_APIMSG(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);
  return err;
}

/* 接受連接 */
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn)
{
  struct netconn *newconn;
  err_t err;

  *new_conn = NULL;

  err = conn->last_err;
  if (ERR_IS_FATAL(err)) 
  {
    return err;
  }

  /* 等待連接 */
  sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
	
  /* 調用連接API回調函數 */
  API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
  if(newconn == NULL) 
  {
    NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
    return ERR_ABRT;
  }

  *new_conn = newconn;

  return ERR_OK;
}

/* 接收數據 */
static err_t netconn_recv_data(struct netconn *conn, void **new_buf)
{
  void *buf = NULL;
  u16_t len;
  err_t err;
  struct api_msg msg;

  *new_buf = NULL;

  err = conn->last_err;
  if(ERR_IS_FATAL(err)) 
  {
    return err;
  }

  /* 等待數據 */
  sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);

  /* TCP */
  if(conn->type == NETCONN_TCP)
  {
	/* 自動接收 */
    if(!netconn_get_noautorecved(conn) || (buf == NULL)) 
	{
	  /* 請求接收,更新窗口 */
      msg.function = do_recv;
      msg.msg.conn = conn;
      if(buf != NULL) 
	  {
        msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
      } 
	  else 
	  {
        msg.msg.msg.r.len = 1;
      }

      TCPIP_APIMSG(&msg);
    }

    if(buf == NULL) 
	{
      API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
      NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
      return ERR_CLSD;
    }
    len = ((struct pbuf *)buf)->tot_len;
  }
  /* 非TCP */
  else
  {
    len = netbuf_len((struct netbuf *)buf);
  }
	
  /* 調用連接API回調函數 */
  API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);

  *new_buf = buf;

  return ERR_OK;
}

/* 接收數據 */
err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
{
  return netconn_recv_data(conn, (void **)new_buf);
}

/* 接收數據並將數據封裝到netbuf */
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf)
{
  struct netbuf *buf = NULL;
  err_t err;

  *new_buf = NULL;

  if (conn->type == NETCONN_TCP)
  {
    struct pbuf *p = NULL;

    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
    if(buf == NULL) 
	{
      NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
      return ERR_MEM;
    }

    err = netconn_recv_data(conn, (void **)&p);
    if(err != ERR_OK) 
	{
      memp_free(MEMP_NETBUF, buf);
      return err;
    }

    buf->p = p;
    buf->ptr = p;
    buf->port = 0;
    ip_addr_set_any(&buf->addr);
    *new_buf = buf;

    return ERR_OK;
  }
	
  else
  {
    return netconn_recv_data(conn, (void **)new_buf);
  }
}

/* 更新接收窗口 */
void netconn_recved(struct netconn *conn, u32_t length)
{
  if((conn != NULL) && (conn->type == NETCONN_TCP) && (netconn_get_noautorecved(conn))) 
  {
    struct api_msg msg;

	/* 請求接收,更新窗口 */
    msg.function = do_recv;
    msg.msg.conn = conn;
    msg.msg.msg.r.len = length;
    TCPIP_APIMSG(&msg);
  }
}

/* UDP或RAW發送數據 */
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
{
  if(buf != NULL) 
  {
    ip_addr_set(&buf->addr, addr);
    buf->port = port;

    return netconn_send(conn, buf);
  }

  return ERR_VAL;
}

/* UDP或RAW發送數據 */
err_t netconn_send(struct netconn *conn, struct netbuf *buf)
{
  struct api_msg msg;
  err_t err;
  
  /* 請求發送數據 */
  msg.function = do_send;
  msg.msg.conn = conn;
  msg.msg.msg.b = buf;
  err = TCPIP_APIMSG(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* TCP發送數據 */
err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags, size_t *bytes_written)
{
  struct api_msg msg;
  err_t err;
  u8_t dontblock;

  if(size == 0) 
  {
    return ERR_OK;
  }
	
  dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
  if(dontblock && !bytes_written) 
  {
    return ERR_VAL;
  }

  /* 請求TCP發送數據 */
  msg.function = do_write;
  msg.msg.conn = conn;
  msg.msg.msg.w.dataptr = dataptr;
  msg.msg.msg.w.apiflags = apiflags;
  msg.msg.msg.w.len = size;

  err = TCPIP_APIMSG(&msg);
  if((err == ERR_OK) && (bytes_written != NULL)) 
  {
		/* 非阻塞 */
    if(dontblock) 
	{
      *bytes_written = msg.msg.msg.w.len;
    } 
	/* 阻塞型 */
	else 
	{
      *bytes_written = size;
    }
  }

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* 關閉連接 */
static err_t netconn_close_shutdown(struct netconn *conn, u8_t how)
{
  struct api_msg msg;
  err_t err;

  /* 請求關閉連接 */
  msg.function = do_close;
  msg.msg.conn = conn;
  msg.msg.msg.sd.shut = how;
  err = tcpip_apimsg(&msg);

  NETCONN_SET_SAFE_ERR(conn, err);

  return err;
}

/* 完全關閉連接 */
err_t netconn_close(struct netconn *conn)
{
  return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
}

/* 關閉連接方向 */
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
{
  return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章