/*
* Handle reading urgent data. BSD has very simple semantics for
* this, no blocking and very strange errors 8)
*/staticinttcp_recv_urg(structsock*sk,structmsghdr*msg,int len,int flags){structtcp_sock*tp =tcp_sk(sk);/* No URG data to read. */if(sock_flag(sk, SOCK_URGINLINE)||!tp->urg_data ||
tp->urg_data == TCP_URG_READ)return-EINVAL;/* Yes this is right ! */if(sk->sk_state == TCP_CLOSE &&!sock_flag(sk, SOCK_DONE))return-ENOTCONN;if(tp->urg_data & TCP_URG_VALID){int err =0;char c = tp->urg_data;if(!(flags & MSG_PEEK))
tp->urg_data = TCP_URG_READ;/* Read urgent data. */
msg->msg_flags |= MSG_OOB;if(len >0){if(!(flags & MSG_TRUNC))
err =memcpy_toiovec(msg->msg_iov,&c,1);
len =1;}else
msg->msg_flags |= MSG_TRUNC;return err ?-EFAULT : len;}if(sk->sk_state == TCP_CLOSE ||(sk->sk_shutdown & RCV_SHUTDOWN))return0;/* Fixed the recv(..., MSG_OOB) behaviour. BSD docs and
* the available implementations agree in this case:
* this call should never block, independent of the
* blocking state of the socket.
* Mike
*/return-EAGAIN;}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">
/*
* This routine copies from a sock struct into the user buffer.
*
* Technical note: in 2.3 we work on _locked_ socket, so that
* tricks with *seq access order and skb->users are not required.
* Probably, code can be easily improved even more.
*/inttcp_recvmsg(structkiocb*iocb,structsock*sk,structmsghdr*msg,
size_t len,int nonblock,int flags,int*addr_len){structtcp_sock*tp =tcp_sk(sk);int copied =0;
u32 peek_seq;
u32 *seq;unsignedlong used;int err;int target;/* Read at least this many bytes */long timeo;structtask_struct*user_recv =NULL;int copied_early =0;structsk_buff*skb;
u32 urg_hole =0;lock_sock(sk);
err =-ENOTCONN;if(sk->sk_state == TCP_LISTEN)goto out;
timeo =sock_rcvtimeo(sk, nonblock);/* Urgent data needs to be handled specially. */if(flags & MSG_OOB)goto recv_urg;
seq =&tp->copied_seq;if(flags & MSG_PEEK){
peek_seq = tp->copied_seq;
seq =&peek_seq;}
target =sock_rcvlowat(sk, flags & MSG_WAITALL, len);#ifdefCONFIG_NET_DMA
tp->ucopy.dma_chan =NULL;preempt_disable();
skb =skb_peek_tail(&sk->sk_receive_queue);{int available =0;if(skb)
available =TCP_SKB_CB(skb)->seq + skb->len -(*seq);if((available < target)&&(len > sysctl_tcp_dma_copybreak)&&!(flags & MSG_PEEK)&&!sysctl_tcp_low_latency &&dma_find_channel(DMA_MEMCPY)){preempt_enable_no_resched();
tp->ucopy.pinned_list =dma_pin_iovec_pages(msg->msg_iov, len);}else{preempt_enable_no_resched();}}#endifdo{
u32 offset;/* 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;}}/* Next get a buffer. */skb_queue_walk(&sk->sk_receive_queue, skb){/* Now that we have two receive queues this
* shouldn't happen.
*/if(WARN(before(*seq,TCP_SKB_CB(skb)->seq),"recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n",*seq,TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
flags))break;
offset =*seq -TCP_SKB_CB(skb)->seq;if(tcp_hdr(skb)->syn)
offset--;if(offset < skb->len)goto found_ok_skb;if(tcp_hdr(skb)->fin)goto found_fin_ok;WARN(!(flags & MSG_PEEK),"recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n",*seq,TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags);}/* Well, if we have backlog, try to process it now yet. */if(copied >= target &&!sk->sk_backlog.tail)break;if(copied){if(sk->sk_err ||
sk->sk_state == TCP_CLOSE ||(sk->sk_shutdown & RCV_SHUTDOWN)||!timeo ||signal_pending(current))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 == TCP_CLOSE){if(!sock_flag(sk, SOCK_DONE)){/* This occurs when user tries to read
* from never connected socket.
*/
copied =-ENOTCONN;break;}break;}if(!timeo){
copied =-EAGAIN;break;}if(signal_pending(current)){
copied =sock_intr_errno(timeo);break;}}tcp_cleanup_rbuf(sk, copied);if(!sysctl_tcp_low_latency && tp->ucopy.task == user_recv){/* Install new reader */if(!user_recv &&!(flags &(MSG_TRUNC | MSG_PEEK))){
user_recv = current;
tp->ucopy.task = user_recv;
tp->ucopy.iov = msg->msg_iov;}
tp->ucopy.len = len;WARN_ON(tp->copied_seq != tp->rcv_nxt &&!(flags &(MSG_PEEK | MSG_TRUNC)));/* Ugly... If prequeue is not empty, we have to
* process it before releasing socket, otherwise
* order will be broken at second iteration.
* More elegant solution is required!!!
*
* Look: we have the following (pseudo)queues:
*
* 1. packets in flight
* 2. backlog
* 3. prequeue
* 4. receive_queue
*
* Each queue can be processed only if the next ones
* are empty. At this point we have empty receive_queue.
* But prequeue _can_ be not empty after 2nd iteration,
* when we jumped to start of loop because backlog
* processing added something to receive_queue.
* We cannot release_sock(), because backlog contains
* packets arrived _after_ prequeued ones.
*
* Shortly, algorithm is clear --- to process all
* the queues in order. We could make it more directly,
* requeueing packets from backlog to prequeue, if
* is not empty. It is more elegant, but eats cycles,
* unfortunately.
*/if(!skb_queue_empty(&tp->ucopy.prequeue))goto do_prequeue;/* __ Set realtime policy in scheduler __ */}#ifdefCONFIG_NET_DMAif(tp->ucopy.dma_chan)dma_async_memcpy_issue_pending(tp->ucopy.dma_chan);#endifif(copied >= target){/* Do not sleep, just process backlog. */release_sock(sk);lock_sock(sk);}elsesk_wait_data(sk,&timeo);#ifdefCONFIG_NET_DMAtcp_service_net_dma(sk,false);/* Don't block */
tp->ucopy.wakeup =0;#endifif(user_recv){int chunk;/* __ Restore normal policy in scheduler __ */if((chunk = len - tp->ucopy.len)!=0){NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, chunk);
len -= chunk;
copied += chunk;}if(tp->rcv_nxt == tp->copied_seq &&!skb_queue_empty(&tp->ucopy.prequeue)){
do_prequeue:tcp_prequeue_process(sk);if((chunk = len - tp->ucopy.len)!=0){NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk);
len -= chunk;
copied += chunk;}}}if((flags & MSG_PEEK)&&(peek_seq - copied - urg_hole != tp->copied_seq)){if(net_ratelimit())printk(KERN_DEBUG "TCP(%s:%d): Application bug, race in MSG_PEEK.\n",
current->comm,task_pid_nr(current));
peek_seq = tp->copied_seq;}continue;
found_ok_skb:/* Ok so how much can we use? */
used = skb->len - offset;if(len < used)
used = len;/* Do we have urgent data here? */if(tp->urg_data){
u32 urg_offset = tp->urg_seq -*seq;if(urg_offset < used){if(!urg_offset){if(!sock_flag(sk, SOCK_URGINLINE)){++*seq;
urg_hole++;
offset++;
used--;if(!used)goto skip_copy;}}else
used = urg_offset;}}if(!(flags & MSG_TRUNC)){#ifdefCONFIG_NET_DMAif(!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
tp->ucopy.dma_chan =dma_find_channel(DMA_MEMCPY);if(tp->ucopy.dma_chan){
tp->ucopy.dma_cookie =dma_skb_copy_datagram_iovec(
tp->ucopy.dma_chan, skb, offset,
msg->msg_iov, used,
tp->ucopy.pinned_list);if(tp->ucopy.dma_cookie <0){printk(KERN_ALERT "dma_cookie < 0\n");/* Exception. Bailout! */if(!copied)
copied =-EFAULT;break;}dma_async_memcpy_issue_pending(tp->ucopy.dma_chan);if((offset + used)== skb->len)
copied_early =1;}else#endif{
err =skb_copy_datagram_iovec(skb, offset,
msg->msg_iov, used);if(err){/* Exception. Bailout! */if(!copied)
copied =-EFAULT;break;}}}*seq += used;
copied += used;
len -= used;tcp_rcv_space_adjust(sk);
skip_copy:if(tp->urg_data &&after(tp->copied_seq, tp->urg_seq)){
tp->urg_data =0;tcp_fast_path_check(sk);}if(used + offset < skb->len)continue;if(tcp_hdr(skb)->fin)goto found_fin_ok;if(!(flags & MSG_PEEK)){sk_eat_skb(sk, skb, copied_early);
copied_early =0;}continue;
found_fin_ok:/* Process the FIN. */++*seq;if(!(flags & MSG_PEEK)){sk_eat_skb(sk, skb, copied_early);
copied_early =0;}break;}while(len >0);if(user_recv){if(!skb_queue_empty(&tp->ucopy.prequeue)){int chunk;
tp->ucopy.len = copied >0? len :0;tcp_prequeue_process(sk);if(copied >0&&(chunk = len - tp->ucopy.len)!=0){NET_ADD_STATS_USER(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk);
len -= chunk;
copied += chunk;}}
tp->ucopy.task =NULL;
tp->ucopy.len =0;}#ifdefCONFIG_NET_DMAtcp_service_net_dma(sk,true);/* Wait for queue to drain */
tp->ucopy.dma_chan =NULL;if(tp->ucopy.pinned_list){dma_unpin_iovec_pages(tp->ucopy.pinned_list);
tp->ucopy.pinned_list =NULL;}#endif/* 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. */tcp_cleanup_rbuf(sk, copied);release_sock(sk);return copied;
out:release_sock(sk);return err;
recv_urg:
err =tcp_recv_urg(sk, msg, len, flags);goto out;}EXPORT_SYMBOL(tcp_recvmsg);
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">
评论记录:
回复评论: