📄 api_msg.c
字号:
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); break;#endif /* LWIP_UDP */#if LWIP_TCP case NETCONN_TCP: msg->conn->pcb.tcp = tcp_new(); if(msg->conn->pcb.tcp == NULL) { msg->err = ERR_MEM; break; } setup_tcp(msg->conn); break;#endif /* LWIP_TCP */ default: /* Unsupported netconn type, e.g. protocol disabled */ msg->err = ERR_VAL; break; }}/** * Create a new pcb of a specific type inside a netconn. * Called from netconn_new_with_proto_and_callback. * * @param msg the api_msg_msg describing the connection type */voiddo_newconn(struct api_msg_msg *msg){ msg->err = ERR_OK; if(msg->conn->pcb.tcp == NULL) { pcb_new(msg); } /* Else? This "new" connection already has a PCB allocated. */ /* Is this an error condition? Should it be deleted? */ /* We currently just are happy and return. */ TCPIP_APIMSG_ACK(msg);}/** * Create a new netconn (of a specific type) that has a callback function. * The corresponding pcb is NOT created! * * @param t the type of 'connection' to create (@see enum netconn_type) * @param proto the IP protocol for RAW IP pcbs * @param callback a function to call on status changes (RX available, TX'ed) * @return a newly allocated struct netconn or * NULL on memory error */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;#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) size = DEFAULT_RAW_RECVMBOX_SIZE;#else switch(NETCONNTYPE_GROUP(t)) {#if LWIP_RAW case NETCONN_RAW: size = DEFAULT_RAW_RECVMBOX_SIZE; break;#endif /* LWIP_RAW */#if LWIP_UDP case NETCONN_UDP: size = DEFAULT_UDP_RECVMBOX_SIZE; break;#endif /* LWIP_UDP */#if LWIP_TCP case NETCONN_TCP: size = DEFAULT_TCP_RECVMBOX_SIZE; break;#endif /* LWIP_TCP */ default: LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); break; }#endif if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { memp_free(MEMP_NETCONN, conn); return NULL; } if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { sys_sem_free(&conn->op_completed); memp_free(MEMP_NETCONN, conn); return NULL; }#if LWIP_TCP sys_mbox_set_invalid(&conn->acceptmbox);#endif conn->state = NETCONN_NONE;#if LWIP_SOCKET /* initialize socket to -1 since 0 is a valid socket */ conn->socket = -1;#endif /* LWIP_SOCKET */ conn->callback = callback;#if LWIP_TCP conn->current_msg = NULL; conn->write_offset = 0;#endif /* LWIP_TCP */#if LWIP_SO_RCVTIMEO conn->recv_timeout = 0;#endif /* LWIP_SO_RCVTIMEO */#if LWIP_SO_RCVBUF conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; conn->recv_avail = 0;#endif /* LWIP_SO_RCVBUF */ conn->flags = 0; return conn;}/** * Delete a netconn and all its resources. * The pcb is NOT freed (since we might not be in the right thread context do this). * * @param conn the netconn to free */voidnetconn_free(struct netconn *conn){ LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); LWIP_ASSERT("recvmbox must be deallocated before calling this function", !sys_mbox_valid(&conn->recvmbox));#if LWIP_TCP LWIP_ASSERT("acceptmbox must be deallocated before calling this function", !sys_mbox_valid(&conn->acceptmbox));#endif /* LWIP_TCP */ sys_sem_free(&conn->op_completed); sys_sem_set_invalid(&conn->op_completed); memp_free(MEMP_NETCONN, conn);}/** * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in * these mboxes * * @param conn the netconn to free * @bytes_drained bytes drained from recvmbox * @accepts_drained pending connections drained from acceptmbox */static voidnetconn_drain(struct netconn *conn){ void *mem;#if LWIP_TCP struct pbuf *p;#endif /* LWIP_TCP */ /* This runs in tcpip_thread, so we don't need to lock against rx packets */ /* Delete and drain the recvmbox. */ if (sys_mbox_valid(&conn->recvmbox)) { while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {#if LWIP_TCP if (conn->type == NETCONN_TCP) { if(mem != NULL) { p = (struct pbuf*)mem; /* pcb might be set to NULL already by err_tcp() */ if (conn->pcb.tcp != NULL) { tcp_recved(conn->pcb.tcp, p->tot_len); } pbuf_free(p); } } else#endif /* LWIP_TCP */ { netbuf_delete((struct netbuf *)mem); } } sys_mbox_free(&conn->recvmbox); sys_mbox_set_invalid(&conn->recvmbox); } /* Delete and drain the acceptmbox. */#if LWIP_TCP if (sys_mbox_valid(&conn->acceptmbox)) { while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { struct netconn *newconn = (struct netconn *)mem; /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ /* pcb might be set to NULL already by err_tcp() */ if (conn->pcb.tcp != NULL) { tcp_accepted(conn->pcb.tcp); } /* drain recvmbox */ netconn_drain(newconn); 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); }#endif /* LWIP_TCP */}#if LWIP_TCP/** * Internal helper function to close a TCP netconn: since this sometimes * doesn't work at the first attempt, this function is called from multiple * places. * * @param conn the TCP netconn to close */static voiddo_close_internal(struct netconn *conn){ err_t err; u8_t shut, shut_rx, shut_tx, close; LWIP_ASSERT("invalid conn", (conn != NULL)); LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); shut = conn->current_msg->msg.sd.shut; shut_rx = shut & NETCONN_SHUT_RD; shut_tx = shut & NETCONN_SHUT_WR; /* shutting down both ends is the same as closing */ close = shut == NETCONN_SHUT_RDWR; /* Set back some callback pointers */ if (close) { tcp_arg(conn->pcb.tcp, NULL); } if (conn->pcb.tcp->state == LISTEN) { tcp_accept(conn->pcb.tcp, NULL); } else { /* some callbacks have to be reset if tcp_close is not successful */ if (shut_rx) { tcp_recv(conn->pcb.tcp, NULL); tcp_accept(conn->pcb.tcp, NULL); } if (shut_tx) { tcp_sent(conn->pcb.tcp, NULL); } if (close) { tcp_poll(conn->pcb.tcp, NULL, 4); tcp_err(conn->pcb.tcp, NULL); } } /* Try to close the connection */ if (shut == NETCONN_SHUT_RDWR) { err = tcp_close(conn->pcb.tcp); } else { err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); } if (err == ERR_OK) { /* Closing succeeded */ conn->current_msg->err = ERR_OK; conn->current_msg = NULL; conn->state = NETCONN_NONE; /* Set back some callback pointers as conn is going away */ conn->pcb.tcp = NULL; /* Trigger select() in socket layer. Make sure everybody notices activity on the connection, error first! */ if (close) { 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); } /* wake up the application task */ sys_sem_signal(&conn->op_completed); } else { /* Closing failed, restore some of the callbacks */ /* Closing of listen pcb will never fail! */ LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); 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); /* don't restore recv callback: we don't want to receive any more data */ } /* If closing didn't succeed, we get called again either from poll_tcp or from sent_tcp */}#endif /* LWIP_TCP *//** * Delete the pcb inside a netconn. * Called from netconn_delete. * * @param msg the api_msg_msg pointing to the connection */voiddo_delconn(struct api_msg_msg *msg){ /* @todo TCP: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN) && (msg->conn->state != NETCONN_CONNECT)) { /* this only happens for TCP netconns */ LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else { LWIP_ASSERT("blocking connect in progress", (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); /* Drain and delete mboxes */ netconn_drain(msg->conn); if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) {#if LWIP_RAW case NETCONN_RAW: raw_remove(msg->conn->pcb.raw); break;#endif /* LWIP_RAW */#if LWIP_UDP case NETCONN_UDP: msg->conn->pcb.udp->recv_arg = NULL; udp_remove(msg->conn->pcb.udp); break;#endif /* LWIP_UDP */#if LWIP_TCP case NETCONN_TCP: LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && msg->conn->write_offset == 0); msg->conn->state = NETCONN_CLOSE; msg->msg.sd.shut = NETCONN_SHUT_RDWR; msg->conn->current_msg = msg; do_close_internal(msg->conn); /* API_EVENT is called inside do_close_internal, before releasing the application thread, so we can return at this point! */ return;#endif /* LWIP_TCP */ default: break; } msg->conn->pcb.tcp = NULL; } /* tcp netconns don't come here! */ /* @todo: this lets select make the socket readable and writable, which is wrong! errfd instead? */ 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); }}/** * 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 */voiddo_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);}#if LWIP_TCP/** * TCP callback function if a connection (opened by tcp_connect/do_connect) has * been established (or reset by the remote host). * * @see tcp.h (struct tcp_pcb.connected) for parameters and return values */static err_tdo_connected(void *arg, struct tcp_pcb *pcb, err_t err){ struct netconn *conn; int was_blocking; LWIP_UNUSED_ARG(pcb); conn = (struct netconn *)arg; if (conn == NULL) { return ERR_VAL; } LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); if (conn->current_msg != NULL) { conn->current_msg->err = err; } 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_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); if (was_blocking) { sys_sem_signal(&conn->op_completed); } return ERR_OK;}#endif /* LWIP_TCP *//** * Connect a pcb contained inside a netconn * Called from netconn_connect. * * @param msg the api_msg_msg pointing to the connection and containing * the IP address and port to connect to */voiddo_connect(struct api_msg_msg *msg){ if (msg->conn->pcb.tcp == NULL) { /* This may happen when calling netconn_connect() a second time */ msg->err = ERR_CLSD; } else { switch (NETCONNTYPE_GROUP(msg->conn->type)) {#if LWIP_RAW case NETCONN_RAW: msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); break;#endif /* LWIP_RAW */#if LWIP_UDP case NETCONN_UDP: msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); break;#endif /* LWIP_UDP */#if LWIP_TCP case NETCONN_TCP: /* Prevent connect while doing any other action. */ 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; /* sys_sem_signal() is called from do_connected (or err_tcp()), * when the connection is established! */ return; } } } break;#endif /* LWIP_TCP */ default: LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); break; } } sys_sem_signal(&msg->conn->op_completed);}/** * Connect a pcb contained inside a netconn * Only used for UDP netconns.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -