예제 #1
0
파일: rostcp.c 프로젝트: hoangduit/reactos
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);
}
예제 #2
0
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);
}
예제 #3
0
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);
}
예제 #4
0
파일: tcp.c 프로젝트: rtorrentuser/inadyn
/*
  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);
}
예제 #5
0
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 );
}
예제 #6
0
파일: tcp.c 프로젝트: ebichu/dd-wrt
/* 
	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;
}
예제 #7
0
파일: rostcp.c 프로젝트: RareHare/reactos
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);
}
예제 #8
0
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);
	}
}
예제 #9
0
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 */
    }
}
예제 #10
0
파일: tcp.c 프로젝트: ebichu/dd-wrt
/*
	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;
}
예제 #11
0
void sock_exit( void )
{
    if (_initialized)			// S. Lawson
       tcp_shutdown();
    _initialized = 0;			// S. Lawson
}
예제 #12
0
int server_shutdown(const struct protocol_interface *protocol)
{
	tcp_shutdown();
	return 0;
}
예제 #13
0
파일: tcp.c 프로젝트: rtorrentuser/inadyn
/*
  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;
}
예제 #14
0
void cXVDRSession::Abort()
{
  tcp_shutdown(m_fd);
}
예제 #15
0
파일: api_msg.c 프로젝트: spindance/lwip
/**
 * 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));
}
예제 #16
0
int sserver_shutdown(const struct protocol_interface *protocol)
{
	return tcp_shutdown();
}
예제 #17
0
파일: api_msg.c 프로젝트: comrid1987/jb3500
/**
 * 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 */
}
예제 #18
0
파일: ol_tcp.c 프로젝트: MCRedJay/ling
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;
}