static void tcp_op_accept(struct socket * sock, message * m) { debug_tcp_print("socket num %ld", get_sock_num(sock)); if (!(sock->flags & SOCK_FLG_OP_LISTENING)) { debug_tcp_print("socket %ld does not listen\n", get_sock_num(sock)); sock_reply(sock, EINVAL); return; } /* there is a connection ready to be accepted */ if (sock->recv_head) { int ret; struct tcp_pcb * pcb; pcb = (struct tcp_pcb *) sock->recv_head->data; assert(pcb); ret = tcp_do_accept(sock, m, pcb); sock_reply(sock, ret); if (ret == OK) sock_dequeue_data(sock); return; } debug_tcp_print("no ready connection, suspending\n"); sock_reply(sock, SUSPEND); sock->flags |= SOCK_FLG_OP_PENDING; }
static void udp_op_read(struct socket * sock, message * m, int blk) { debug_udp_print("socket num %ld", get_sock_num(sock)); if (sock->recv_head) { /* data available receive immeditely */ struct udp_recv_data * data; int ret; data = (struct udp_recv_data *) sock->recv_head->data; ret = udp_do_receive(sock, m, (struct udp_pcb *) sock->pcb, data->pbuf, &data->ip, data->port); if (ret > 0) { sock_dequeue_data(sock); sock->recv_data_size -= data->pbuf->tot_len; udp_recv_free(data); } sock_reply(sock, ret); } else if (!blk) sock_reply(sock, EAGAIN); else { /* store the message so we know how to reply */ sock->mess = *m; /* operation is being processes */ sock->flags |= SOCK_FLG_OP_PENDING; debug_udp_print("no data to read, suspending\n"); } }
static int read_from_tcp(struct socket * sock, message * m) { unsigned rem_buf, written = 0; struct pbuf * p; assert(!(sock->flags & SOCK_FLG_OP_LISTENING) && sock->recv_head); rem_buf = m->COUNT; debug_tcp_print("socket num %ld recv buff sz %d", get_sock_num(sock), rem_buf); p = (struct pbuf *)sock->recv_head->data; while (rem_buf) { int err; if (rem_buf >= p->len) { struct pbuf * np; /* * FIXME perhaps copy this to a local buffer and do a * single copy to user then */ #if 0 print_tcp_payload(p->payload, p->len); #endif err = copy_to_user(m->m_source, p->payload, p->len, (cp_grant_id_t) m->IO_GRANT, written); if (err != OK) goto cp_error; sock->recv_data_size -= p->len; debug_tcp_print("whole pbuf copied (%d bytes)", p->len); rem_buf -= p->len; written += p->len; if ((np = p->next)) { pbuf_ref(np); if (pbuf_free(p) != 1) panic("LWIP : pbuf_free != 1"); /* * Mark where we are going to continue if an * error occurs */ sock->recv_head->data = np; p = np; } else { sock_dequeue_data(sock); pbuf_free(p); if (sock->recv_head) p = (struct pbuf *)sock->recv_head->data; else break; } if (rem_buf == 0) break; } else { /* * It must be PBUF_RAM for us to be able to shift the * payload pointer */ assert(p->type == PBUF_RAM); #if 0 print_tcp_payload(p->payload, rem_buf); #endif err = copy_to_user(m->m_source, p->payload, rem_buf, (cp_grant_id_t) m->IO_GRANT, written); if (err != OK) goto cp_error; sock->recv_data_size -= rem_buf; debug_tcp_print("partial pbuf copied (%d bytes)", rem_buf); /* * The whole pbuf hasn't been copied out, we only shift * the payload pointer to remember where to continue * next time */ pbuf_header(p, -rem_buf); written += rem_buf; break; } } debug_tcp_print("%d bytes written to userspace", written); //printf("%d wr, queue %d\n", written, sock->recv_data_size); tcp_recved((struct tcp_pcb *) sock->pcb, written); return written; cp_error: if (written) { debug_tcp_print("%d bytes written to userspace", written); return written; } else return EFAULT; }