Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1396086
  • 博文数量: 277
  • 博客积分: 2551
  • 博客等级: 少校
  • 技术积分: 3918
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-21 22:46
文章分类

全部博文(277)

文章存档

2017年(3)

2016年(9)

2015年(65)

2014年(27)

2013年(85)

2012年(61)

2011年(27)

分类: LINUX

2016-08-09 10:21:40

int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,size_t size)
{
struct sock *sk = sock->sk;
struct iovec *iov;
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags;
int mss_now, size_goal;
int err, copied;
long timeo;


lock_sock(sk);
TCP_CHECK_TIMER(sk);


flags = msg->msg_flags;
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);//非阻塞为0


/* Wait for a connection to finish. */
if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
goto out_err;


/* This should be in poll */
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);


mss_now = tcp_send_mss(sk, &size_goal, flags);


/* Ok commence sending. */
iovlen = msg->msg_iovlen;
iov = msg->msg_iov;
copied = 0;


err = -EPIPE;
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
goto out_err;


while (--iovlen >= 0) 
{
int seglen = iov->iov_len;
unsigned char __user *from = iov->iov_base;


iov++;


while (seglen > 0) 
{
int copy = 0;
int max = size_goal;


skb = tcp_write_queue_tail(sk);
if (tcp_send_head(sk)) {
if (skb->ip_summed == CHECKSUM_NONE)
max = mss_now;
copy = max - skb->len;
}


if (copy <= 0) 
{
new_segment:
/* Allocate new segment. If the interface is SG,
* allocate skb fitting to single page.
*/
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;


skb = sk_stream_alloc_skb(sk, select_size(sk),
sk->sk_allocation);
if (!skb)
goto wait_for_memory;


/*
* Check whether we can use HW checksum.
*/
if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
skb->ip_summed = CHECKSUM_PARTIAL;


skb_entail(sk, skb);
copy = size_goal;
max = size_goal;
}


/* Try to append data to the end of skb. */
if (copy > seglen)
copy = seglen;


/* Where to copy to? */
if (skb_tailroom(skb) > 0) {
/* We have some space in skb head. Superb! */
if (copy > skb_tailroom(skb))
copy = skb_tailroom(skb);
if ((err = skb_add_data(skb, from, copy)) != 0)
goto do_fault;
} else {
int merge = 0;
int i = skb_shinfo(skb)->nr_frags;
struct page *page = TCP_PAGE(sk);
int off = TCP_OFF(sk);


if (skb_can_coalesce(skb, i, page, off) &&
   off != PAGE_SIZE) {
/* We can extend the last page
* fragment. */
merge = 1;
} else if (i == MAX_SKB_FRAGS ||
  (!i &&
  !(sk->sk_route_caps & NETIF_F_SG))) {
/* Need to add new fragment and cannot
* do this because interface is non-SG,
* or because all the page slots are
* busy. */
tcp_mark_push(tp, skb);
goto new_segment;
} else if (page) {
if (off == PAGE_SIZE) {
put_page(page);
TCP_PAGE(sk) = page = NULL;
off = 0;
}
} else
off = 0;


if (copy > PAGE_SIZE - off)
copy = PAGE_SIZE - off;


if (!sk_wmem_schedule(sk, copy))
goto wait_for_memory;


if (!page) {
/* Allocate new cache page. */
if (!(page = sk_stream_alloc_page(sk)))
goto wait_for_memory;
}


/* Time to copy data. We are close to
* the end! */
err = skb_copy_to_page(sk, from, skb, page,
      off, copy);
if (err) {
/* If this page was new, give it to the
* socket so it does not get leaked.
*/
if (!TCP_PAGE(sk)) {
TCP_PAGE(sk) = page;
TCP_OFF(sk) = 0;
}
goto do_error;
}


/* Update the skb. */
if (merge) {
skb_shinfo(skb)->frags[i - 1].size +=
copy;
} else {
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
get_page(page);
} else if (off + copy < PAGE_SIZE) {
get_page(page);
TCP_PAGE(sk) = page;
}
}


TCP_OFF(sk) = off + copy;
}


if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;


tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
skb_shinfo(skb)->gso_segs = 0;


from += copy;
copied += copy;
if ((seglen -= copy) == 0 && iovlen == 0)
goto out;


if (skb->len < max || (flags & MSG_OOB))
continue;


if (forced_push(tp)) {
tcp_mark_push(tp, skb);
__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH);
} else if (skb == tcp_send_head(sk))
tcp_push_one(sk, mss_now);
continue;


wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
if (copied)
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);


if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;


mss_now = tcp_send_mss(sk, &size_goal, flags);
}
}


out:
if (copied)
tcp_push(sk, flags, mss_now, tp->nonagle);
TCP_CHECK_TIMER(sk);
release_sock(sk);
return copied;


do_fault:
if (!skb->len) 
{
tcp_unlink_write_queue(skb, sk);
/* It is the one place in all of TCP, except connection
* reset, where we can be unlinking the send_head.
*/
tcp_check_send_head(sk, skb);
sk_wmem_free_skb(sk, skb);
}


do_error:
if (copied)
goto out;
out_err:
err = sk_stream_error(sk, flags, err);
TCP_CHECK_TIMER(sk);
release_sock(sk);
return err;
}

int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
{
struct task_struct *tsk = current;
DEFINE_WAIT(wait);
int done;


do {
int err = sock_error(sk);
if (err)
return err;
if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
return -EPIPE;
if (!*timeo_p)
return -EAGAIN;
if (signal_pending(tsk))
return sock_intr_errno(*timeo_p);


prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
sk->sk_write_pending++;
done = sk_wait_event(sk, timeo_p,
    !sk->sk_err &&
    !((1 << sk->sk_state) &
      ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)));
finish_wait(sk->sk_sleep, &wait);
sk->sk_write_pending--;
} while (!done);
return 0;
}





1、EBADF---找不到对应的文件对象
2、连接并未建立,等待直到进入TCPF_ESTABLISHED或者TCPF_CLOSE_WAIT
   1、ERESTARTSYS ---当前套接字上有事件,调度时间到了
   2、EINTR--当前套接字上有事件,被中断
   3、EPIPE --连接状体没不是TCPF_SYN_SENT | TCPF_SYN_RECV,直接返回
   4、EAGAIN --非阻塞,直接返回


3、检查当前的shutdown标志和连接上是否有错误
   1、EPIPE
4、可能发送缓冲区不足
   发送的字节数为0,需要重新发送
 
5、可能内存不足
   发送的字节数为0,需要重新发送
   
6、返回发送的字节数
   表示发送的字节数
阅读(10696) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~