先看总的函数调用流程
应用层 | socket层 | inet层
socket------->sys_socket---->sock_create->__sock_create--->inet_create
int socket(int domain, int type, int protocol)
domain:协议族 AF_INET,AF_UNIX等
type:指定socket类型,常用的socket类型有,SOCK_STREAM(字节流)、SOCK_DGRAM(数据报)、SOCK_RAW(原始套接口)等,
在Linux 2.6.27后可以通过|设置SOCK_NONBLOCK,SOCK_CLOEXEC,来修改socket行为
protocol:指定协议 如IPPROTO_TCP,IPPTOTO_UDP, IPPROTO_IP
返回值: 成功返回一个>0的文件描述符,否则返回-1
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
int retval;
struct socket *sock;
int flags;
//检查宏定义的值是否一致
//BUILD_BUG_ON的作用是在编译的时候如果condition为真,则编译出错
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);
//type的组成为 socket类型 | 标志位(可以不设置)
//获得SOCK_CLOEXEC或SOCK_NONBLOCK标志位
//通过SOCK_TYPE_MASK为0xf 可看出type的低四位为socket类型
flags = type & ~SOCK_TYPE_MASK;
//检查设置的flags是否为 SOCK_CLOEXEC或SOCK_NONBLOCK中的值,
//不是的话返回错误
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
//获得socket类型
type &= SOCK_TYPE_MASK;
//防止O_NONBLOCK和SOCK_NONBLOCK值不一样的问题
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
//创建一个socket{}
retval = sock_create(family, type, protocol, &sock);
if (retval < 0)
goto out;
//将fd于socket结构体进行关联 用于之后根据fd来查找socket结构体
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的使用锁
sock_release(sock);
return retval;
}
int sock_create(int family, int type, int protocol, struct socket **res)
{
return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}
static int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
{
int err;
st