網絡子係統75_套接字創建
// 創建套接字,係統調用sys_socket // 步驟: // 1.分配套接字描述符 // 2.創建套接字對應的文件描述符 // 參數: // 協議族: 對於TCP/IP協議族,該參數為AF_INET // 套接字類型:流套接字類型為SOCK_STREAM, 數據報套接字類型為SOCK_DGRAM // 通信協議: 單個協議係列中的不同傳輸協議,在internet通信域中,此參數一般取值為0, // 係統根據套接字的類型決定應使用的傳輸層協議 1.1 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) { int retval; struct socket *sock; int flags; .... //創建套接字 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: //返回文件描述符 return retval; out_release: sock_release(sock); return retval; } // 創建套接字 // 步驟: // 1.安全性檢查 // 2.分配socket描述符 // 3.由具體協議執行進一步初始化 // 參數: // kern,指示操作發起者所在層 2.1 int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern) { int err; struct socket *sock; const struct net_proto_family *pf; //檢查協議族 if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; //檢查套接字類型 if (type < 0 || type >= SOCK_MAX) return -EINVAL; //兼容性檢查,PF_INET中的SOCK_PACKET現在調整為PF_PACKET協議族 if (family == PF_INET && type == SOCK_PACKET) { static int warned; if (!warned) { warned = 1; printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); } family = PF_PACKET; } //分配套接字內存 sock = sock_alloc(); //套接字類型 sock->type = type; rcu_read_lock(); pf = rcu_dereference(net_families[family]); rcu_read_unlock(); //由具體的協議族執行進一步的初始化 err = pf->create(net, sock, protocol, kern); if (err < 0) goto out_module_put; //返回創建好的套接字 *res = sock; return 0; } // 分配socket描述符 // socket描述符與inode節點相綁定,初始化inode操作集合 2.2 static struct socket *sock_alloc(void) { struct inode *inode; struct socket *sock; //分配inode inode = new_inode_pseudo(sock_mnt->mnt_sb); if (!inode) return NULL; //inode與socket描述符同時分配,通過container_of返回socket描述符 sock = SOCKET_I(inode); //inode號 inode->i_ino = get_next_ino(); //S_IFSOCK表示此inode為socket節點 inode->i_mode = S_IFSOCK | S_IRWXUGO; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); //inode操作結合 inode->i_op = &sockfs_inode_ops; //inode引用計數 this_cpu_add(sockets_in_use, 1); return sock; } // 為套接字描述符分配文件描述符 3.1 static int sock_map_fd(struct socket *sock, int flags) { //內核空間文件描述符 struct file *newfile; //用戶空間文件描述符 int fd = get_unused_fd_flags(flags); if (unlikely(fd < 0)) return fd; //分配文件描述符 newfile = sock_alloc_file(sock, flags, NULL); if (likely(!IS_ERR(newfile))) { //向進程描述符安裝文件描述符 fd_install(fd, newfile); //返回用戶空間描述符 return fd; } put_unused_fd(fd); return PTR_ERR(newfile); } // 文件係統特定於進程的信息 4.1 struct task_struct { ... //所有打開文件的信息 struct files_struct *files; ... } 4.2 struct files_struct { atomic_t count; struct fdtable __rcu *fdt; struct fdtable fdtab; //下一個可用的文件描述符 int next_fd; unsigned long close_on_exec_init[1]; //比特位域,如果對應比特置位,則對應的文件描述符在使用中。 unsigned long open_fds_init[1]; //打開文件數組,NR_OPEN_DEFAULT=LONG_BITS struct file __rcu * fd_array[NR_OPEN_DEFAULT]; };
最後更新:2017-04-03 12:55:16