全部博文(41)
分类: LINUX
2009-10-09 10:41:53
* We also need to worry about the window.
* If window < 1/2 the maximum window we've seen from this
* host, don't use it. This is sender side
* silly window prevention, as specified in RFC1122.
* (Note that this is different than earlier versions of
* SWS prevention, e.g. RFC813.). What we actually do is
* use the whole MSS. Since the results in the right
* edge of the packet being outside the window, it will
* be queued for later rather than sent.
*/
copy = sk->window_seq - sk->write_seq;
if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
copy = sk->mss;
if (copy > len)
copy = len;
/*
* We should really check the window here also.
*/
send_tmp = NULL;
if (copy < sk->mss && !(flags & MSG_OOB))
{
/*
* We will release the socket in case we sleep here.
*/
release_sock(sk);
/*
* NB: following must be mtu, because mss can be increased.
* mss is always <= mtu
*/
skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL);
sk->inuse = 1;
send_tmp = skb;
}
else
{
/*
* We will release the socket in case we sleep here.
*/
release_sock(sk);
skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL);
sk->inuse = 1;
}
/*
* If we didn't get any memory, we need to sleep.
*/
if (skb == NULL)
{
sk->socket->flags |= SO_NOSPACE;
if (nonblock)
{
release_sock(sk);
if (copied)
return(copied);
return(-EAGAIN);
}
/*
* FIXME: here is another race condition.
*/
tmp = sk->wmem_alloc;
release_sock(sk);
cli();
/*
* Again we will try to avoid it.
*/
if (tmp <= sk->wmem_alloc &&
(sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
&& sk->err == 0)
{
sk->socket->flags &= ~SO_NOSPACE;
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked)
{
sti();
if (copied)
return(copied);
return(-ERESTARTSYS);
}
}
sk->inuse = 1;
sti();
continue;
}
skb->len = 0;
skb->sk = sk;
skb->free = 0;
skb->localroute = sk->localroute|(flags&MSG_DONTROUTE);
buff = skb->data;
/*
* FIXME: we need to optimize this.
* Perhaps some hints here would be good.
*/
tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
if (tmp < 0 )
{
prot->wfree(sk, skb->mem_addr, skb->mem_len);
release_sock(sk);
if (copied)
return(copied);
return(tmp);
}
skb->len += tmp;
skb->dev = dev;
buff += tmp;
skb->h.th =(struct tcphdr *) buff;
tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
if (tmp < 0)
{
prot->wfree(sk, skb->mem_addr, skb->mem_len);
release_sock(sk);
if (copied)
return(copied);
return(tmp);
}
if (flags & MSG_OOB)
{
((struct tcphdr *)buff)->urg = 1;
((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
}
skb->len += tmp;
memcpy_fromfs(buff+tmp, from, copy);
from += copy;
copied += copy;
len -= copy;
skb->len += copy;
skb->free = 0;
sk->write_seq += copy;
if (send_tmp != NULL && sk->packets_out)
{
tcp_enqueue_partial(send_tmp, sk);
continue;
}
tcp_send_skb(sk, skb);
}
sk->err = 0;
/*
* Nagle's rule. Turn Nagle off with TCP_NODELAY for highly
* interactive fast network servers. It's meant to be on and
* it really improves the throughput though not the echo time
* on my slow slip link - Alan
*/
/*
* Avoid possible race on send_tmp - c/o Johannes Stille
*/
if(sk->partial && ((!sk->packets_out)
/* If not nagling we can send on the before case too.. */
|| (sk->nonagle && before(sk->write_seq , sk->window_seq))
))
tcp_send_partial(sk);
release_sock(sk);
return(copied);
}