📄 api_msg.c
字号:
/**
* @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>
/* forward declarations */
#if LWIP_TCP
static 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_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr)
{
struct pbuf *q;
struct netbuf *buf;
struct netconn *conn;
#if LWIP_SO_RCVBUF
int recv_avail;
#endif /* LWIP_SO_RCVBUF */
LWIP_UNUSED_ARG(addr);
conn = arg;
#if LWIP_SO_RCVBUF
SYS_ARCH_GET(conn->recv_avail, recv_avail);
if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
#else /* LWIP_SO_RCVBUF */
if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
#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) {
buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
pbuf_free(q);
return 0;
}
buf->p = q;
buf->ptr = q;
buf->addr = &(((struct ip_hdr*)(q->payload))->src);
buf->port = pcb->protocol;
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
netbuf_delete(buf);
return 0;
} else {
SYS_ARCH_INC(conn->recv_avail, q->tot_len);
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_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 void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port)
{
struct netbuf *buf;
struct netconn *conn;
#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 = 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) || (conn->recvmbox == SYS_MBOX_NULL) ||
((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else /* LWIP_SO_RCVBUF */
if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
pbuf_free(p);
return;
}
buf = memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
pbuf_free(p);
return;
} else {
buf->p = p;
buf->ptr = p;
buf->addr = addr;
buf->port = port;
}
if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
netbuf_delete(buf);
return;
} else {
SYS_ARCH_INC(conn->recv_avail, p->tot_len);
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_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_t
recv_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 = arg;
LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
return ERR_VAL;
}
conn->err = err;
if (p != NULL) {
len = p->tot_len;
SYS_ARCH_INC(conn->recv_avail, len);
} else {
len = 0;
}
if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
return ERR_MEM;
} else {
/* 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_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
struct netconn *conn = 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);
}
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_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct netconn *conn = arg;
LWIP_UNUSED_ARG(pcb);
LWIP_ASSERT("conn != NULL", (conn != NULL));
if (conn->state == NETCONN_WRITE) {
LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
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)) {
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 void
err_tcp(void *arg, err_t err)
{
struct netconn *conn;
conn = arg;
LWIP_ASSERT("conn != NULL", (conn != NULL));
conn->pcb.tcp = NULL;
conn->err = err;
if (conn->recvmbox != SYS_MBOX_NULL) {
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->recvmbox, NULL);
}
if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
conn->state = NETCONN_NONE;
sys_sem_signal(conn->op_completed);
}
if (conn->acceptmbox != SYS_MBOX_NULL) {
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
sys_mbox_post(conn->acceptmbox, NULL);
}
if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
/* calling do_writemore/do_close_internal is not necessary
since the pcb has already been deleted! */
conn->state = NETCONN_NONE;
/* wake up the waiting task */
sys_sem_signal(conn->op_completed);
}
}
/**
* Setup a tcp_pcb with the correct callback function pointers
* and their arguments.
*
* @param conn the TCP netconn to setup
*/
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);
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_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
struct netconn *newconn;
struct netconn *conn;
#if API_MSG_DEBUG
#if TCP_DEBUG
tcp_debug_print_state(newpcb->state);
#endif /* TCP_DEBUG */
#endif /* API_MSG_DEBUG */
conn = (struct netconn *)arg;
LWIP_ERROR("accept_function: invalid conn->acceptmbox",
conn->acceptmbox != SYS_MBOX_NULL, 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);
newconn->err = err;
if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
/* When returning != ERR_OK, the connection is aborted in tcp_process(),
so do nothing here! */
newconn->pcb.tcp = NULL;
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 err_t
pcb_new(struct api_msg_msg *msg)
{
msg->conn->err = ERR_OK;
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->conn->err = ERR_MEM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -