// 创建套接字,系统调用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];
};