예제 #1
0
static err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	struct socket * sock = (struct socket *) arg;

	debug_tcp_print("socket num %ld", get_sock_num(sock));

	assert(err == ERR_OK && newpcb);
	assert(sock->flags & SOCK_FLG_OP_LISTENING);

	if (sock->flags & SOCK_FLG_OP_PENDING) {
		int ret;

		ret = tcp_do_accept(sock, &sock->mess, newpcb);
		sock_revive(sock, ret);
		sock->flags &= ~SOCK_FLG_OP_PENDING;
		if (ret == OK) {
			return ERR_OK;
		}
		/* in case of an error fall through */
	}

	/* If we cannot accept rightaway we enqueue the connection for later */

	debug_tcp_print("Enqueue connection sock %ld pcb %p\n",
			get_sock_num(sock), newpcb);
	if (sock_enqueue_data(sock, newpcb, 1) != OK) {
		tcp_abort(newpcb);
		return ERR_ABRT;
	}
	if (sock_select_read_set(sock))
		sock_select_notify(sock);

	return ERR_OK;
}
예제 #2
0
static err_t tcp_connected_callback(void *arg,
				struct tcp_pcb *tpcb,
				__unused err_t err)
{
	struct socket * sock = (struct socket *) arg;

	debug_tcp_print("socket num %ld err %d", get_sock_num(sock), err);

	if (sock->pcb == NULL) {
		if (sock_select_set(sock))
			sock_select_notify(sock);
		return ERR_OK;
	}

	assert((struct tcp_pcb *)sock->pcb == tpcb);

	tcp_sent(tpcb, tcp_sent_callback);
	tcp_recv(tpcb, tcp_recv_callback);
	sock_revive(sock, OK);
	sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_CONNECTING);

	/* revive does the sock_select_notify() for us */

	return ERR_OK;
}
예제 #3
0
static void tcp_error_callback(void *arg, err_t err)
{
	int perr;
	struct socket * sock = (struct socket *) arg;

	debug_tcp_print("socket num %ld err %d", get_sock_num(sock), err);

	switch (err) {
	case ERR_RST:
		perr = ECONNREFUSED;
		break;
	case ERR_CLSD:
		perr = EPIPE;
		break;
	case ERR_CONN:
		perr = ENOTCONN;
		break;
	default:
		perr = EIO;
	}
	
	if (sock->flags & SOCK_FLG_OP_PENDING) {
		sock_revive(sock, perr);
		sock->flags &= ~SOCK_FLG_OP_PENDING;
	} else if (sock_select_set(sock))
		sock_select_notify(sock);
	/*
	 * When error callback is called the tcb either does not exist anymore
	 * or is going to be deallocated soon after. We must not use the pcb
	 * anymore
	 */
	sock->pcb = NULL;
}
예제 #4
0
파일: udp.c 프로젝트: Hooman3/minix
static void udp_recv_callback(void *arg,
			struct udp_pcb *pcb,
			struct pbuf *pbuf,
			ip_addr_t *addr,
			u16_t port)
{
	struct socket * sock = (struct socket *) arg;
	struct udp_recv_data * data;

	debug_udp_print("socket num : %ld addr : %x port : %d\n",
			get_sock_num(sock), (unsigned int) addr->addr, port);

	if (sock->flags & SOCK_FLG_OP_PENDING) {
		/* we are resuming a suspended operation */
		int ret;

		ret = udp_do_receive(sock, &sock->req, pcb, pbuf, addr, port);

		send_req_reply(&sock->req, ret);
		sock->flags &= ~SOCK_FLG_OP_PENDING;

		if (ret > 0) {
			pbuf_free(pbuf);
			return;
		}
	}

	/* Do not enqueue more data than allowed */
	if (sock->recv_data_size > UDP_BUF_SIZE) {
		pbuf_free(pbuf);
		return;
	}

	/*
	 * nobody is waiting for the data or an error occured above, we enqueue
	 * the packet
	 */
	if (!(data = udp_recv_alloc())) {
		pbuf_free(pbuf);
		return;
	}

	data->ip = *addr;
	data->port = port;
	data->pbuf = pbuf;

	if (sock_enqueue_data(sock, data, data->pbuf->tot_len) != OK) {
		udp_recv_free(data);
		return;
	}
	
	/*
	 * We don't need to notify when somebody is already waiting, reviving
	 * read operation will do the trick for us. But we must announce new
	 * data available here.
	 */
	if (sock_select_read_set(sock))
		sock_select_notify(sock);
}
예제 #5
0
static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
	struct socket * sock = (struct socket *) arg;
	struct wbuf * wbuf;
	struct wbuf_chain * wc = (struct wbuf_chain *) sock->buf;
	unsigned snd_buf_len;
	int ret;
	
	debug_tcp_print("socket num %ld", get_sock_num(sock));

	/* an error might have had happen */
	if (sock->pcb == NULL) {
		if (sock_select_set(sock))
			sock_select_notify(sock);
		return ERR_OK;
	}

	assert((struct tcp_pcb *)sock->pcb == tpcb);

	/* operation must have been canceled, do not send any other data */
	if (!sock->flags & SOCK_FLG_OP_PENDING)
		return ERR_OK;

	wbuf = wbuf_ack_sent(sock, len);

	if (wbuf == NULL) {
		debug_tcp_print("all data acked, nothing more to send");
		sock->flags &= ~SOCK_FLG_OP_WRITING;
		if (!(sock->flags & SOCK_FLG_OP_READING))
			sock->flags &= ~SOCK_FLG_OP_PENDING;
		/* no reviving, we must notify. Write and read possible */
		if (sock_select_rw_set(sock))
			sock_select_notify(sock);
		return ERR_OK;
	}

	/* we have just freed some space, write will be accepted */
	if (sock->buf_size < TCP_BUF_SIZE && sock_select_rw_set(sock)) {
		if (!(sock->flags & SOCK_FLG_OP_READING)) {
			sock->flags &= ~SOCK_FLG_OP_PENDING;
			sock_select_notify(sock);
		}
	}

	/*
	 * Check if there is some space for new data, there should be, we just
	 * got a confirmation that some data reached the other end of the
	 * connection
	 */
	snd_buf_len = tcp_sndbuf(tpcb);
	assert(snd_buf_len > 0);
	debug_tcp_print("tcp can accept %d bytes", snd_buf_len);

	if (!wc->unsent) {
		debug_tcp_print("nothing to send");
		return ERR_OK;
	}

	wbuf = wc->unsent;
	while (wbuf) {
		unsigned towrite;
		u8_t flgs = 0;

		towrite = (snd_buf_len < wbuf->rem_len ?
					snd_buf_len : wbuf->rem_len);
		wbuf->rem_len -= towrite;
		debug_tcp_print("data to send, sending %d", towrite);

		if (wbuf->rem_len || wbuf->next)
			flgs = TCP_WRITE_FLAG_MORE;
		ret = tcp_write(tpcb, wbuf->data + wbuf->written + wbuf->unacked,
						towrite, flgs);
		debug_tcp_print("%d bytes to tcp", towrite);

		/* tcp_output() is called once we return from this callback */

		if (ret != ERR_OK) {
			debug_print("tcp_write() failed (%d), written %d"
					, ret, wbuf->written);
			sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_WRITING);
			/* no reviving, we must notify. Write and read possible */
			if (sock_select_rw_set(sock))
				sock_select_notify(sock);
			return ERR_OK;
		}
		
		wbuf->unacked += towrite;
		snd_buf_len -= towrite;
		debug_tcp_print("tcp still accepts %d bytes\n", snd_buf_len);

		if (snd_buf_len) {
			assert(wbuf->rem_len == 0);
			wbuf = wbuf->next;
			wc->unsent = wbuf;
			if (wbuf)
				debug_tcp_print("unsent %p remains %d\n",
						wbuf, wbuf->rem_len);
			else {
				debug_tcp_print("nothing to send");
			}
		} else
			break;
	}

	return ERR_OK;
}
예제 #6
0
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;
}