Implementation of the Socket Layer Implementation Series-send () class Send function

Source: Internet
Author: User
Tags sendmsg

Main content: Socket send function system call, socket layer implementation.

Kernel version: 3.15.2

My blog: http://blog.csdn.net/zhangskd

Send flowchart

The following is the sending flowchart for Send (), sendto (), sendmsg (), and sendmmsg (), which are four functions except at the system call level

There are some differences in the implementation of the socket layer and TCP layer are the same.

Application Layer

The application layer can use the following socket function 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 is the difference between these send functions?

When the flags is 0 o'clock, the Send () and write () functions are the same.

Send (S, buf, Len, Flags) and sendto (S, buf, Len, flags, NULL, 0) function the same.

Write () and send () can be used when the socket is connected, while SendTo (), sendmsg (), and Sendmmsg () are available at all times.

The data at the user level is ultimately described as a message header.

struct MSGHDR {    void *msg_name;/* Optional address, Destination */    socklen_t msg_namelen; */size of address, length of destination addresses */
   struct Iovec *msg_iov; /* Scatter/gather array, array of scattered data blocks */    size_t Msg_iovlen;/* #elements in Msg_iov, number of scattered data blocks */    void *msg_control;/* A Ncillary data, Control/* *    socklen_t msg_controllen;/* Ancillary data buffer len, length of control/    int msg_flags;/* Flags O N Received message */};
/* Structure for Scatter/gather I/O. */struct Iovec {    void *iov_base;/* Pointer to data. */    size_t Iov_len;/* Le Ngth of data. */};

Send by default is blocked send, or can be set to non-blocking send.

Non-blocking flag: O_nonblock, msg_dontwait

When the message does not fit into the send buffer of the socket, send () normally blocks, unless the

Sockets have been placed in non-blocking I/O mode.

Enables non-blocking operations; If the operation would block, Eagain is returned (this can also be enabled

Using the O_non-block with the F_setel fcntl (2)).

System calls

The Send function is provided by GLIBC, the declaration is in include/sys/socket.h, and the implementation is in Sysdeps/mach/hurd/connect.c,

It is primarily used to enter a system call called Sys_socketcall from user space and pass parameters. Sys_socketcall () is actually all

The socket function enters the common portal 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;    ...    }}

Send () 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, F Lags, NULL, 0);}

SendTo () initializes the message header and then calls Sock_sendmsg () to process it.

/* Send A datagram to a given address. We move the address into kernel space * and check the user space data area is readable before invoking the protocol. */syscall_define6 (sendto, int, fd, void __user *, buff, size_t, Len, unsigned, flags, struct sockaddr __user *, addr, I    NT, 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;     /* Locate the corresponding socket instance by using the file descriptor FD.     * Use FD as index to find the corresponding file instance from the document descriptor Files_struct instance of the current process, and then get 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 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 socket address from user space to 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 the non-blocking flag is set */if (Sock->file->f_flags & O_nonblock) flags |= msg_dontwait;     Msg.msg_flags = flags; /* Call the Unified Send entry function sock_sendmsg () */err = sock_sendmsg (sock, &msg, Len); Out_put:fput_light (Sock->file, Fput_nee ded); Out:return err;}
struct MSGHDR {    void *msg_name;/* PTR to socket address structure */    int msg_namelen;/* Size of socket address s Tructure */    struct IOVEC *msg_iov;/* Scatter/gather array, array of scattered data blocks */    __kernel_size_t msg_iovlen;/* #elements I n Msg_iov, number of scattered data blocks */    void *msg_control;/* Ancillary data, control//    __kernel_size_t Msg_controllen;/* Ancillary D ATA buffer Len, the length of the control data *    /unsigned int msg_flags;/* flags on received message */};/* Structure for scatter/gather I/O . */struct Iovec {    void *iov_base;/* Pointer to data. */    __kernel_size_t iov_len;/* Length of data. */};/* for Rec Vmmsg/sendmmsg */struct mmsghdr {    struct MSGHDR msg_hdr;    unsigned int msg_len;};

Sock_sendmsg () calls __sock_sendmsg () after initializing the asynchronous IO control block.

int sock_sendmsg (struct socket *sock, struct MSGHDR *msg, size_t size) {struct KIOCB iocb;    struct SOCK_IOCB SIOCB;    int ret;    INIT_SYNC_KIOCB (&AMP;IOCB, NULL);    Iocb.private = &siocb;    ret = __sock_sendmsg (&AMP;IOCB, sock, msg, size);    /* IOCB Queued, 'll get completion event */if (-eiocbqueued = = ret) ret = WAIT_ON_SYNC_KIOCB (&AMP;IOCB); return ret;}    /* AIO control block */struct KIOCB {struct file *ki_filp; struct KIOCTX *ki_ctx;    /* NULL for sync OPS, or null if synchronous (*/KIOCB_CANCEL_FN *ki_cancel; void *private;        /* point to SOCK_IOCB */union {void __user *user; struct Task_struct *tsk;    /* Execute IO Process */} 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 I s the underlying EVENTFD context to deliver eventsTo. */struct eventfd_ctx *ki_eventfd;};

__sock_sendmsg () invokes the Send function of the socket layer, if it is sock_stream,

Then the call to Inet_sendmsg () is processed.

static inline int __sock_sendmsg (struct KIOCB *iocb, struct socket *sock,       struct MSGHDR *msg, size_t size) {    int er R = security_socket_sendmsg (sock, MSG, size);    Return err?: __sock_sendmsg_nosec (IOCB, sock, msg, size);} 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 operation function of the socket layer, if it is sock_stream, then Proto_ops is Inet_stream_ops,     * The function pointer points to inet_sendmsg ().     *    /return sock->ops->sendmsg (IOCB, sock, msg, size);}

Sendmsg () and sendmmsg () also copy the data from the user space to the kernel message header in the system call function, and finally call

The Send function inet_sendmsg () of the socket layer is processed next, and is not mentioned here.

Socket Layer

The socket layer operand set instance of the SOCK_STREAM socket is inet_stream_ops, where the Send function is inet_sendmsg ().

const struct Proto_ops inet_stream_ops = {    . Family = pf_inet,    . Owner = This_module,    ....    sendmsg = Inet_sendmsg,    ...};

Inet_sendmsg () primarily calls the TCP layer's send function tcp_sendmsg () to handle.

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 the connection has not been assigned a local port and allows automatic binding, bind a local port to the connection.     * Tcp_prot No_autobaind is true, so TCP is not allowed to automatically bind ports. */if (! Inet_sk (SK)->inet_num && sk->sk_prot->no_autobind && inet_autobind (s)) retur    N-eagain; /* If the transport layer is using TCP, then Sk_prot is tcp_prot,sendmsg point 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 be need to bind the socket.    */Lock_sock (SK); /* If you have not yet assigned a local port */if (! Inet->inet_num) {/* Sock_stream the set of TCP operation functions for the socket interface is Tcp_prot, where the port binding function is * inet_csk_ge         T_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;}

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Implementation of the Socket Layer Implementation Series-send () class Send function

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.