static void LibTCPShutdownCallback(void *arg) { struct lwip_callback_msg *msg = arg; PTCP_PCB pcb = msg->Input.Shutdown.Connection->SocketContext; if (!msg->Input.Shutdown.Connection->SocketContext) { msg->Output.Shutdown.Error = ERR_CLSD; goto done; } /* LwIP makes the (questionable) assumption that SHUTDOWN_RDWR is equivalent to tcp_close(). * This assumption holds even if the shutdown calls are done separately (even through multiple * WinSock shutdown() calls). This assumption means that lwIP has the right to deallocate our * PCB without telling us if we shutdown TX and RX. To avoid these problems, we'll clear the * socket context if we have called shutdown for TX and RX. */ if (msg->Input.Shutdown.shut_rx) { msg->Output.Shutdown.Error = tcp_shutdown(pcb, TRUE, FALSE); } if (msg->Input.Shutdown.shut_tx) { msg->Output.Shutdown.Error = tcp_shutdown(pcb, FALSE, TRUE); } if (!msg->Output.Shutdown.Error) { if (msg->Input.Shutdown.shut_rx) { msg->Input.Shutdown.Connection->ReceiveShutdown = TRUE; msg->Input.Shutdown.Connection->ReceiveShutdownStatus = STATUS_FILE_CLOSED; } if (msg->Input.Shutdown.shut_tx) msg->Input.Shutdown.Connection->SendShutdown = TRUE; if (msg->Input.Shutdown.Connection->ReceiveShutdown && msg->Input.Shutdown.Connection->SendShutdown) { /* The PCB is not ours anymore */ msg->Input.Shutdown.Connection->SocketContext = NULL; tcp_arg(pcb, NULL); TCPFinEventHandler(msg->Input.Shutdown.Connection, ERR_CLSD); } } done: KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); }
void termination_handler(int sig) { PRINT_DEBUG("**********Terminating *******"); //shutdown all module threads in backwards order of startup //rtm_shutdown(); udp_shutdown(); tcp_shutdown(); icmp_shutdown(); ipv4_shutdown(); arp_shutdown(); interface_shutdown(); //TODO finish daemon_shutdown(); //TODO finish switch_shutdown(); //TODO finish //have each module free data & que/sem //TODO finish each of these //rtm_release(); udp_release(); tcp_release(); icmp_release(); ipv4_release(); arp_release(); interface_release(); daemon_release(); switch_release(); PRINT_DEBUG("FIN"); exit(-1); }
static err_t altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) { struct tcp_pcb *pcb; if (conn == NULL) { return ERR_VAL; } ALTCP_TCP_ASSERT_CONN(conn); pcb = (struct tcp_pcb *)conn->state; return tcp_shutdown(pcb, shut_rx, shut_tx); }
/* Resource free. */ int tcp_destruct(tcp_sock_t *p_self) { if (p_self == NULL) { return 0; } if (p_self->initialized == 1) { tcp_shutdown(p_self); } return ip_destruct(&p_self->super); }
static int handler( void ) { if ( wathndlcbrk ) { watcbroke = 1; if (cbrkmode & 0x10 ) outs("\n\rInterrupting\n\r"); return( 1 ); } if (cbrkmode & 0x10 ) outs( msgs[ cbrkmode & 1 ]); if (cbrkmode & 1) return( 1 ); tcp_shutdown(); return( 0 ); }
/* Sets up the object. - ... */ RC_TYPE tcp_do_initialize(TCP_SOCKET *p_self,int is_connect_all) { RC_TYPE rc; int i=0; do { if (!(RC_OK==(rc=tcp_create_socket(p_self)))) break; rc=RC_IP_CONNECT_FAILED; for (i=0;i<p_self->super.server_socket_count;i++) { /*connect*/ if (0 == connect(p_self->super.socket[i],p_self->super.addr_ar[i]->ai_addr, p_self->super.addr_ar[i]->ai_addrlen)) { rc=RC_OK; if (is_connect_all) { p_self->super.sock_index=0; } else { p_self->super.sock_index=i; break; } } } } while(0); if (rc != RC_OK) { tcp_shutdown(p_self); } else { p_self->initialized = TRUE; } return rc; }
static void LibTCPShutdownCallback(void *arg) { struct lwip_callback_msg *msg = arg; PTCP_PCB pcb = msg->Input.Shutdown.Connection->SocketContext; if (!msg->Input.Shutdown.Connection->SocketContext) { msg->Output.Shutdown.Error = ERR_CLSD; goto done; } /* These need to be called separately, otherwise we get a tcp_close() */ if (msg->Input.Shutdown.shut_rx) { msg->Output.Shutdown.Error = tcp_shutdown(pcb, TRUE, FALSE); } if (msg->Input.Shutdown.shut_tx) { msg->Output.Shutdown.Error = tcp_shutdown(pcb, FALSE, TRUE); } if (!msg->Output.Shutdown.Error) { if (msg->Input.Shutdown.shut_rx) { msg->Input.Shutdown.Connection->ReceiveShutdown = TRUE; msg->Input.Shutdown.Connection->ReceiveShutdownStatus = STATUS_FILE_CLOSED; } if (msg->Input.Shutdown.shut_tx) msg->Input.Shutdown.Connection->SendShutdown = TRUE; } done: KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); }
static void tcp_op_shutdown_tx(struct socket * sock) { err_t err; debug_tcp_print("socket num %ld", get_sock_num(sock)); err = tcp_shutdown((struct tcp_pcb *) sock->pcb, 0, 1); switch (err) { case ERR_OK: sock_reply(sock, OK); break; case ERR_CONN: sock_reply(sock, ENOTCONN); break; default: sock_reply(sock, EGENERIC); } }
static void net_tcp_close_connect(struct tls_netconn *conn) { err_t err; if (NULL == conn->pcb.tcp){ return; } /* Set back some callback pointers */ 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 */ tcp_recv(conn->pcb.tcp, NULL); tcp_accept(conn->pcb.tcp, NULL); tcp_sent(conn->pcb.tcp, NULL); tcp_poll(conn->pcb.tcp, NULL, 4); tcp_err(conn->pcb.tcp, NULL); } err = tcp_close(conn->pcb.tcp); if (err) err = tcp_shutdown(conn->pcb.tcp, 1, 1); if (err == ERR_OK) { /* Closing succeeded */ TLS_DBGPRT_INFO("tcp %d closed\n", conn->skt_num); conn->state = NETCONN_STATE_NONE; /* Set back some callback pointers as conn is going away */ conn->pcb.tcp = NULL; net_free_socket(conn); /* Trigger select() in socket layer. Make sure everybody notices activity on the connection, error first! */ } 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, net_tcp_sent_cb); tcp_poll(conn->pcb.tcp, net_tcp_poll_cb, 4); tcp_err(conn->pcb.tcp, net_tcp_err_cb); tcp_arg(conn->pcb.tcp, conn); /* don't restore recv callback: we don't want to receive any more data */ } }
/* Resource free. */ RC_TYPE tcp_destruct(TCP_SOCKET *p_self) { RC_TYPE rc; if (p_self == NULL) { return RC_OK; } super_destruct(&p_self->super); if (!(p_self->is_constructed)) { return RC_OK; } rc=tcp_shutdown(p_self); memset(p_self,0,sizeof(TCP_SOCKET)); return rc; }
void sock_exit( void ) { if (_initialized) // S. Lawson tcp_shutdown(); _initialized = 0; // S. Lawson }
int server_shutdown(const struct protocol_interface *protocol) { tcp_shutdown(); return 0; }
/* Sets up the object. - ... */ int tcp_initialize(tcp_sock_t *p_self, char *msg) { int rc; struct timeval sv; int svlen = sizeof(sv); char host[NI_MAXHOST]; do { local_set_params(p_self); /*call the super */ rc = ip_initialize(&p_self->super); if (rc != 0) { break; } /* local object initalizations */ if (p_self->super.type == TYPE_TCP) { p_self->super.socket = socket(AF_INET, SOCK_STREAM, 0); if (p_self->super.socket == -1) { int code = os_get_socket_error(); logit(LOG_ERR, "Error creating client socket: %s", strerror(code)); rc = RC_IP_SOCKET_CREATE_ERROR; break; } /* Call to socket() OK, allow tcp_shutdown() to run to * prevent socket leak if any of the below calls fail. */ p_self->initialized = 1; if (p_self->super.bound == 1) { if (bind (p_self->super.socket, (struct sockaddr *)&p_self->super.local_addr, sizeof(struct sockaddr_in)) < 0) { int code = os_get_socket_error(); logit(LOG_WARNING, "Failed binding client socket to local address: %s", strerror(code)); rc = RC_IP_SOCKET_BIND_ERROR; break; } } } else { p_self->initialized = 1; /* Allow tcp_shutdown() to run. */ rc = RC_IP_BAD_PARAMETER; } /* set timeouts */ sv.tv_sec = p_self->super.timeout / 1000; /* msec to sec */ sv.tv_usec = (p_self->super.timeout % 1000) * 1000; /* reminder to usec */ setsockopt(p_self->super.socket, SOL_SOCKET, SO_RCVTIMEO, &sv, svlen); setsockopt(p_self->super.socket, SOL_SOCKET, SO_SNDTIMEO, &sv, svlen); if (!getnameinfo (&p_self->super.remote_addr, p_self->super.remote_len, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) { logit(LOG_INFO, "%s, connecting to %s(%s)", msg, p_self->super.p_remote_host_name, host); } if (0 != connect(p_self->super.socket, &p_self->super.remote_addr, p_self->super.remote_len)) { int code = os_get_socket_error(); logit(LOG_WARNING, "Failed connecting to remote server: %s", strerror(code)); rc = RC_IP_CONNECT_FAILED; break; } } while (0); if (rc != 0) { tcp_shutdown(p_self); return rc; } return 0; }
void cXVDRSession::Abort() { tcp_shutdown(m_fd); }
/** * 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)); }
int sserver_shutdown(const struct protocol_interface *protocol) { return tcp_shutdown(); }
/** * 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 (close) { err = tcp_close(conn->pcb.tcp); } else { err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); } if (err == ERR_OK) { /* Closing succeeded */ conn->current_msg->err = ERR_OK; 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 */ 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 */ }
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; }