Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 111522
b: refs/heads/master
c: 146993c
h: refs/heads/master
v: v3
  • Loading branch information
Gerrit Renker committed Sep 4, 2008
1 parent 922b95d commit a180d35
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e7937772d7a2b0127cc4cbc67bc594e139fdaf63
refs/heads/master: 146993cf5174472644ed11bd5fb539f0af8bfa49
3 changes: 2 additions & 1 deletion trunk/net/dccp/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,9 @@ extern void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
extern void dccp_send_sync(struct sock *sk, const u64 seq,
const enum dccp_pkt_type pkt_type);

extern void dccp_write_xmit(struct sock *sk, int block);
extern void dccp_write_xmit(struct sock *sk);
extern void dccp_write_space(struct sock *sk);
extern void dccp_flush_write_queue(struct sock *sk, long *time_budget);

extern void dccp_init_xmit_timers(struct sock *sk);
static inline void dccp_clear_xmit_timers(struct sock *sk)
Expand Down
115 changes: 65 additions & 50 deletions trunk/net/dccp/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,49 +206,29 @@ void dccp_write_space(struct sock *sk)
}

/**
* dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
* dccp_wait_for_ccid - Await CCID send permission
* @sk: socket to wait for
* @skb: current skb to pass on for waiting
* @delay: sleep timeout in milliseconds (> 0)
* This function is called by default when the socket is closed, and
* when a non-zero linger time is set on the socket. For consistency
* @delay: timeout in jiffies
* This is used by CCIDs which need to delay the send time in process context.
*/
static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay)
static int dccp_wait_for_ccid(struct sock *sk, unsigned long delay)
{
struct dccp_sock *dp = dccp_sk(sk);
DEFINE_WAIT(wait);
unsigned long jiffdelay;
int rc;

do {
dccp_pr_debug("delayed send by %d msec\n", delay);
jiffdelay = msecs_to_jiffies(delay);

prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
long remaining;

sk->sk_write_pending++;
release_sock(sk);
schedule_timeout(jiffdelay);
lock_sock(sk);
sk->sk_write_pending--;
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
sk->sk_write_pending++;
release_sock(sk);

if (sk->sk_err)
goto do_error;
if (signal_pending(current))
goto do_interrupted;
remaining = schedule_timeout(delay);

rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
} while ((delay = rc) > 0);
out:
lock_sock(sk);
sk->sk_write_pending--;
finish_wait(sk->sk_sleep, &wait);
return rc;

do_error:
rc = -EPIPE;
goto out;
do_interrupted:
rc = -EINTR;
goto out;

if (signal_pending(current) || sk->sk_err)
return -1;
return remaining;
}

/**
Expand Down Expand Up @@ -311,7 +291,53 @@ static void dccp_xmit_packet(struct sock *sk)
dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC);
}

void dccp_write_xmit(struct sock *sk, int block)
/**
* dccp_flush_write_queue - Drain queue at end of connection
* Since dccp_sendmsg queues packets without waiting for them to be sent, it may
* happen that the TX queue is not empty at the end of a connection. We give the
* HC-sender CCID a grace period of up to @time_budget jiffies. If this function
* returns with a non-empty write queue, it will be purged later.
*/
void dccp_flush_write_queue(struct sock *sk, long *time_budget)
{
struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
long delay, rc;

while (*time_budget > 0 && (skb = skb_peek(&sk->sk_write_queue))) {
rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);

switch (ccid_packet_dequeue_eval(rc)) {
case CCID_PACKET_WILL_DEQUEUE_LATER:
/*
* If the CCID determines when to send, the next sending
* time is unknown or the CCID may not even send again
* (e.g. remote host crashes or lost Ack packets).
*/
DCCP_WARN("CCID did not manage to send all packets\n");
return;
case CCID_PACKET_DELAY:
delay = msecs_to_jiffies(rc);
if (delay > *time_budget)
return;
rc = dccp_wait_for_ccid(sk, delay);
if (rc < 0)
return;
*time_budget -= (delay - rc);
/* check again if we can send now */
break;
case CCID_PACKET_SEND_AT_ONCE:
dccp_xmit_packet(sk);
break;
case CCID_PACKET_ERR:
skb_dequeue(&sk->sk_write_queue);
kfree_skb(skb);
dccp_pr_debug("packet discarded due to err=%ld\n", rc);
}
}
}

void dccp_write_xmit(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
Expand All @@ -323,19 +349,9 @@ void dccp_write_xmit(struct sock *sk, int block)
case CCID_PACKET_WILL_DEQUEUE_LATER:
return;
case CCID_PACKET_DELAY:
if (!block) {
sk_reset_timer(sk, &dp->dccps_xmit_timer,
msecs_to_jiffies(rc)+jiffies);
return;
}
rc = dccp_wait_for_ccid(sk, skb, rc);
if (rc && rc != -EINTR) {
DCCP_BUG("err=%d after dccp_wait_for_ccid", rc);
skb_dequeue(&sk->sk_write_queue);
kfree_skb(skb);
break;
}
/* fall through */
sk_reset_timer(sk, &dp->dccps_xmit_timer,
jiffies + msecs_to_jiffies(rc));
return;
case CCID_PACKET_SEND_AT_ONCE:
dccp_xmit_packet(sk);
break;
Expand Down Expand Up @@ -660,7 +676,6 @@ void dccp_send_close(struct sock *sk, const int active)
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE;

if (active) {
dccp_write_xmit(sk, 1);
dccp_skb_entail(sk, skb);
dccp_transmit_skb(sk, skb_clone(skb, prio));
/*
Expand Down
15 changes: 14 additions & 1 deletion trunk/net/dccp/proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto out_discard;

skb_queue_tail(&sk->sk_write_queue, skb);
dccp_write_xmit(sk,0);
dccp_write_xmit(sk);
out_release:
release_sock(sk);
return rc ? : len;
Expand Down Expand Up @@ -958,9 +958,22 @@ void dccp_close(struct sock *sk, long timeout)
/* Check zero linger _after_ checking for unread data. */
sk->sk_prot->disconnect(sk, 0);
} else if (sk->sk_state != DCCP_CLOSED) {
/*
* Normal connection termination. May need to wait if there are
* still packets in the TX queue that are delayed by the CCID.
*/
dccp_flush_write_queue(sk, &timeout);
dccp_terminate_connection(sk);
}

/*
* Flush write queue. This may be necessary in several cases:
* - we have been closed by the peer but still have application data;
* - abortive termination (unread data or zero linger time),
* - normal termination but queue could not be flushed within time limit
*/
__skb_queue_purge(&sk->sk_write_queue);

sk_stream_wait_close(sk, timeout);

adjudge_to_death:
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/dccp/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ static void dccp_write_xmitlet(unsigned long data)
if (sock_owned_by_user(sk))
sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
else
dccp_write_xmit(sk, 0);
dccp_write_xmit(sk);
bh_unlock_sock(sk);
}

Expand Down

0 comments on commit a180d35

Please sign in to comment.