全部博文(41)
分类: LINUX
2009-10-09 10:40:52
tcp.c文件的tcp_write函数
978计划工作组
/*
* This routine copies from a user buffer into a socket,
* and starts the transmit system.
*/
static int tcp_write(struct sock *sk, unsigned char *from,
int len, int nonblock, unsigned flags)
{
int copied = 0;
int copy;
int tmp;
struct sk_buff *skb;
struct sk_buff *send_tmp;
unsigned char *buff;
struct proto *prot;
struct device *dev = NULL;
sk->inuse=1;
prot = sk->prot;
while(len > 0)
{
if (sk->err)
{ /* Stop on an error */
release_sock(sk);
if (copied)
return(copied);
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
/*
* First thing we do is make sure that we are established.
*/
if (sk->shutdown & SEND_SHUTDOWN)
{
release_sock(sk);
sk->err = EPIPE;
if (copied)
return(copied);
sk->err = 0;
return(-EPIPE);
}
/*
* Wait for a connection to finish.
*/
while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
{
if (sk->err)
{
release_sock(sk);
if (copied)
return(copied);
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
{
release_sock(sk);
if (copied)
return(copied);
if (sk->err)
{
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
if (sk->keepopen)
{
send_sig(SIGPIPE, current, 0);
}
return(-EPIPE);
}
if (nonblock || copied)
{
release_sock(sk);
if (copied)
return(copied);
return(-EAGAIN);
}
release_sock(sk);
cli();
if (sk->state != TCP_ESTABLISHED &&
sk->state != TCP_CLOSE_WAIT && sk->err == 0)
{
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked)
{
sti();
if (copied)
return(copied);
return(-ERESTARTSYS);
}
}
sk->inuse = 1;
sti();
}
/*
* The following code can result in copy <= if sk->mss is ever
* decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window).
* sk->mtu is constant once SYN processing is finished. I.e. we
* had better not get here until we've seen his SYN and at least one
* valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.)
* But ESTABLISHED should guarantee that. sk->max_window is by definition
* non-decreasing. Note that any ioctl to set user_mss must be done
* before the exchange of SYN's. If the initial ack from the other
* end has a window of 0, max_window and thus mss will both be 0.
*/
/*
* Now we need to check if we have a half built packet.
*/
if ((skb = tcp_dequeue_partial(sk)) != NULL)
{
int hdrlen;
/* IP header + TCP header */
hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
+ sizeof(struct tcphdr);
/* Add more stuff to the end of skb->len */
if (!(flags & MSG_OOB))
{
copy = min(sk->mss - (skb->len - hdrlen), len);
/* FIXME: this is really a bug. */
if (copy <= 0)
{
printk("TCP: **bug**: \"copy\" <= 0!!\n");
copy = 0;
}
memcpy_fromfs(skb->data + skb->len, from, copy);
skb->len += copy;
from += copy;
copied += copy;
len -= copy;
sk->write_seq += copy;
}
if ((skb->len - hdrlen) >= sk->mss ||
(flags & MSG_OOB) || !sk->packets_out)
tcp_send_skb(sk, skb);
else
tcp_enqueue_partial(skb, sk);
continue;
}