Linux TCP sending process source code analysis-socket Layer
Source code analysis of the linuxTCP sending Process--Socket Layer -- lvyilong316
Kernel version: 3.15.2
Socket Data Structure
Sending Flowchart
The following is the sending flowchart of send (), sendto (), sendmsg (), and sendmmsg (). These four functions differ in addition to system calls, both the Socket layer and TCP layer have the same implementation.
Application Layer
The application layer can use the following Socket functions to send data:
- ssize_t write(int fd, const void *buf, size_t count);
- ssize_t send(int s, const void *buf, size_t len, int flags);
- ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
- ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
- int sendmmsg(int s, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags);
What are the differences between these sending functions? When flags is 0, the send () and write () functions are the same. The send (s, buf, len, flags) and sendto (s, buf, len, flags, NULL, 0) functions are the same. Write () and send () can be used when the socket is connected, while sendto (), sendmsg () and sendmmsg () are available at any time. The data at the user layer is finally described in the message header.
Lstructmsghdr
- Struct msghdr {
- Void * msg_name;/* optional address, Destination address */
- Socklen_t msg_namelen;/* size of address, the length of the destination address */
- Struct iovec * msg_iov;/* scatter/gather array, scattered data block array */
- Size_t msg_iovlen;/* # elements in msg_iov, number of scattered data blocks */
- Void * msg_control;/* ancillary data, control data */
- Socklen_t msg_controllen;/* ancillary data buffer len, controls the data Length */
- Int msg_flags;/* flags on received message */
- };
Lstructiovec
- /* Structure for scatter/gather I/O. */
- struct iovec {
- void *iov_base; /* Pointer to data. */
- size_t iov_len; /* Length of data. */
- };
By default, sending is blocked or non-blocking. Non-blocking signs: O_NONBLOCK and MSG_DONTWAIT.
System Call
The sending function is provided by glibc and is declared in include/sys/socket. h, implemented in sysdeps/mach/hurd/connect. c is mainly used to access the system call named sys_socketcall from the user space and pass parameters. Sys_socketcall () is actually all
The socket function enters the Common Entrance of the kernel space.
- SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
- {
- ...
- switch(call) {
- ...
- case SYS_SEND:
- err = sys_send(a0, (void __user *)a1, a[2], a[3]);
- break;
- case SYS_SENDTO:
- err = sys_sendto(a0, (void __user *)a1 a[2], a[3], (struct sockaddr __user *)a[4], a[5]);
- break;
- ...
- case SYS_SENDMSG:
- err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
- break;
- case SYS_SENDMMSG:
- err = sys_sendmmsg(a0, (struct msghdr __user *)a1, a[2], a[3]);
- break;
- ...
- }
- }
Lsend
Sending () is actually a special case of sendto.
- SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, unsigned, flags)
- {
- return sys_sendto(fd, buff, len, flags, NULL, 0);
- }
Lsendto
Sendto () initializes the message header, and then calls sock_sendmsg () for processing.
- SYSCALL_DEFINE6 (sendto, int, fd, void _ user *, buff, size_t, len, unsigned, flags,
- Struct sockaddr _ user *, addr, int, addr_len)
- {
- Struct socket * sock;
- Struct sockaddr_storage address;
- Int err;
- Struct msghdr msg;
- Struct iovec iov;
- Int fput_needed;
- If (len> INT_MAX)
- Len = INT_MAX;
- /* Find the corresponding socket instance through the file descriptor fd.
- * Use fd as the index to find the corresponding file instance from the file descriptor table files_struct instance of the current process,
- * Obtain the socket instance from the private_data Member of the file instance.
- */
- Sock = sockfd_lookup_light (fd, & err, & fput_needed );
- If (! Sock)
- Goto out;
- /* Initialize the message header */
- Iov. iov_base = buff;
- Iov. iov_len = len;
- Msg. msg_name = NULL;
- Msg. msg_iov = & iov;
- Msg. msg_iovlen = 1;/* only one data block */
- Msg. msg_control = NULL;
- Msg. msg_controllen = 0;
- Msg. msg_namelen = 0;
- If (addr ){
- /* Copy the socket address from the user space to the kernel space */
- Err = move_addr_to_kernel (addr, addr_len, & address );
- If (err <0)
- Goto out_put;
- Msg. msg_name = (struct sockaddr *) & address;
- Msg. msg_namelen = addr_len;
- }
- /* If a non-blocking flag is set */
- If (sock-> file-> f_flags & O_NONBLOCK)
- Flags | = MSG_DONTWAIT;
- Msg. msg_flags = flags;
- /* Call the unified sending entry function sock_sendmsg ()*/
- Err = sock_sendmsg (sock, & msg, len );
- Out_put:
- Fput_light (sock-> file, fput_needed );
- Out:
- Return err;
- }
Lsock_sendmsg
After _sendmsg () initializes the asynchronous IO control block, it calls _ sock_sendmsg ().
- Int sock_sendmsg (struct socket * sock, struct msghdr * msg, size_t size)
- {
- Struct kiocb iocb;
- Struct sock_iocb siocb;
- Int ret;
- Init_sync_kiocb (& iocb, NULL );
- Iocb. private = & siocb;
- Ret = _ sock_sendmsg (& iocb, sock, msg, size );
- /* Iocb queued, will get completion event */
- If (-EIOCBQUEUED = ret)
- Ret = wait_on_sync_kiocb (& iocb );
- Return ret;
- }
- /* AIO control block */
- Struct kiocb {
- Struct file * ki_filp;
- Struct kioctx * ki_ctx;/* NULL for sync ops. If it is synchronous, It is NULL */
- Kiocb_cancel_fn * ki_cancel;
- Void * private;/* points to sock_iocb */
- Union {
- Void _ user * user;
- Struct task_struct * tsk;/* processes that execute io */
- } Ki_obj;
- _ U64 ki_user_data;/* user's data for completion */
- Loff_t ki_pos;
- Size_t ki_nbytes;/* copy of iocb-> aio_nbytes */
- Struct list_head ki_list;/* the aio core uses this for cancellation */
- /* If the aio_resfd field of the userspace iocb is not zero,
- * This is the underlying eventfd context to deliver events.
- */
- Struct eventfd_ctx * ki_eventfd;
- };
L _ sock_sendmsg ()
_ Sock_sendmsg () will call the sending function at the Socket layer. If it is SOCK_STREAM, it will then call inet_sendmsg () for processing.
- static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size)
- {
- int err = security_socket_sendmsg(sock, msg, size);
- return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
- }
L _ sock_sendmsg_nosec
- Static inline int _ sock_sendmsg_nosec (struct kiocb * iocb, struct socket * sock,
- Struct msghdr * msg, size_t size)
- {
- Struct sock_iocb * si = kiocb_to_siocb (iocb );
- Si-> sock = sock;
- Si-> scm = NULL;
- Si-> msg = msg;
- Si-> size = size;
- /* Call the Socket-layer operation function. If it is SOCK_STREAM, proto_ops is inet_stream_ops, and the function pointer points to inet_sendmsg ().
- */
- Return sock-> ops-> sendmsg (iocb, sock, msg, size );
- }
Sendmsg () and sendmmsg () are used to copy user space data to the kernel message header in the system call function. Finally, the inet_sendmsg () function of the Socket layer is called for next processing, I will not go into details here.
Socket Layer
The socket-layer operation function set instance of the SOCK_STREAM interface is inet_stream_ops, And the sending function is inet_sendmsg ().
- const struct proto_ops inet_stream_ops = {
- .family = PF_INET,
- .owner = THIS_MODULE,
- ...
- .sendmsg = inet_sendmsg,
- ...
- };
Linet_sendmsg
Inet_sendmsg () mainly calls the tcp_sendmsg () function of the TCP layer for processing.
- Int inet_sendmsg (struct kiocb * iocb, struct socket * sock, struct msghdr * msg, size_t size)
- {
- Struct sock * sk = sock-> sk;
- Sock_rps_record_flow (sk );
- /* We may need to bnd the socket.
- * If no local port is allocated for the connection and automatic binding is allowed, bind a local port to the connection.
- * The no_autobaind value of tcp_prot is true, so TCP does not allow automatic port binding.
- */
- If (! Inet_sk (sk)-> inet_num &&! Sk-> sk_prot-> no_autobind & inet_autobind (s ))
- Return-EAGAIN;
- /* If the transport layer uses TCP, sk_prot is tcp_prot, and sendmsg points to tcp_sendmsg ()*/
- Return sk-> sk_prot-> sendmsg (iocb, sk, msg, size );
- }
- /* Automatically bind an unbound socket .*/
- Static int inet_autobind (struct sock * sk)
- {
- Struct inet_sock * inet;
- /* We may need to bind the socket .*/
- Lock_sock (sk );
- /* If no local port is allocated */
- If (! Inet-> inet_num ){
- /* The TCP operation function set of the SOCK_STREAM interface is tcp_prot, and the port binding function is
- * Inet_csk_get_port ().
- */
- If (sk-> sk_prot-> get_port (sk, 0 )){
- Release_sock (sk );
- Return-EAGAIN;
- }
- Inet-> inet_sport = htons (inet-> inet_num );
- }
- Release_sock (sk );
- Return 0;
- }
The relationship between function calls (red lines) and data structures (blue lines) is as follows: