static int tcp_do_accept(struct socket * listen_sock, message * m, struct tcp_pcb * newpcb) { struct socket * newsock; unsigned sock_num; int ret; debug_tcp_print("socket num %ld", get_sock_num(listen_sock)); if ((ret = copy_from_user(m->m_source, &sock_num, sizeof(sock_num), (cp_grant_id_t) m->IO_GRANT, 0)) != OK) return EFAULT; if (!is_valid_sock_num(sock_num)) return EBADF; newsock = get_sock(sock_num); assert(newsock->pcb); /* because of previous open() */ /* we really want to forget about this socket */ tcp_err((struct tcp_pcb *)newsock->pcb, NULL); tcp_abandon((struct tcp_pcb *)newsock->pcb, 0); tcp_arg(newpcb, newsock); tcp_err(newpcb, tcp_error_callback); tcp_sent(newpcb, tcp_sent_callback); tcp_recv(newpcb, tcp_recv_callback); tcp_nagle_disable(newpcb); tcp_accepted(((struct tcp_pcb *)(listen_sock->pcb))); newsock->pcb = newpcb; debug_tcp_print("Accepted new connection using socket %d\n", sock_num); return OK; }
static int tcp_op_open(struct socket * sock, __unused message * m) { struct tcp_pcb * pcb; int ret; debug_tcp_print("socket num %ld", get_sock_num(sock)); if (!(pcb = tcp_new())) return ENOMEM; debug_tcp_print("new tcp pcb %p\n", pcb); if ((ret = tcp_fill_new_socket(sock, pcb) != OK)) tcp_abandon(pcb, 0); return ret; }
/****************************************************************************** * FunctionName : espconn_server_poll * Description : The poll function is called every 3nd second. * If there has been no data sent (which resets the retries) in 3 seconds, close. * If the last portion of a file has not been sent in 3 seconds, close. * * This could be increased, but we don't want to waste resources for bad connections. * Parameters : arg -- Additional argument to pass to the callback function * pcb -- The connection pcb for which data has been acknowledged * Returns : ERR_OK: try to send some data by calling tcp_output * ERR_ABRT: if you have called tcp_abort from within the function! *******************************************************************************/ static err_t ICACHE_FLASH_ATTR espconn_server_poll(void *arg, struct tcp_pcb *pcb) { espconn_msg *pspoll_cb = arg; /*exception calling abandon the connection for send a RST frame*/ if (arg == NULL) { tcp_abandon(pcb, 0); tcp_poll(pcb, NULL, 0); return ERR_OK; } espconn_printf("espconn_server_poll %d %d\n", pspoll_cb->pcommon.recv_check, pcb->state); pspoll_cb->pcommon.pcb = pcb; if (pcb->state == ESTABLISHED) { pspoll_cb->pcommon.recv_check++; if (pspoll_cb->pcommon.timeout != 0){/*no data sent in one active connection's set timeout, close.*/ if (pspoll_cb->pcommon.recv_check >= pspoll_cb->pcommon.timeout) { pspoll_cb->pcommon.recv_check = 0; espconn_server_close(pspoll_cb, pcb,0); } } else { espconn_msg *ptime_msg = pserver_list; while (ptime_msg != NULL) { if (ptime_msg->pespconn == pspoll_cb->preverse){ if (ptime_msg->pcommon.timeout != 0){/*no data sent in server's set timeout, close.*/ if (pspoll_cb->pcommon.recv_check >= ptime_msg->pcommon.timeout){ pspoll_cb->pcommon.recv_check = 0; espconn_server_close(pspoll_cb, pcb,0); } } else {/*don't close for ever*/ pspoll_cb->pcommon.recv_check = 0; } break; } ptime_msg = ptime_msg->pnext; } } } else { espconn_server_close(pspoll_cb, pcb,0); } return ERR_OK; }
/****************************************************************************** * FunctionName : espconn_client_poll * Description : The poll function is called every 2nd second. * If there has been no data sent (which resets the retries) in 8 seconds, close. * If the last portion of a file has not been sent in 2 seconds, close. * * This could be increased, but we don't want to waste resources for bad connections. * Parameters : arg -- Additional argument to pass to the callback function * pcb -- The connection pcb for which data has been acknowledged * Returns : ERR_OK: try to send some data by calling tcp_output * ERR_ABRT: if you have called tcp_abort from within the function! *******************************************************************************/ static err_t ICACHE_FLASH_ATTR espconn_client_poll(void *arg, struct tcp_pcb *pcb) { espconn_msg *ppoll_cb = arg; espconn_printf("espconn_client_poll pcb %p %p %d\n", pcb, arg, pcb->state); if (arg == NULL) { tcp_abandon(pcb, 0); tcp_poll(pcb, NULL, 0); return ERR_OK; } ppoll_cb->pcommon.pcb = pcb; if (pcb->state == ESTABLISHED) { } else { tcp_poll(pcb, espconn_client_poll, 0); espconn_client_close(ppoll_cb->pespconn, pcb); } return ERR_OK; }
/****************************************************************************** * FunctionName : espconn_server_poll * Description : The poll function is called every 3nd second. * If there has been no data sent (which resets the retries) in 3 seconds, close. * If the last portion of a file has not been sent in 3 seconds, close. * * This could be increased, but we don't want to waste resources for bad connections. * Parameters : arg -- Additional argument to pass to the callback function * pcb -- The connection pcb for which data has been acknowledged * Returns : ERR_OK: try to send some data by calling tcp_output * ERR_ABRT: if you have called tcp_abort from within the function! *******************************************************************************/ static err_t ICACHE_FLASH_ATTR espconn_server_poll(void *arg, struct tcp_pcb *pcb) { espconn_msg *pspoll_cb = arg; if (arg == NULL) { tcp_abandon(pcb, 0); tcp_poll(pcb, NULL, 0); return ERR_OK; } espconn_printf("espconn_server_poll %d %d\n", pspoll_cb->pcommon.recv_check, pcb->state); pspoll_cb->pcommon.pcb = pcb; if (pcb->state == ESTABLISHED) { pspoll_cb->pcommon.recv_check++; if (pspoll_cb->pcommon.timeout != 0){ if (pspoll_cb->pcommon.recv_check == pspoll_cb->pcommon.timeout) { pspoll_cb->pcommon.recv_check = 0; espconn_server_close(pspoll_cb, pcb); } } else if (link_timer != 0){ if (pspoll_cb->pcommon.recv_check == link_timer) { pspoll_cb->pcommon.recv_check = 0; espconn_server_close(pspoll_cb, pcb); } } else { if (pspoll_cb->pcommon.recv_check == 0x0a) { pspoll_cb->pcommon.recv_check = 0; espconn_server_close(pspoll_cb, pcb); } } } else { espconn_server_close(pspoll_cb, pcb); } return ERR_OK; }
/** * Aborts the connection by sending a RST (reset) segment to the remote * host. The pcb is deallocated. This function never fails. * * ATTENTION: When calling this from one of the TCP callbacks, make * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise * or you will risk accessing deallocated memory or memory leaks! * * @param pcb the tcp pcb to abort */ void tcp_abort(struct tcp_pcb *pcb) { tcp_abandon(pcb, 1); }
static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *pbuf, err_t err) { int ret, enqueued = 0; struct socket * sock = (struct socket *) arg; debug_tcp_print("socket num %ld", get_sock_num(sock)); if (sock->pcb == NULL) { if (sock_select_set(sock)) sock_select_notify(sock); return ERR_OK; } assert((struct tcp_pcb *) sock->pcb == tpcb); if (err != ERR_OK) return ERR_OK; if (!pbuf) { debug_tcp_print("tcp stream closed on the remote side"); // sock->flags |= SOCK_FLG_CLOSED; /* wake up the reader and report EOF */ if (sock->flags & SOCK_FLG_OP_PENDING && sock->flags & SOCK_FLG_OP_READING && !(sock->flags & SOCK_FLG_OP_REVIVING)) { sock_revive(sock, 0); sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_READING); } #if 0 /* if there are any undelivered data, drop them */ sock_dequeue_data_all(sock, tcp_recv_free); tcp_abandon(tpcb, 0); sock->pcb = NULL; #endif return ERR_OK; } /* * FIXME we always enqueue the data first. If the head is empty and read * operation is pending we could try to deliver immeditaly without * enqueueing */ if (enqueue_rcv_data(sock, pbuf) == ERR_OK) enqueued = 1; /* * Deliver data if there is a pending read operation, otherwise notify * select if the socket is being monitored */ if (sock->flags & SOCK_FLG_OP_PENDING) { if (sock->flags & SOCK_FLG_OP_READING) { ret = read_from_tcp(sock, &sock->mess); debug_tcp_print("read op finished"); sock_revive(sock, ret); sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_READING); } } else if (!(sock->flags & SOCK_FLG_OP_WRITING) && sock_select_rw_set(sock)) sock_select_notify(sock); /* perhaps we have deliverd some data to user, try to enqueue again */ if (!enqueued) { return enqueue_rcv_data(sock, pbuf); } else return ERR_OK; }
/** * Called by tcp_input() when a segment arrives for a listening * connection (from tcp_input()). * * @param pcb the tcp_pcb_listen for which a segment arrived * @return ERR_OK if the segment was processed * another err_t on error * * @note the return value is not (yet?) used in tcp_input() * @note the segment which arrived is saved in global variables, therefore only the pcb * involved is passed as a parameter to this function */ static err_t tcp_listen_input(struct tcp_pcb_listen *pcb) { struct tcp_pcb *npcb; err_t rc; /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); tcp_rst(ackno + 1, seqno + tcplen, &(iphdr->dest), &(iphdr->src), tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG if (pcb->accepts_pending >= pcb->backlog) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); return ERR_ABRT; } #endif /* TCP_LISTEN_BACKLOG */ npcb = tcp_alloc(pcb->prio); /* If a new PCB could not be created (probably due to lack of memory), we don't do anything, but rely on the sender will retransmit the SYN at a time when we have more memory available. */ if (npcb == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); TCP_STATS_INC(tcp.memerr); return ERR_MEM; } #if TCP_LISTEN_BACKLOG pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); npcb->local_port = pcb->local_port; ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; npcb->rcv_ann_right_edge = npcb->rcv_nxt; npcb->snd_wnd = tcphdr->wnd; npcb->ssthresh = npcb->snd_wnd; npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ npcb->callback_arg = pcb->callback_arg; #if LWIP_CALLBACK_API npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ /* inherit socket options */ npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG(&tcp_active_pcbs, npcb); /* Parse any options in the SYN. */ tcp_parseopt(npcb); #if TCP_CALCULATE_EFF_SEND_MSS npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); /* Send a SYN|ACK together with the MSS option. */ rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS #if LWIP_TCP_TIMESTAMPS /* and maybe include the TIMESTAMP option */ | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0) #endif ); if (rc != ERR_OK) { tcp_abandon(npcb, 0); return rc; } return tcp_output(npcb); } return ERR_OK; }