Commit 531669a0 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

[DCCP]: Rewrite dccp_sendmsg to be more like UDP

Based on discussions with Nishida-san.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7690af3f
...@@ -214,197 +214,101 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ...@@ -214,197 +214,101 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto out_release; goto out_release;
} }
EXPORT_SYMBOL(dccp_sendmsg);
int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int nonblock, int flags, int *addr_len) size_t len, int nonblock, int flags, int *addr_len)
{ {
const struct dccp_hdr *dh; const struct dccp_hdr *dh;
int copied = 0;
unsigned long used;
int err;
int target; /* Read at least this many bytes */
long timeo; long timeo;
lock_sock(sk); lock_sock(sk);
err = -ENOTCONN; if (sk->sk_state == DCCP_LISTEN) {
if (sk->sk_state == DCCP_LISTEN) len = -ENOTCONN;
goto out; 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 { do {
struct sk_buff *skb; struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
u32 offset;
/* FIXME */ if (skb == NULL)
#if 0 goto verify_sock_status;
/*
* 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
/* Next get a buffer. */ dh = dccp_hdr(skb);
skb = skb_peek(&sk->sk_receive_queue);
do {
if (!skb)
break;
offset = 0; if (dh->dccph_type == DCCP_PKT_DATA ||
dh = dccp_hdr(skb); dh->dccph_type == DCCP_PKT_DATAACK)
goto found_ok_skb;
if (dh->dccph_type == DCCP_PKT_DATA || if (dh->dccph_type == DCCP_PKT_RESET ||
dh->dccph_type == DCCP_PKT_DATAACK) dh->dccph_type == DCCP_PKT_CLOSE) {
goto found_ok_skb; dccp_pr_debug("found fin ok!\n");
len = 0;
if (dh->dccph_type == DCCP_PKT_RESET || goto found_fin_ok;
dh->dccph_type == DCCP_PKT_CLOSE) { }
dccp_pr_debug("found fin ok!\n"); dccp_pr_debug("packet_type=%s\n",
goto found_fin_ok; dccp_packet_name(dh->dccph_type));
} sk_eat_skb(sk, skb);
dccp_pr_debug("packet_type=%s\n", verify_sock_status:
dccp_packet_name(dh->dccph_type)); if (sock_flag(sk, SOCK_DONE)) {
BUG_TRAP(flags & MSG_PEEK); len = 0;
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)
break; break;
}
if (copied) { if (sk->sk_err) {
if (sk->sk_err || len = sock_error(sk);
sk->sk_state == DCCP_CLOSED || break;
(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 (!timeo) { if (sk->sk_shutdown & RCV_SHUTDOWN) {
copied = -EAGAIN; len = 0;
break; break;
} }
if (signal_pending(current)) { if (sk->sk_state == DCCP_CLOSED) {
copied = sock_intr_errno(timeo); if (!sock_flag(sk, SOCK_DONE)) {
/* This occurs when user tries to read
* from never connected socket.
*/
len = -ENOTCONN;
break; break;
} }
len = 0;
break;
} }
/* FIXME: cleanup_rbuf(sk, copied); */ if (!timeo) {
len = -EAGAIN;
break;
}
if (copied >= target) { if (signal_pending(current)) {
/* Do not sleep, just process backlog. */ len = sock_intr_errno(timeo);
release_sock(sk); break;
lock_sock(sk); }
} else
sk_wait_data(sk, &timeo);
sk_wait_data(sk, &timeo);
continue; continue;
found_ok_skb: found_ok_skb:
/* Ok so how much can we use? */ if (len > skb->len)
used = skb->len - offset; len = skb->len;
if (len < used) else if (len < skb->len)
used = len; msg->msg_flags |= MSG_TRUNC;
if (!(flags & MSG_TRUNC)) { if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
err = skb_copy_datagram_iovec(skb, offset, /* Exception. Bailout! */
msg->msg_iov, used); len = -EFAULT;
if (err) { break;
/* Exception. Bailout! */
if (!copied)
copied = -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: found_fin_ok:
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK))
sk_eat_skb(sk, skb); sk_eat_skb(sk, skb);
break; break;
} while (1);
} 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;
out: out:
release_sock(sk); release_sock(sk);
return err; return len;
recv_urg:
/* FIXME: err = tcp_recv_urg(sk, timeo, msg, len, flags, addr_len); */
goto out;
} }
static int inet_dccp_listen(struct socket *sock, int backlog) static int inet_dccp_listen(struct socket *sock, int backlog)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment