⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 api_msg.c

📁 lwip-1.4.0
💻 C
📖 第 1 页 / 共 3 页
字号:
/** * @file * Sequential API Internal module * *//* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved.  *  * Redistribution and use in source and binary forms, with or without modification,  * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission.  * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. *  * Author: Adam Dunkels <adam@sics.se> * */#include "lwip/opt.h"#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */#include "lwip/api_msg.h"#include "lwip/ip.h"#include "lwip/udp.h"#include "lwip/tcp.h"#include "lwip/raw.h"#include "lwip/memp.h"#include "lwip/tcpip.h"#include "lwip/igmp.h"#include "lwip/dns.h"#include <string.h>#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)/* forward declarations */#if LWIP_TCPstatic err_t do_writemore(struct netconn *conn);static void do_close_internal(struct netconn *conn);#endif#if LWIP_RAW/** * Receive callback function for RAW netconns. * Doesn't 'eat' the packet, only references it and sends it to * conn->recvmbox * * @see raw.h (struct raw_pcb.recv) for parameters and return value */static u8_trecv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,    ip_addr_t *addr){  struct pbuf *q;  struct netbuf *buf;  struct netconn *conn;  LWIP_UNUSED_ARG(addr);  conn = (struct netconn *)arg;  if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {#if LWIP_SO_RCVBUF    int recv_avail;    SYS_ARCH_GET(conn->recv_avail, recv_avail);    if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {      return 0;    }#endif /* LWIP_SO_RCVBUF */    /* copy the whole packet into new pbufs */    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 {#if LWIP_SO_RCVBUF        SYS_ARCH_INC(conn->recv_avail, len);#endif /* LWIP_SO_RCVBUF */        /* Register event with callback */        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);      }    }  }  return 0; /* do not eat the packet */}#endif /* LWIP_RAW*/#if LWIP_UDP/** * Receive callback function for UDP netconns. * Posts the packet to conn->recvmbox or deletes it on memory error. * * @see udp.h (struct udp_pcb.recv) for parameters */static voidrecv_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;#if LWIP_SO_RCVBUF  int recv_avail;#endif /* LWIP_SO_RCVBUF */  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);  conn = (struct netconn *)arg;  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);#if LWIP_SO_RCVBUF  SYS_ARCH_GET(conn->recv_avail, recv_avail);  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {#else  /* LWIP_SO_RCVBUF */  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {#endif /* LWIP_SO_RCVBUF */    pbuf_free(p);    return;  }  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;#if LWIP_NETBUF_RECVINFO    {      const struct ip_hdr* iphdr = ip_current_header();      /* get the UDP header - always in the first pbuf, ensured by udp_input */      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));#if LWIP_CHECKSUM_ON_COPY      buf->flags = NETBUF_FLAG_DESTADDR;#endif /* LWIP_CHECKSUM_ON_COPY */      ip_addr_set(&buf->toaddr, ip_current_dest_addr());      buf->toport_chksum = udphdr->dest;    }#endif /* LWIP_NETBUF_RECVINFO */  }  len = p->tot_len;  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {    netbuf_delete(buf);    return;  } else {#if LWIP_SO_RCVBUF    SYS_ARCH_INC(conn->recv_avail, len);#endif /* LWIP_SO_RCVBUF */    /* Register event with callback */    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);  }}#endif /* LWIP_UDP */#if LWIP_TCP/** * Receive callback function for TCP netconns. * Posts the packet to conn->recvmbox, but doesn't delete it on errors. * * @see tcp.h (struct tcp_pcb.recv) for parameters and return value */static err_trecv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err){  struct netconn *conn;  u16_t len;  LWIP_UNUSED_ARG(pcb);  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);  conn = (struct netconn *)arg;  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);  if (conn == NULL) {    return ERR_VAL;  }  if (!sys_mbox_valid(&conn->recvmbox)) {    /* recvmbox already deleted */    if (p != NULL) {      tcp_recved(pcb, p->tot_len);      pbuf_free(p);    }    return ERR_OK;  }  /* Unlike for UDP or RAW pcbs, don't check for available space     using recv_avail since that could break the connection     (data is already ACKed) */  /* don't overwrite fatal errors! */  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) {    /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */    return ERR_MEM;  } else {#if LWIP_SO_RCVBUF    SYS_ARCH_INC(conn->recv_avail, len);#endif /* LWIP_SO_RCVBUF */    /* Register event with callback */    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);  }  return ERR_OK;}/** * Poll callback function for TCP netconns. * Wakes up an application thread that waits for a connection to close * or data to be sent. The application thread then takes the * appropriate action to go on. * * Signals the conn->sem. * netconn_close waits for conn->sem if closing failed. * * @see tcp.h (struct tcp_pcb.poll) for parameters and return value */static err_tpoll_tcp(void *arg, struct tcp_pcb *pcb){  struct netconn *conn = (struct netconn *)arg;  LWIP_UNUSED_ARG(pcb);  LWIP_ASSERT("conn != NULL", (conn != NULL));  if (conn->state == NETCONN_WRITE) {    do_writemore(conn);  } else if (conn->state == NETCONN_CLOSE) {    do_close_internal(conn);  }  /* @todo: implement connect timeout here? */  /* Did a nonblocking write fail before? Then check available write-space. */  if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {    /* If the queued byte- or pbuf-count drops below the configured low-water limit,       let select mark this pcb as writable again. */    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;}/** * Sent callback function for TCP netconns. * Signals the conn->sem and calls API_EVENT. * netconn_write waits for conn->sem if send buffer is low. * * @see tcp.h (struct tcp_pcb.sent) for parameters and return value */static err_tsent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len){  struct netconn *conn = (struct netconn *)arg;  LWIP_UNUSED_ARG(pcb);  LWIP_ASSERT("conn != NULL", (conn != NULL));  if (conn->state == NETCONN_WRITE) {    do_writemore(conn);  } else if (conn->state == NETCONN_CLOSE) {    do_close_internal(conn);  }  if (conn) {    /* If the queued byte- or pbuf-count drops below the configured low-water limit,       let select mark this pcb as writable again. */    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;}/** * Error callback function for TCP netconns. * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. * The application thread has then to decide what to do. * * @see tcp.h (struct tcp_pcb.err) for parameters */static voiderr_tcp(void *arg, err_t err){  struct netconn *conn;  enum netconn_state old_state;  SYS_ARCH_DECL_PROTECT(lev);  conn = (struct netconn *)arg;  LWIP_ASSERT("conn != NULL", (conn != NULL));  conn->pcb.tcp = NULL;  /* no check since this is always fatal! */  SYS_ARCH_PROTECT(lev);  conn->last_err = err;  SYS_ARCH_UNPROTECT(lev);  /* reset conn->state now before waking up other threads */  old_state = conn->state;  conn->state = NETCONN_NONE;  /* Notify the user layer about a connection error. Used to signal     select. */  API_EVENT(conn, NETCONN_EVT_ERROR, 0);  /* Try to release selects pending on 'read' or 'write', too.     They will get an error if they actually try to read or write. */  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);  /* pass NULL-message to recvmbox to wake up pending recv */  if (sys_mbox_valid(&conn->recvmbox)) {    /* use trypost to prevent deadlock */    sys_mbox_trypost(&conn->recvmbox, NULL);  }  /* pass NULL-message to acceptmbox to wake up pending accept */  if (sys_mbox_valid(&conn->acceptmbox)) {    /* use trypost to preven deadlock */    sys_mbox_trypost(&conn->acceptmbox, NULL);  }  if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||      (old_state == NETCONN_CONNECT)) {    /* calling do_writemore/do_close_internal is not necessary       since the pcb has already been deleted! */    int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);    SET_NONBLOCKING_CONNECT(conn, 0);    if (!was_nonblocking_connect) {      /* set error return code */      LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);      conn->current_msg->err = err;      conn->current_msg = NULL;      /* wake up the waiting task */      sys_sem_signal(&conn->op_completed);    }  } else {    LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);  }}/** * Setup a tcp_pcb with the correct callback function pointers * and their arguments. * * @param conn the TCP netconn to setup */static voidsetup_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);  tcp_poll(pcb, poll_tcp, 4);  tcp_err(pcb, err_tcp);}/** * Accept callback function for TCP netconns. * Allocates a new netconn and posts that to conn->acceptmbox. * * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value */static err_taccept_function(void *arg, struct tcp_pcb *newpcb, err_t err){  struct netconn *newconn;  struct netconn *conn = (struct netconn *)arg;  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));  if (!sys_mbox_valid(&conn->acceptmbox)) {    LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));    return ERR_VAL;  }  /* We have to set the callback here even though   * the new socket is unknown. conn->socket is marked as -1. */  newconn = netconn_alloc(conn->type, conn->callback);  if (newconn == NULL) {    return ERR_MEM;  }  newconn->pcb.tcp = newpcb;  setup_tcp(newconn);  /* no protection: when creating the pcb, the netconn is not yet known     to the application thread */  newconn->last_err = err;  if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {    /* When returning != ERR_OK, the pcb is aborted in tcp_process(),       so do nothing here! */    newconn->pcb.tcp = NULL;    /* no need to drain since we know the recvmbox is empty. */    sys_mbox_free(&newconn->recvmbox);    sys_mbox_set_invalid(&newconn->recvmbox);    netconn_free(newconn);    return ERR_MEM;  } else {    /* Register event with callback */    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);  }  return ERR_OK;}#endif /* LWIP_TCP *//** * Create a new pcb of a specific type. * Called from do_newconn(). * * @param msg the api_msg_msg describing the connection type * @return msg->conn->err, but the return value is currently ignored */static voidpcb_new(struct api_msg_msg *msg){  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);  /* Allocate a PCB for this connection */  switch(NETCONNTYPE_GROUP(msg->conn->type)) {#if LWIP_RAW  case NETCONN_RAW:    msg->conn->pcb.raw = raw_new(msg->msg.n.proto);    if(msg->conn->pcb.raw == NULL) {      msg->err = ERR_MEM;      break;    }    raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);    break;#endif /* LWIP_RAW */#if LWIP_UDP  case NETCONN_UDP:    msg->conn->pcb.udp = udp_new();    if(msg->conn->pcb.udp == NULL) {      msg->err = ERR_MEM;      break;    }#if LWIP_UDPLITE    if (msg->conn->type==NETCONN_UDPLITE) {      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);    }#endif /* LWIP_UDPLITE */    if (msg->conn->type==NETCONN_UDPNOCHKSUM) {      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -