網絡子系統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];
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章