zoukankan      html  css  js  c++  java
  • TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术


    轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com微笑


    linux内核协议栈中对于socket相关API的实现


    首先对于内核中断向量表不是很熟悉的请先参考一下博文:《TCP/IP协议栈源码图解分析系列6:linux 系统调用中断向量表》 URL:http://blog.csdn.net/byhankswang/article/details/9284023


    首先应该做的事情

    定义好了内核中断向量表之后,需要做的就是当用户层程序陷入到内核态之后,通过内核中断向量表找到了内核中对于该系统调用的实现。补充一下内核中SYSCALL_DEFINE的用法:

     

    SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol){ ….}

    <=>SYSCALL_DEFINEX(3,_socket,__VA_ARGS__)

    <=>_SYSCALL_DEFINE(3,_socket,__VA_ARGS__)

    <=>asmlinkage long sys_socket(int family,int type,int protocol)

    SYSCALL_DEFINE* 把内核中断向量表和内核实现完美的衔接了起来。


    用户层API内核是如何实现的

    以socket相关的套接字编程接口为例(linux 3.9.3):

    socket.c:1382:SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
    socket.c:1423:SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
    socket.c:1519:SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
    socket.c:1548:SYSCALL_DEFINE2(listen, int, fd, int, backlog)
    socket.c:1581:SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
    socket.c:1662:SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
    socket.c:1680:SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
    socket.c:1712:SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
    socket.c:1743:SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
    socket.c:1775:SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
    socket.c:1822:SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
    socket.c:1834:SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
    socket.c:1890:SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
    socket.c:1924:SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
    socket.c:1954:SYSCALL_DEFINE2(shutdown, int, fd, int, how)
    socket.c:2096:SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
    socket.c:2171:SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
    socket.c:2269:SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
    socket.c:2393:SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
    socket.c:2435:SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)


    然后我们看相关的源代码以socket和bind为例:

    SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
    {
    int retval;
    struct socket *sock;
    int flags;


    /* Check the SOCK_* constants for consistency.  */
    BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
    BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
    BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
    BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);

    flags = type & ~SOCK_TYPE_MASK;
    if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
    return -EINVAL;
    type &= SOCK_TYPE_MASK;

    if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
    flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;

    retval = sock_create(family, type, protocol, &sock);
    if (retval < 0)
    goto out;

    retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
    if (retval < 0)
    goto out_release;

    out:
    /* It may be already another descriptor 8) Not kernel problem. */
    return retval;

    out_release:
    sock_release(sock);
    return retval;
    }



    SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
    {
    struct socket *sock;
    struct sockaddr_storage address;
    int err, fput_needed;

    sock = sockfd_lookup_light(fd, &err, &fput_needed);
    if (sock) {
    err = move_addr_to_kernel(umyaddr, addrlen, &address);
    if (err >= 0) {
    err = security_socket_bind(sock,
      (struct sockaddr *)&address,
      addrlen);
    if (!err)
    err = sock->ops->bind(sock,
         (struct sockaddr *)
         &address, addrlen);
    }
    fput_light(sock->file, fput_needed);
    }
    return err;
    }


    我们可以看到,只要抓住了主要的脉络,分析内核协议栈是很简单的事情,用侯捷先生的话说“源码在手,了无秘密”。

  • 相关阅读:
    poj 3126 Prime Path
    poj 2255 Tree Recovery
    spoj 7259 LITE
    poj 1742 Coins
    poj 1915 Knight Moves
    poj 2352 Stars
    【祝贺】gooogleman嵌入式开发板联盟图标设计完成,Let me Show!
    【讨论】TE6410/OK6410 开发板dnw c0008000是什么意思, ?
    【讨论】为什么我的300W摄像头偶尔会拍照不成功?
    【探讨】关于2440 触摸屏驱动的怪异现象分析
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3181713.html
Copyright © 2011-2022 走看看