diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/proto.c | 214 |
1 files changed, 59 insertions, 155 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 46dd489f66c..ed0bf58c8ae 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -214,197 +214,101 @@ out_discard: goto out_release; } -EXPORT_SYMBOL(dccp_sendmsg); - int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len) { const struct dccp_hdr *dh; - int copied = 0; - unsigned long used; - int err; - int target; /* Read at least this many bytes */ long timeo; lock_sock(sk); - err = -ENOTCONN; - if (sk->sk_state == DCCP_LISTEN) + if (sk->sk_state == DCCP_LISTEN) { + len = -ENOTCONN; goto out; - - timeo = sock_rcvtimeo(sk, nonblock); - - /* Urgent data needs to be handled specially. */ - if (flags & MSG_OOB) - goto recv_urg; - - /* FIXME */ -#if 0 - seq = &tp->copied_seq; - if (flags & MSG_PEEK) { - peek_seq = tp->copied_seq; - seq = &peek_seq; } -#endif - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); + timeo = sock_rcvtimeo(sk, nonblock); do { - struct sk_buff *skb; - u32 offset; + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); - /* FIXME */ -#if 0 - /* - * Are we at urgent data? Stop if we have read anything or - * have SIGURG pending. - */ - if (tp->urg_data && tp->urg_seq == *seq) { - if (copied) - break; - if (signal_pending(current)) { - copied = timeo ? sock_intr_errno(timeo) : - -EAGAIN; - break; - } - } -#endif + if (skb == NULL) + goto verify_sock_status; - /* Next get a buffer. */ - - skb = skb_peek(&sk->sk_receive_queue); - do { - if (!skb) - break; + dh = dccp_hdr(skb); - offset = 0; - dh = dccp_hdr(skb); + if (dh->dccph_type == DCCP_PKT_DATA || + dh->dccph_type == DCCP_PKT_DATAACK) + goto found_ok_skb; - if (dh->dccph_type == DCCP_PKT_DATA || - dh->dccph_type == DCCP_PKT_DATAACK) - goto found_ok_skb; - - if (dh->dccph_type == DCCP_PKT_RESET || - dh->dccph_type == DCCP_PKT_CLOSE) { - dccp_pr_debug("found fin ok!\n"); - goto found_fin_ok; - } - dccp_pr_debug("packet_type=%s\n", - dccp_packet_name(dh->dccph_type)); - BUG_TRAP(flags & MSG_PEEK); - skb = skb->next; - } while (skb != (struct sk_buff *)&sk->sk_receive_queue); - - /* Well, if we have backlog, try to process it now yet. */ - if (copied >= target && !sk->sk_backlog.tail) + if (dh->dccph_type == DCCP_PKT_RESET || + dh->dccph_type == DCCP_PKT_CLOSE) { + dccp_pr_debug("found fin ok!\n"); + len = 0; + goto found_fin_ok; + } + dccp_pr_debug("packet_type=%s\n", + dccp_packet_name(dh->dccph_type)); + sk_eat_skb(sk, skb); +verify_sock_status: + if (sock_flag(sk, SOCK_DONE)) { + len = 0; break; + } - if (copied) { - if (sk->sk_err || - sk->sk_state == DCCP_CLOSED || - (sk->sk_shutdown & RCV_SHUTDOWN) || - !timeo || - signal_pending(current) || - (flags & MSG_PEEK)) - break; - } else { - if (sock_flag(sk, SOCK_DONE)) - break; - - if (sk->sk_err) { - copied = sock_error(sk); - break; - } - - if (sk->sk_shutdown & RCV_SHUTDOWN) - break; - - if (sk->sk_state == DCCP_CLOSED) { - if (!sock_flag(sk, SOCK_DONE)) { - /* This occurs when user tries to read - * from never connected socket. - */ - copied = -ENOTCONN; - break; - } - break; - } + if (sk->sk_err) { + len = sock_error(sk); + break; + } - if (!timeo) { - copied = -EAGAIN; - break; - } + if (sk->sk_shutdown & RCV_SHUTDOWN) { + len = 0; + break; + } - if (signal_pending(current)) { - copied = sock_intr_errno(timeo); + if (sk->sk_state == DCCP_CLOSED) { + if (!sock_flag(sk, SOCK_DONE)) { + /* This occurs when user tries to read + * from never connected socket. + */ + len = -ENOTCONN; break; } + len = 0; + break; } - /* FIXME: cleanup_rbuf(sk, copied); */ + if (!timeo) { + len = -EAGAIN; + break; + } - if (copied >= target) { - /* Do not sleep, just process backlog. */ - release_sock(sk); - lock_sock(sk); - } else - sk_wait_data(sk, &timeo); + if (signal_pending(current)) { + len = sock_intr_errno(timeo); + break; + } + sk_wait_data(sk, &timeo); continue; - found_ok_skb: - /* Ok so how much can we use? */ - used = skb->len - offset; - if (len < used) - used = len; - - if (!(flags & MSG_TRUNC)) { - err = skb_copy_datagram_iovec(skb, offset, - msg->msg_iov, used); - if (err) { - /* Exception. Bailout! */ - if (!copied) - copied = -EFAULT; - break; - } + if (len > skb->len) + len = skb->len; + else if (len < skb->len) + msg->msg_flags |= MSG_TRUNC; + + if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) { + /* Exception. Bailout! */ + len = -EFAULT; + break; } - - copied += used; - len -= used; - - /* FIXME: tcp_rcv_space_adjust(sk); */ - -//skip_copy: - if (used + offset < skb->len) - continue; - - if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); - continue; found_fin_ok: if (!(flags & MSG_PEEK)) sk_eat_skb(sk, skb); break; - - } while (len > 0); - - /* According to UNIX98, msg_name/msg_namelen are ignored - * on connected socket. I was just happy when found this 8) --ANK - */ - - /* Clean up data we have read: This will do ACK frames. */ - /* FIXME: cleanup_rbuf(sk, copied); */ - - release_sock(sk); - return copied; - + } while (1); out: release_sock(sk); - return err; - -recv_urg: - /* FIXME: err = tcp_recv_urg(sk, timeo, msg, len, flags, addr_len); */ - goto out; + return len; } static int inet_dccp_listen(struct socket *sock, int backlog) |