• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            大龍的博客

            常用鏈接

            統計

            最新評論

            Linux TCP/IP協議棧之Socket的實現分析(一 套接字的創建) --- 轉

            Socket并不是TCP/IP協議的一部份,從廣義上來講,socket是Unix/Linux抽像的進程間通訊的一種方法
            網絡socket通訊僅僅是其若干協議中的一類,而tcp/ip又是網絡協議各類中的一種
            從tcp/ip的角度看socket,它更多地體現了用戶API與協議棧的一個中間層接口層
            用戶通過調用socket API將報文遞交給協議棧,或者從協議棧中接收報文

            系統總入口
            Linux內核為所有的與socket有關操作的API,提供了一個統一的系統調用入口,其代碼在net/socket.c中
            asmlinkage long sys_socketcall(int call, unsigned long __user *args)
            {
                ...
                /* copy_from_user should be SMP safe. */
                if (copy_from_user(a, args, nargs[call]))
                    return -EFAULT;

                a0=a[0];
                a1=a[1];
                switch(call)
                {
                    case SYS_SOCKET:
                        err = sys_socket(a0,a1,a[2]);
                        break;
                    case SYS_BIND:
                        err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
                        break;
                    case SYS_CONNECT:
                        err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
                        break;
                    case SYS_LISTEN:
                        err = sys_listen(a0,a1);
                        break;
                    case SYS_ACCEPT:
                        err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
                        break;
                    case SYS_GETSOCKNAME:
                        err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
                        break;
                    case SYS_GETPEERNAME:
                        err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
                        break;
                    case SYS_SOCKETPAIR:
                        err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);
                        break;
                    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_RECV:
                        err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
                        break;
                    case SYS_RECVFROM:
                        err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
                                   (struct sockaddr __user *)a[4], (int __user *)a[5]);
                        break;
                    case SYS_SHUTDOWN:
                        err = sys_shutdown(a0,a1);
                        break;
                    case SYS_SETSOCKOPT:
                        err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
                        break;
                    case SYS_GETSOCKOPT:
                        err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);
                        break;
                    case SYS_SENDMSG:
                        err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);
                        break;
                    case SYS_RECVMSG:
                        err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);
                        break;
                    default:
                        err = -EINVAL;
                        break;
                }
                return err;
            }
            首先調用 copy_from_user將用戶態參數拷貝至數組a,但是問題在于每個被調用的 API 的參數不盡相同,
            那么每次拷貝的字節在小如何判斷.來看其第三個參數 nargs[call],其中 call 是操作碼,后面有個大大的
            switch...case 就是判斷它。對應的操作碼定義在 include/linux/net.h
            #define SYS_SOCKET                     1                /* sys_socket(2)                */
            #define SYS_BIND                         2                /* sys_bind(2)                        */
            #define SYS_CONNECT                  3                /* sys_connect(2)                */
            #define SYS_LISTEN                       4                /* sys_listen(2)                */
            #define SYS_ACCEPT                     5                /* sys_accept(2)                */
            #define SYS_GETSOCKNAME        6                /* sys_getsockname(2)                */
            #define SYS_GETPEERNAME         7                /* sys_getpeername(2)                */
            #define SYS_SOCKETPAIR             8                /* sys_socketpair(2)                */
            #define SYS_SEND                          9                /* sys_send(2)                        */
            #define SYS_RECV                         10                /* sys_recv(2)                        */
            #define SYS_SENDTO                    11                /* sys_sendto(2)                */
            #define SYS_RECVFROM               12                /* sys_recvfrom(2)                */
            #define SYS_SHUTDOWN              13                /* sys_shutdown(2)                */
            #define SYS_SETSOCKOPT           14                /* sys_setsockopt(2)                */
            #define SYS_GETSOCKOPT          15                /* sys_getsockopt(2)                */
            #define SYS_SENDMSG                 16                /* sys_sendmsg(2)                */
            #define SYS_RECVMSG                 17                /* sys_recvmsg(2)                */
            而數組nargs則根據操作碼的不同,計算對應的參數的空間大小:
            /* Argument list sizes for sys_socketcall */
            #define AL(x) ((x) * sizeof(unsigned long))
            static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
                                             AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
                                             AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
            #undef AL
            當拷貝完成參數后,就進入一個switch...case...判斷操作碼,跳轉至對應的系統接口.

            sys_socket函數
            操作碼 SYS_SOCKET 是由 sys_socket()實現的:
            1239 asmlinkage long sys_socket(int family, int type, int protocol)
            1240 {
            1241     int retval;
            1242     struct socket *sock;
            1243
            1244     retval = sock_create(family, type, protocol, &sock);
            1245     if (retval < 0)
            1246         goto out;
            1247
            1248     retval = sock_map_fd(sock);
            1249     if (retval < 0)
            1250         goto out_release;
            1251
            1252 out:
            1253     /* It may be already another descriptor 8) Not kernel problem. */
            1254     return retval;
            1255
            1256 out_release:
            1257     sock_release(sock);
            1258     return retval;
            1259 }
            在分析這段代碼之前, 首先來看創建一個Socket, 對內核而言,究竟意味著什么?究竟需要內核干什么事?
            當用戶空間要創建一個 socke 接口時,會調用 API 函數
            int socket(int domain, int type, int protocol)
            其三個參數分別表示協議族,協議類型(面向連接或無連接)以及協議

            對于用戶態而言, 一個Socket, 就是一個特殊的已經打開的文件,為了對socket抽像出文件的概念,
            內核中為socket定義了一個專門的文件系統類型sockfs.
             344 static struct vfsmount *sock_mnt __read_mostly;
             345
             346 static struct file_system_type sock_fs_type = {                                                                        
             347     .name =     "sockfs",
             348     .get_sb =   sockfs_get_sb,
             349     .kill_sb =    kill_anon_super,
             350 };
            在模塊初始化的時候,安裝該文件系統: 
            void __init sock_init(void)
            {
                    ……
                    register_filesystem(&sock_fs_type);
                    sock_mnt = kern_mount(&sock_fs_type);        
            }
            稍后還要回來繼續分析安裝中的一點細節

            有了文件系統后,對內核而言,創建一個socket,就是在sockfs文件系統中創建一個文件節點(inode),并建立起為了實現
            socket功能所需的一整套數據結構,包括struct inode和struct socket結構.
            struct socket結構在內核中,就代表了一個"Socket",當一個struct socket數據結構被分配空間后,再將其與一個已打開
            的文件“建立映射關系”.這樣,用戶態就可以用抽像的文件的概念來操作socket了
            ——當然由于網絡的特殊性,至少就目前而言,這種抽像,并不如其它模塊的抽像那么完美.

            文件系統struct vfsmount中有一個成員指針mnt_sb指向該文件系統的超級塊,而超級塊結構struct super_lock
            有一個重要的成員s_op指向了超級塊的操作函數表,其中有函數指針alloc_inode()即為在給定的超級塊下創建并初始化
            一個新的索引節點對像. 也就是調用:
            sock_mnt->mnt_sb->s_op->alloc_inode(sock_mnt->mnt_sb);
            當然,連同相關的處理細節一起,這一操作被層層封裝至一個上層函數new_inode()

            那如何分配一個struct socket結構呢?
            如前所述,一個socket總是與一個inode 密切相關的.當然,在 inode 中設置一個socket成員是完全可行的,
            但是這貌似浪費了空間——畢竟更多的文件系統沒有socket這個東東.
            所以,內核引入了另一個socket_alloc結構
            struct socket_alloc {
                    struct socket socket;
                    struct inode vfs_inode;
            };
            顯而易見,該結構實現了inode和socket的封裝.已知一個inode可以通過宏SOCKET_I來獲取
            與之對應的 socket:
            sock = SOCKET_I(inode);
            static inline struct socket *SOCKET_I(struct inode *inode)
            {
                    return &container_of(inode, struct socket_alloc, vfs_inode)->socket;
            }
            但是這樣做也同時意味著在分配一個inode后,必須再分配一個socket_alloc結構,并實現對應的封裝.
            否則container_of又能到哪兒去找到socket呢?
            現在來簡要地看一個這個流程——這是文件系統安裝中的一個重要步驟

            881 struct vfsmount *kern_mount(struct file_system_type *type)
            882 {
            883     return vfs_kern_mount(type, 0, type->name, NULL);
            884 }

            817 struct vfsmount *
            818 vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
            819 {
            820     struct vfsmount *mnt;
            821     char *secdata = NULL;
            822     int error;
                       ....
            828     mnt = alloc_vfsmnt(name);
            829     if (!mnt)
            830         goto out;
            841     ....
            842     error = type->get_sb(type, flags, name, data, mnt);
            843     if (error < 0)
            844         goto out_free_secdata;
            849
            850     mnt->mnt_mountpoint = mnt->mnt_root;
            851     mnt->mnt_parent = mnt;
            852     up_write(&mnt->mnt_sb->s_umount);
            853     free_secdata(secdata);
            854     return mnt;
            855     .....
            865 }
            申請文件系統mnt結構, 調用之前注冊的sock_fs_type的get_sb成員函數指針, 獲取相應的超級塊sb.
            并將mnt->mnt_sb指向sock_fs_type中的超級塊

            337 static int sockfs_get_sb(struct file_system_type *fs_type,
            338     int flags, const char *dev_name, void *data, struct vfsmount *mnt)
            339 {
            340     return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC,                                                
            341                  mnt);
            342 }
            注意其第三個參數 sockfs_ops,它封裝了 sockfs 的功能函數表
            331 static struct super_operations sockfs_ops = {
            332     .alloc_inode =  sock_alloc_inode,
            333     .destroy_inode =sock_destroy_inode,
            334     .statfs =   simple_statfs,
            335 };

            struct super_block *
            get_sb_pseudo(struct file_system_type *fs_type, char *name,
                    struct super_operations *ops, unsigned long magic)
            {
                    struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
                            ……
                    s->s_op = ops ? ops : &default_ops;
            }
            這里就是先獲取/分配一個超級塊,然后初始化超級塊的各成員,包括s_op,它封裝了對應的功能函數表.
            s_op自然就指向了sockfs_ops,那前面提到的new_inode()函數分配inode時調用的
            sock_mnt->mnt_sb->s_op->alloc_inode(sock_mnt->mnt_sb);
            這個alloc_inode函數指針也就是sockfs_ops的sock_alloc_inode()函數——轉了一大圈,終于指到它了.

            來看看sock_alloc_inode是如何分配一個inode節點的
             283 static kmem_cache_t * sock_inode_cachep __read_mostly;
             284
             285 static struct inode *sock_alloc_inode(struct super_block *sb)
             286 {
             287     struct socket_alloc *ei;
             288     ei = (struct socket_alloc *)kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL);                                      
             289     if (!ei)
             290         return NULL;
             291     init_waitqueue_head(&ei->socket.wait);
             292    
             293     ei->socket.fasync_list = NULL;
             294     ei->socket.state = SS_UNCONNECTED;
             295     ei->socket.flags = 0;
             296     ei->socket.ops = NULL;
             297     ei->socket.sk = NULL;
             298     ei->socket.file = NULL;
             299     ei->socket.flags = 0;
             300
             301     return &ei->vfs_inode;
             302 }
            函數先分配了一個用于封裝socket和inode的 ei,然后在高速緩存中為之申請了一塊空間.
            這樣inode和socket就同時都被分配了,接下來初始化socket的各個成員,這些成員在后面都會一一提到
             96 /**
             97  *  struct socket - general BSD socket
             98  *  @state: socket state (%SS_CONNECTED, etc)
             99  *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
            100  *  @ops: protocol specific socket operations
            101  *  @fasync_list: Asynchronous wake up list
            102  *  @file: File back pointer for gc
            103  *  @sk: internal networking protocol agnostic socket representation
            104  *  @wait: wait queue for several uses
            105  *  @type: socket type (%SOCK_STREAM, etc)
            106  */
            107 struct socket {
            108     socket_state        state;
            109     unsigned long       flags;
            110     const struct proto_ops  *ops;
            111     struct fasync_struct    *fasync_list;
            112     struct file     *file;
            113     struct sock     *sk;                                                                                                
            114     wait_queue_head_t   wait;
            115     short           type;
            116 };
            至目前為止,分配inode,socket以及兩者如何關聯,都已一一分析了.
            最后一個關鍵問題,就是如何把socket與一個已打開的文件,建立映射關系.

            在內核中,用struct file結構描述一個已經打開的文件,指向該結構的指針內核中通常用file或filp來描述.
            我們知道,內核中可以通過全局項current來獲得當前進程,它是一個struct task_struct類型的指針.
            tastk_struct有一個成員:
            struct files_struct *files;指向一個已打開的文件.
            當然,由于一個進程可能打開多個文件,所以,struct files_struct 結構有
            struct file *fd_array[NR_OPEN_DEFAULT]成員,
            這是個數組,以文件描述符為下標,即current->files->fd[fd],可以找到與當前進程指定文件描述符的文件

            有了這些基礎,如果要把一個socket與一個已打開的文件建立映射,首先要做的就是為socket分配一個struct file,
            并申請分配一個相應的文件描述符fd. 因為socket并不支持open方法,所以不能期望用戶界面通過調用open() API
            來分配一個struct file,而是通過調用get_empty_filp來獲取
            struct file *file = get_empty_filp()
            fd = get_unused_fd();獲取一個空間的文件描述符
            然后讓current的files指針的fd數組的fd索引項指向該file
            void fastcall fd_install(unsigned int fd, struct file * file)
            {
                    struct files_struct *files = current->files;
                    spin_lock(&files->file_lock);
                    if (unlikely(files->fd[fd] != NULL))
                            BUG();
                    files->fd[fd] = file;
                    spin_unlock(&files->file_lock);
            }
            做到這一步,有了一個文件描述符fd和一個打開的文件file,它們與當前進程相連,但是好像與創建的socket并無任何瓜葛.
            要做的映射還是沒有進展,struct file或者文件描述述fd或current都沒有任何能夠與 inode或者是socket相關的東東
            這需要一個中間的橋梁,目錄項:struct dentry結構

            因為一個文件都有與其對應的目錄項:
            struct file {
                    struct list_head        f_list;
                    struct dentry          *f_dentry;
                    ……
            而一個目錄項:
            struct dentry {
                    ……
                    struct inode *d_inode;                /* Where the name belongs to - NULL is negative */
            d_inode 成員指向了與之對應的 inode節點

            之前已經創建了一個inode節點和與之對應的 socket. 所以現在要做的就是:
            “先為當前文件分配一個對應的目錄項,再將已創建的 inode節點安裝至該目錄項”
            這樣一個完成的映射關系:
            進程,文件描述符,打開文件,目錄項,inode節點,socket就完整地串起來了
             
            基本要分析的一些前導的東東都一一羅列了,雖然已盡量避免陷入文件系統的細節分析,但是還是不可避免地進入其中,
            因為它們關系實現太緊密了,現在可以來看套接字的創建過程了
            1239 asmlinkage long sys_socket(int family, int type, int protocol)
            1240 {
            1241     int retval;
            1242     struct socket *sock;
            1243
            1244     retval = sock_create(family, type, protocol, &sock);                                                               
            1245     if (retval < 0)
            1246         goto out;
            1247
            1248     retval = sock_map_fd(sock);
            1249     if (retval < 0)
            1250         goto out_release;
            1251
            1252 out:
            1253     /* It may be already another descriptor 8) Not kernel problem. */
            1254     return retval;
            1255
            1256 out_release:
            1257     sock_release(sock);
            1258     return retval;
            1259 }
            1229 int sock_create(int family, int type, int protocol, struct socket **res)
            1230 {
            1231     return __sock_create(family, type, protocol, res, 0);
            1232 }

            AF_INET協議簇的協議封裝
            接下來,函數調用之前已經注冊的inet_family_ops的函數指針create,也就是inet_create()函數.
            前面可以說一個通用的socket已經創建好了,這里要完成與協議本身相關的一些創建socket的工作.
            這一部份的工作比較復雜,還是先來看看af_inet.c中的模塊初始化時候,做了哪些與此相關的工作.

            要引入的第一個數據結構是struct inet_protosw,它封裝了一個協議類型(如 SOCK_STREAM,SOCK_DGRAM等)
            與IP協議中對應的傳輸層協議.
             68 /* This is used to register socket interfaces for IP protocols.  */                                                     
             69 struct inet_protosw {     
             70     struct list_head list;
             71
             72     /* These two fields form the lookup key.  */
             73     unsigned short   type;     /* This is the 2nd argument to socket(2). */
             74     int      protocol; /* This is the L4 protocol number.  */                                                           
             75
             76     struct proto     *prot;
             77     const struct proto_ops *ops;                                                                                        
             78  
             79     int                capability;   /* Which (if any) capability do we need to use this socket interface*/            
             83     char             no_check;   /* checksum on rcv/xmit/none? */
             84     unsigned char    flags;    /* See INET_PROTOSW_* below.  */                                                       
             85 };
            type是協議類型,對于 ipv4 而言就是SOCK_STREAM,SOCK_DGRAM或者是SOCK_RAW之一.
            protocol是傳輸層的協議號,prot用于描述一個具體的傳輸層協議,而ops指向對應的當前協議類型的操作函數集
            針對不同的協議類型,定義了不同的 ops:
            791 const struct proto_ops inet_stream_ops = {
             792     .family        = PF_INET,
             793     .owner         = THIS_MODULE,
             794     .release       = inet_release,
             795     .bind          = inet_bind,
             796     .connect       = inet_stream_connect,
             797     .socketpair    = sock_no_socketpair,
             798     .accept        = inet_accept,
             799     .getname       = inet_getname,
             800     .poll          = tcp_poll,
             801     .ioctl         = inet_ioctl,
             802     .listen        = inet_listen,
             803     .shutdown      = inet_shutdown,
             804     .setsockopt    = sock_common_setsockopt,
             805     .getsockopt    = sock_common_getsockopt,
             806     .sendmsg       = inet_sendmsg,
             807     .recvmsg       = sock_common_recvmsg,
             808     .mmap          = sock_no_mmap,
             809     .sendpage      = tcp_sendpage,
             810 #ifdef CONFIG_COMPAT
             811     .compat_setsockopt = compat_sock_common_setsockopt,
             812     .compat_getsockopt = compat_sock_common_getsockopt,
             813 #endif
             814 };
             815
             816 const struct proto_ops inet_dgram_ops = {
             817     .family        = PF_INET,
             818     .owner         = THIS_MODULE,
             819     .release       = inet_release,
             820     .bind          = inet_bind,
             821     .connect       = inet_dgram_connect,
             822     .socketpair    = sock_no_socketpair,
             823     .accept        = sock_no_accept,
             824     .getname       = inet_getname,
             825     .poll          = udp_poll,
             826     .ioctl         = inet_ioctl,
             827     .listen        = sock_no_listen,
            828     .shutdown      = inet_shutdown,
             829     .setsockopt    = sock_common_setsockopt,
             830     .getsockopt    = sock_common_getsockopt,
             831     .sendmsg       = inet_sendmsg,
             832     .recvmsg       = sock_common_recvmsg,
             833     .mmap          = sock_no_mmap,
             834     .sendpage      = inet_sendpage,
             835 #ifdef CONFIG_COMPAT
             836     .compat_setsockopt = compat_sock_common_setsockopt,
             837     .compat_getsockopt = compat_sock_common_getsockopt,
             838 #endif
             839 };
             840
             841 /*
             842  * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without
             843  * udp_poll
             844  */
            845 static const struct proto_ops inet_sockraw_ops = {
             846     .family        = PF_INET,
             847     .owner         = THIS_MODULE,
             848     .release       = inet_release,
             849     .bind          = inet_bind,
             850     .connect       = inet_dgram_connect,
             851     .socketpair    = sock_no_socketpair,
             852     .accept        = sock_no_accept,
             853     .getname       = inet_getname,
             854     .poll          = datagram_poll,
             855     .ioctl         = inet_ioctl,                                                                                       
             856     .listen        = sock_no_listen,
             857     .shutdown      = inet_shutdown,
             858     .setsockopt    = sock_common_setsockopt,
             859     .getsockopt    = sock_common_getsockopt,
             860     .sendmsg       = inet_sendmsg,
             861     .recvmsg       = sock_common_recvmsg,
             862     .mmap          = sock_no_mmap,
             863     .sendpage      = inet_sendpage,
             864 #ifdef CONFIG_COMPAT
             865     .compat_setsockopt = compat_sock_common_setsockopt,
             866     .compat_getsockopt = compat_sock_common_getsockopt,
             867 #endif
             868 };
            從各個函數指針的名稱,我們就可以大約知道它們是做什么事的了.進一步進以看到,
            它們的函數指針指向的函數差不多都是相同的.除了一些細節上的區別,例如后面兩種協議類型并不支持listen.

            socket()API第二個參數是協議類型,第三個參數是該協議類型下的協議——不過對于ipv4而言,
            它們都是一一對應的,但是從抽像封裝的角度看,數據結構的設計本身應該滿足一個協議類型下邊可能存在多個不同的協議,
            即一對多的情況.而一一對應,僅是它們的特例:
            876 /* Upon startup we insert all the elements in inetsw_array[] into
             877  * the linked list inetsw.
             878  */
             879 static struct inet_protosw inetsw_array[] =
             880 {
             881         {
             882                 .type =       SOCK_STREAM,
             883                 .protocol =   IPPROTO_TCP,
             884                 .prot =       &tcp_prot,
             885                 .ops =        &inet_stream_ops,
             886                 .capability = -1,
             887                 .no_check =   0,
             888                 .flags =      INET_PROTOSW_PERMANENT |
             889                   INET_PROTOSW_ICSK,
             890         },
             892         {
             893                 .type =       SOCK_DGRAM,
             894                 .protocol =   IPPROTO_UDP,
             895                 .prot =       &udp_prot,
             896                 .ops =        &inet_dgram_ops,
             897                 .capability = -1,
             898                 .no_check =   UDP_CSUM_DEFAULT,
             899                 .flags =      INET_PROTOSW_PERMANENT,
             900        },
             903        {
             904                .type =       SOCK_RAW,
             905                .protocol =   IPPROTO_IP,    /* wild card */
             906                .prot =       &raw_prot,
             907                .ops =        &inet_sockraw_ops,
             908                .capability = CAP_NET_RAW,
             909                .no_check =   UDP_CSUM_DEFAULT,
             910                .flags =      INET_PROTOSW_REUSE,
             911        }
             912 };
            數組的每一個元素,就是支持的一種協議名稱,例如IPOROTO_TCP,但是由于IPV4本身協議類型跟協議是一一對應的,
            所以沒有更多的.type= SOCK_xxx 了.這樣數組實現了對PF_INET協議族下支持的協議類型,
            以及協議類型下邊的協議進行了封裝,雖然事實上它們是一一對應的關系,不過理論上完全可能存在一對多的可能.

            數組內,封裝的一個具體的協議,由 struct proto 結構來描述
            以 TCP協議為例,TCP協議的 sokcet 操作函數都被封裝在這里了。 
            struct proto tcp_prot = {
                    .name                        = "TCP",
                    .owner                        = THIS_MODULE,
                    .close                        = tcp_close,
                    .connect                = tcp_v4_connect,
                    .disconnect                = tcp_disconnect,
                    .accept                        = tcp_accept,
                    .ioctl                        = tcp_ioctl,
                    .init                        = tcp_v4_init_sock,
                    .destroy                = tcp_v4_destroy_sock,
                    .shutdown                = tcp_shutdown,
                    .setsockopt                = tcp_setsockopt,
                    .getsockopt                = tcp_getsockopt,
                    .sendmsg                = tcp_sendmsg,
                    .recvmsg                = tcp_recvmsg,
                    .backlog_rcv                = tcp_v4_do_rcv,
                    .hash                        = tcp_v4_hash,
                    .unhash                        = tcp_unhash,
                    .get_port                = tcp_v4_get_port,
                    .enter_memory_pressure        = tcp_enter_memory_pressure,
                    .sockets_allocated        = &tcp_sockets_allocated,
                    .memory_allocated        = &tcp_memory_allocated,
                    .memory_pressure        = &tcp_memory_pressure,
                    .sysctl_mem                = sysctl_tcp_mem,
                    .sysctl_wmem                = sysctl_tcp_wmem,
                    .sysctl_rmem                = sysctl_tcp_rmem,
                    .max_header                = MAX_TCP_HEADER,
                    .obj_size                = sizeof(struct tcp_sock),
            }
            分配struct sock
            看完了PF_INET的協議簇,協議類型和協議(也就是socket調用的三個參數)的封裝關系,它們通過了兩個數據結構
            inet_protosw,struct proto來描述,被一個數組inetsw_array所封裝.接下來看它的初始化工作:
            static struct list_head inetsw[SOCK_MAX];
            static int __init inet_init(void)
            {
                    ……
                    /* Register the socket-side information for inet_create. */
                    for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
                            INIT_LIST_HEAD(r);
                    for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
                            inet_register_protosw(q);
                    ……
            }
            inetsw是一個數組,其每一個元素都是一個鏈表首部,前面一個循環初始化之.后一個循環就值得注意了,
            也就是函數
            916 void inet_register_protosw(struct inet_protosw *p)
             917 {
             918     struct list_head *lh;
             919     struct inet_protosw *answer;
             920     int protocol = p->protocol;
             921     struct list_head *last_perm;
             922
             923     spin_lock_bh(&inetsw_lock);
             925     if (p->type >= SOCK_MAX)
             926         goto out_illegal;
             928     /* If we are trying to override a permanent protocol, bail. */
             929     answer = NULL;
             930     last_perm = &inetsw[p->type];
             931     list_for_each(lh, &inetsw[p->type]) {
             932         answer = list_entry(lh, struct inet_protosw, list);
             934         /* Check only the non-wild match. */
             935         if (INET_PROTOSW_PERMANENT & answer->flags) {
             936             if (protocol == answer->protocol)
             937                 break;
             938             last_perm = lh;
             939         }
             941         answer = NULL;
             942     }
             943     if (answer)
             944         goto out_permanent;
             943     if (answer)
             944         goto out_permanent;
             945
             946     /* Add the new entry after the last permanent entry if any, so that
             947      * the new entry does not override a permanent entry when matched with
             948      * a wild-card protocol. But it is allowed to override any existing
             949      * non-permanent entry.  This means that when we remove this entry, the
             950      * system automatically returns to the old behavior.
             951      */
             952     list_add_rcu(&p->list, last_perm);
             953 out:
             954     spin_unlock_bh(&inetsw_lock);
             955
             956     synchronize_net();
             957
             958     return;
             .....................
            這個函數完成的工作就是把inetsw_array數組中相同的協議類型下邊的協議,
            加入到inetsw對應的協議類型的鏈表中去,因為事實上一對一的關系,所以這個函數要簡單得多
            因為不存在其它成員,所以每一次list_entry都為空值,所以不存在覆蓋和追加的情況,直接調用
            list_add_rcu(&p->list, last_perm);
            把協議類型節點(struct inet_protosw類型的數組的某個元素)添加到鏈表(鏈表首部本身是一個數組,
            數組索引是協議對應的協議類型的值)的第一個成員.

            OK,繞了這么大一圈子,了解了協議的封裝及鏈表的注冊. 現在回到inet_create中來
             220 /*
             221  *  Create an inet socket.
             222  */
             223
             224 static int inet_create(struct socket *sock, int protocol)
             225 {
             226     struct sock *sk;
             227     struct list_head *p;
             228     struct inet_protosw *answer;
             229     struct inet_sock *inet;
             230     struct proto *answer_prot;
             231     unsigned char answer_flags;
             232     char answer_no_check;
             233     int try_loading_module = 0;
             234     int err;
             235
             236     sock->state = SS_UNCONNECTED;
            socket的初始狀態設置為“未連接”,這意味著面向連接的協議類型,如 tcp,在使用之前必須建立連接, 修改狀態位.

             237
             238     /* Look for the requested type/protocol pair. */
             239     answer = NULL;
             240 lookup_protocol:
             241     err = -ESOCKTNOSUPPORT;
             242     rcu_read_lock();
             243     list_for_each_rcu(p, &inetsw[sock->type]) {
             244         answer = list_entry(p, struct inet_protosw, list);
             245
             246         /* Check the non-wild match. */
             247         if (protocol == answer->protocol) {
             248             if (protocol != IPPROTO_IP)
             249                 break;
             250         } else {
             251             /* Check for the two wild cases. */
             252             if (IPPROTO_IP == protocol) {
             253                 protocol = answer->protocol;
             254                 break;
             255             }
             256             if (IPPROTO_IP == answer->protocol)
             257                 break;
             258         }
             259         err = -EPROTONOSUPPORT;
             260         answer = NULL;
             261     }                                                                                                                  
            這個循環根據socket(2)調用的protocol把之前在鏈表中注冊的協議節點找出來.
            一個問題是,因為一一對應關系的存在,用戶態調用socket(2)的時候,常常第三個參數直接就置 0 了.
            也就是這里protocol為 0.那內核又如何處理這一默認值呢?
            也就是protocol != answer->protocol,而是被if (IPPROTO_IP == protocol) 所匹配了.
            這樣將protocol置為鏈表中第一個協議,而當循環結束時,answer自然也是指向這個鏈表中的第一個注冊節點.
            假設SOCK_STREAM下同時注冊了TCP和123,那么這里默認就取TCP了.當然如果把123在inetsw_array數組中的
            位置調前,那么就 默認取123了.

            將創建的socket的ops函數指針集指向具體協議類型的.例如創建的是SOCK_STREAM,
            那么就指向了inet_stream_ops.
             289     sock->ops = answer->ops;
            answer_prot指針指向當前要創建的socket的協議類型下邊的協議,如上例它就是IPPROTO_TCP的tcp_prot結構
             290     answer_prot = answer->prot;
             291     answer_no_check = answer->no_check;
             292     answer_flags = answer->flags;
             293     rcu_read_unlock();
             294
             295     BUG_TRAP(answer_prot->slab != NULL);

            接下來一個重要的工作,就是為 socket 分配一個sock,并初始化它
             298     sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1);
             299     if (sk == NULL)
             300         goto out;
             301
             302     err = 0;
             303     sk->sk_no_check = answer_no_check;
             304     if (INET_PROTOSW_REUSE & answer_flags)
             305         sk->sk_reuse = 1;
             306
             307     inet = inet_sk(sk);
             308     inet->is_icsk = INET_PROTOSW_ICSK & answer_flags;
             309
             310     if (SOCK_RAW == sock->type) {
             311         inet->num = protocol;
             312         if (IPPROTO_RAW == protocol)
             313             inet->hdrincl = 1;
             314     }
             315
             316     if (ipv4_config.no_pmtu_disc)
             317         inet->pmtudisc = IP_PMTUDISC_DONT;
             318     else
             319         inet->pmtudisc = IP_PMTUDISC_WANT;

             321     inet->id = 0;
             322
             323     sock_init_data(sock, sk);
             324
             325     sk->sk_destruct    = inet_sock_destruct;
             326     sk->sk_family      = PF_INET;
             327     sk->sk_protocol    = protocol;
             328     sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
             329
             330     inet->uc_ttl    = -1;
             331     inet->mc_loop   = 1;
             332     inet->mc_ttl    = 1;
             333     inet->mc_index  = 0;
             334     inet->mc_list   = NULL;
             335
             336     sk_refcnt_debug_inc(sk);
             337
             338     if (inet->num) {
             339         /* It assumes that any protocol which allows
             340          * the user to assign a number at socket
             341          * creation time automatically
             342          * shares.
             343          */
             344         inet->sport = htons(inet->num);
             345         /* Add to protocol hash chains. */
             346         sk->sk_prot->hash(sk);
             347     }
             348
             349     if (sk->sk_prot->init) {
             350         err = sk->sk_prot->init(sk);
             351         if (err)
             352             sk_common_release(sk);
             353     }
             354 out:
             355     return err;
             356 out_rcu_unlock:
             357     rcu_read_unlock();  
             358     goto out;
             359 }
            雖然create的代碼就到這兒了,不過要說清楚sk的分配,還得費上大力氣.每一個 Socket 套接字,
            都有一個對應的struct socket結構來描述(內核中一般使用名稱為sock),但是同時又有一個
            struct sock結構(內核中一般使用名稱為 sk).兩者之間是一一對應的關系.在后面的sock_init_data函數中可以看到
            sk->sk_socket=sock;
            sock->sk=sk;
            這樣的代碼.

            socket結構和sock結構實際上是同一個事物的兩個方面.不妨說socket結構是面向進程和系統調用界面的側面,
            而sock結構則是面向底層驅動程序的側面.設計者把socket套接字中與文件系統關系比較密切的那一部份放在
            socket結構中而把與通信關系比較密切的那一部份,則單獨成為一個數結結構,那就是sock結構.
            由于這兩部份邏輯上本來就是一體的,所以要通過指針互相指向對方形成一對一的關系.

            再暫時回到inet_init中來,初始化工作中有如下代碼:
            1262     rc = proto_register(&tcp_prot, 1);
            1263     if (rc)
            1264         goto out;
            1265
            1266     rc = proto_register(&udp_prot, 1);
            1267     if (rc)
            1268         goto out_unregister_tcp_proto;
            1269
            1270     rc = proto_register(&raw_prot, 1);
            1271     if (rc)
            1272         goto out_unregister_udp_proto;
            這里為每個protocol都調用了proto_register函數,其重要功能之一就是根據協議的obj_size成員的大小,
            為協議創建高速緩存.
            1701 static DEFINE_RWLOCK(proto_list_lock);
            1702 static LIST_HEAD(proto_list);
            1703
            1704 int proto_register(struct proto *prot, int alloc_slab)
            1705 {
            1706     char *request_sock_slab_name = NULL;
            1707     char *timewait_sock_slab_name;
            1708     int rc = -ENOBUFS;
            1709
            1710     if (alloc_slab) {

            可以看到函數最重要的功能就是根據prot的obj_size成員的大小為協議創建高速緩存
            1711         prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
            1712                            SLAB_HWCACHE_ALIGN, NULL, NULL);
            1713
            1714         if (prot->slab == NULL) {
            1715             printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
            1716                    prot->name);
            1717             goto out;
            1718         }
            1719
            順便看到它的另一個重要的功能是維護一個以proto_list為首的鏈表
            1758     write_lock(&proto_list_lock);
            1759     list_add(&prot->node, &proto_list);
            1760     write_unlock(&proto_list_lock);
            這里要注意的是prot->obj_size的大小,它它非僅僅是一個sk的大小,以 TCP為例:
            .obj_size = sizeof(struct tcp_sock)。稍后再來分析這個東東

            回到inet_create()函數中來,其調用sk_alloc()分配一個sk
            sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1);
            840 struct sock *sk_alloc(int family, gfp_t priority,
             841               struct proto *prot, int zero_it)
             842 {
             843     struct sock *sk = NULL;
             844     kmem_cache_t *slab = prot->slab;
             845
             846     if (slab != NULL)
             847         sk = kmem_cache_alloc(slab, priority);
             848     else
             849         sk = kmalloc(prot->obj_size, priority);
             850
             851     if (sk) {
             852         if (zero_it) {
             853             memset(sk, 0, prot->obj_size);
             854             sk->sk_family = family;
             855             /*
             856              * See comment in struct sock definition to understand
             857              * why we need sk_prot_creator -acme
             858              */
             859             sk->sk_prot = sk->sk_prot_creator = prot;
             860             sock_lock_init(sk);
             861         }
             862        
             863         if (security_sk_alloc(sk, family, priority))
             864             goto out_free;
             865
             866         if (!try_module_get(prot->owner))
             867             goto out_free;
             868     }
             869     return sk;
             870
             871 out_free:
             872     if (slab != NULL)
             873         kmem_cache_free(slab, sk);
             874     else
             875         kfree(sk);
             876     return NULL;               
             877 }
            在之前創建的高速緩存中申請分配一個slab緩存項并清零,然后設置協議族,并把sk中的sk_prot與對應的協議關聯起來

            初始化sk

            分配完成sk后另一個重要的功能就是初始化它,sk的成員相當復雜,其主要的初始化工作是在函數sock_init_data()
            中完成的.
            1477 void sock_init_data(struct socket *sock, struct sock *sk)
            1478 {
            1479     skb_queue_head_init(&sk->sk_receive_queue);
            1480     skb_queue_head_init(&sk->sk_write_queue);
            1481     skb_queue_head_init(&sk->sk_error_queue);
            sock結構中有三個重要的雙向隊列分別是sk_receive_queue,sk_write_queue和sk_error_queue
            從它們的名字就可以看出來其作用了
            隊列并非采用通用的list_head來維護而是使用skb_buffer隊列
            // 109 struct sk_buff_head {                                                                                                  
            // 110     /* These two members must be first. */
            // 111     struct sk_buff  *next;
            // 112     struct sk_buff  *prev;
            // 113    
            // 114     __u32       qlen;
            // 115     spinlock_t  lock;
            // 116 }; 
            這樣隊列中指向的每一個skb_buffer就是一個數據包,分別是接收、發送和投遞錯誤
            剩余的就是初始化其它成員變量了,后面再來專門分析這些成員的作用
            1482 #ifdef CONFIG_NET_DMA
            1483     skb_queue_head_init(&sk->sk_async_wait_queue);
            1484 #endif
            1485
            1486     sk->sk_send_head    =   NULL;
            1487
            1488     init_timer(&sk->sk_timer);
            1489    
            1490     sk->sk_allocation   =   GFP_KERNEL;
            1491     sk->sk_rcvbuf       =   sysctl_rmem_default;
            1492     sk->sk_sndbuf       =   sysctl_wmem_default;
            1493     sk->sk_state        =   TCP_CLOSE;
            1494     sk->sk_socket       =   sock;
            1495
            1496     sock_set_flag(sk, SOCK_ZAPPED);
            1497
            1498     if(sock)
            1499     {
            1500         sk->sk_type =   sock->type;
            1501         sk->sk_sleep    =   &sock->wait;
            1502         sock->sk    =   sk;
            1503     } else
            1504         sk->sk_sleep    =   NULL;
            1505
            1506     rwlock_init(&sk->sk_dst_lock);
            1507     rwlock_init(&sk->sk_callback_lock);
            1508     lockdep_set_class(&sk->sk_callback_lock,
            1509                af_callback_keys + sk->sk_family);
            1510
            1511     sk->sk_state_change =   sock_def_wakeup;
            1512     sk->sk_data_ready   =   sock_def_readable;
            1513     sk->sk_write_space  =   sock_def_write_space;  
            1514     sk->sk_error_report =   sock_def_error_report;
            1515     sk->sk_destruct     =   sock_def_destruct;
            1516
            1517     sk->sk_sndmsg_page  =   NULL;
            1518     sk->sk_sndmsg_off   =   0;
            1519
            1520     sk->sk_peercred.pid     =   0;
            1521     sk->sk_peercred.uid =   -1;
            1522     sk->sk_peercred.gid =   -1;
            1523     sk->sk_write_pending    =   0;
            1524     sk->sk_rcvlowat     =   1;
            1525     sk->sk_rcvtimeo     =   MAX_SCHEDULE_TIMEOUT;
            1526     sk->sk_sndtimeo     =   MAX_SCHEDULE_TIMEOUT;
            1527
            1528     sk->sk_stamp.tv_sec     = -1L;
            1529     sk->sk_stamp.tv_usec    = -1L;
            1530
            1531     atomic_set(&sk->sk_refcnt, 1);
            1532 }

            inet_create函數中除了初始化sk成員的值還有一部份代碼是初始化一個inet的東東
             307     inet = inet_sk(sk);
             308     inet->is_icsk = INET_PROTOSW_ICSK & answer_flags;

            inet是一個struct inet_sock結構類型來看它的定義
            struct inet_sock {
                    /* sk and pinet6 has to be the first two members of inet_sock */
                    struct sock                sk;
                           ……
            }
            我們說sock是面向用戶態調用而sk是面向內核驅動調用的,那sk是如何與協議棧交互的呢?
            對于每一個類型的協議,為了與 sk 聯系起來都定義了一個struct XXX_sock結構XXX是協議名
            struct tcp_sock {
                    /* inet_sock has to be the first member of tcp_sock */
                    struct inet_sock        inet;
                    int        tcp_header_len;        /* Bytes of tcp header to send                */
                    ……

            struct udp_sock {
                    /* inet_sock has to be the first member */
                    struct inet_sock inet;
                    int                 pending;        /* Any pending frames ? */
                    unsigned int         corkflag;        /* Cork is required */
                      __u16                 encap_type;        /* Is this an Encapsulation socket? */
                    /*
                     * Following member retains the infomation to create a UDP header
                     * when the socket is uncorked.
                     */
                    __u16                 len;                /* total length of pending frames */
            };
             
            struct raw_sock {
                    /* inet_sock has to be the first member */
                    struct inet_sock   inet;
                    struct icmp_filter filter;
            };
             
            很明顯它們的結構定義是“af_inet一般屬性+自己的私有屬性”, 因為它們的第一個成員總是inet 
             
            現在回頭來找一下起初在af_inet.c中封裝協議注冊的時候size成員, 對于 tcp 而言:
            .obj_size  = sizeof(struct tcp_sock),
            其它協議類似.
            以obj_size來確定每個slab緩存項分配的大小,所以我們就可說每次申請分配的實際上是一個struct XXX_sock
            結構大小的結構.因為都是定義于上層結構的第一個成員,可以使用強制類型轉換來使用這塊分配的內存空間.
            例如inet = inet_sk(sk);
             
            static inline struct inet_sock *inet_sk(const struct sock *sk)
            {
                    return (struct inet_sock *)sk;
            }
             
            struct tcp_sock *tp = tcp_sk(sk);
             
            static inline struct tcp_sock *tcp_sk(const struct sock *sk)
            {
                    return (struct tcp_sock *)sk;
            }
             
            OK,inet_create()運行完,一個socket套接字基本上就創建完畢了,剩下的就是與文件系統掛鉤,回到最初的sys_socket()
            函數中來,它在調用完sock_create()后,緊接著調用sock_map_fd()函數
             422 int sock_map_fd(struct socket *sock)
             423 {
             424     struct file *newfile;
             425     int fd = sock_alloc_fd(&newfile);
             426
             427     if (likely(fd >= 0)) {
             428         int err = sock_attach_fd(sock, newfile);
             429
             430         if (unlikely(err < 0)) {           
             431             put_filp(newfile);
             432             put_unused_fd(fd);
             433             return err;  
             434         }                
             435         fd_install(fd, newfile);   
             436     }                    
             437     return fd;           
             438 }
            這個函數的核心思想在一開始就已經分析過了.從進程的角度來講一個socket套接字就是一個特殊的已打開的文件.
            前面分配好一個socket 后,這里要做的就是將它與文件系統拉上親戚關系.
            首先獲取一個空閑的文件描述符號和file結構,然后在文件系統中分配一個目錄項(d_alloc),使其指向已經分配的inode節
            點(d_add),然后把其目錄項掛在sockfs文件系統的根目錄之下,并且把目錄項的指針d_op設置成
            指向sockfs_dentry_operati,這個數據結構通過函數指針提供他與文件路徑有關的操作.
            static struct dentry_operations sockfs_dentry_operations = {
                    .d_delete =        sockfs_delete_dentry,
            };
            最后一步就是將file結構中的f_op和sock結構中的i_fop都指向socket_file_ops,它是一個函數指針集,
            指向了socket面向文件系統的用戶態調用的一些接口函數.
            static struct file_operations socket_file_ops = {
                    .owner =        THIS_MODULE,
                    .llseek =        no_llseek,
                    .aio_read =        sock_aio_read,
                    .aio_write =        sock_aio_write,
                    .poll =                sock_poll,
                    .unlocked_ioctl = sock_ioctl,
                    .mmap =                sock_mmap,
                    .open =                sock_no_open,        /* special open code to disallow open via /proc */
                    .release =        sock_close,
                    .fasync =        sock_fasync,
                    .readv =        sock_readv,
                    .writev =        sock_writev,
                    .sendpage =        sock_sendpage
            };
            OK,到這里整個socket套接字的創建工作就宣告完成了

            寫到這里,可以為 socket 的創建下一個小結了:
            1. 所謂創建socket,對內核而言最重要的工作就是分配sock與sk
            2. sock面向上層系統調用,主要是與文件系統交互.通過進程的current指針的files,結合創建socket
              時返回的文件描符述,可以找到內 核中對應的struct file,再根據file的f_dentry可以找到對應的目
              錄項,而目錄項struct dentry中,有d_inode指針,指向與sock封裝在一起的inode.sock又與
              sk指針互指一一對應.在這串結構中有兩個重要的函數集指針,一個是文件系統struct file中的
              f_op指針,它指向了對應的用戶態調用的read,write等操調用,但不支持open,
              另一個是struct socket結構,即sock的ops指針,它在inet_create()中被置為
              sock->ops = answer->ops指向具體協議類型的ops
              例如inet_stream_ops,inet_dgram_ops或者是inet_sockraw_ops等等
              它用來支持上層的socket的其它API調用
            3. sk面向內核協議棧,協議棧與它的接口數據結構是struct protoname_sock,該結構中包含了一般性
              的inet結構和自己的私有成員,struct inet_sock的第一個成員就是一個 sk 指針,而分配的sk實
              際上空間大小是struct protoname_sock,所以這三者可以通過強制類型轉換來獲取需要的指針
            4. 由于水平有限,文件系統的一些細節被我跳過了,sk 中的大多數成員變量的作用,也被我跳出過了.
              呵呵,還好,終于還是把這塊流程給初步分析出來了.另外當時寫的時候,沒有想到會寫這么長,
              大大超出了每貼的字限制。所以,每個小節內容跟標題可能會有點對不上號。

            posted on 2013-02-16 21:51 大龍 閱讀(1196) 評論(1)  編輯 收藏 引用

            評論

            # re: Linux TCP/IP協議棧之Socket的實現分析(一 套接字的創建) --- 轉 2013-08-09 15:31 wtd321@163.com

            sadsd  回復  更多評論   

            久久久久亚洲AV成人网人人网站 | AV狠狠色丁香婷婷综合久久| 久久毛片一区二区| 91精品国产91热久久久久福利| 国产亚洲精品自在久久| 国产亚洲美女精品久久久2020| 久久久国产99久久国产一| 久久亚洲国产成人影院| 久久国内免费视频| 精品综合久久久久久97| 亚洲AV无码久久精品蜜桃| 午夜精品久久久久久久| 欧洲精品久久久av无码电影| 久久精品国产亚洲AV无码麻豆| 久久精品国产亚洲AV无码偷窥| 久久精品www| 亚洲国产成人久久精品99| 久久婷婷色香五月综合激情| 免费精品久久天干天干| 精产国品久久一二三产区区别| 亚洲精品国产美女久久久| 久久国产精品77777| 久久综合综合久久狠狠狠97色88| 99久久精品免费国产大片| 天堂无码久久综合东京热| 日韩人妻无码精品久久免费一 | 国产精品gz久久久| 色天使久久综合网天天| 无遮挡粉嫩小泬久久久久久久| 狠狠色丁香久久综合婷婷| 久久久久久一区国产精品| 亚洲日韩中文无码久久| 伊人久久综合热线大杳蕉下载| 人妻中文久久久久| 久久国产精品99久久久久久老狼| 久久综合给合综合久久| 国产高潮国产高潮久久久| 欧美一级久久久久久久大| 狠狠色丁香久久婷婷综| 人妻无码αv中文字幕久久| 日日狠狠久久偷偷色综合免费|