• 重要结构体

  • struct socket 结构体

  1. // 普通的 BSD 标准 socket 结构体
  2. // socket_state: socket 状态, 连接?不连接?
  3. // type: socket type (%SOCK_STREAM, etc)
  4. // flags: socket flags (%SOCK_NOSPACE, etc)
  5. // ops: 专用协议的socket的操作
  6. // file: 与socket 有关的指针列表
  7. // sk: 负责协议相关结构体,这样就让这个这个结构体和协议分开。
  8. // wq: 等待队列
  9. struct socket {
  10. socket_state state;
  11. kmemcheck_bitfield_begin(type);
  12. short type;
  13. kmemcheck_bitfield_end(type);
  14. unsigned long flags;
  15. struct socket_wq __rcu *wq;
  16. struct file *file;
  17. struct sock *sk;
  18. const struct proto_ops *ops;
  19. };
  • struct socket 的创建

  1. // socket() 本质上是 glibc 中的函数,执行的实际上是 sys_socketcall() 系统调用。
  2. // sys_socketcall() 几乎是所有的socket函数的入口,
  3. // 也就是 bind,connect 等函数都是需要asmlinkage long sys_socketcall(int call, unsigned long __user *args); 、、sys_socketcall() 作为入口,函数如下:
  4. // include/linux/syscalls.h
  5. asmlinkage long sys_socketcall(int call, unsigned long __user *args);
  1. // net/socket.c
  2. SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
  3. {
  4. unsigned long a[AUDITSC_ARGS];
  5. unsigned long a0, a1;
  6. int err;
  7. unsigned int len;
  8. if (call < 1 || call > SYS_SENDMMSG)
  9. return -EINVAL;
  10. len = nargs[call];
  11. if (len > sizeof(a))
  12. return -EINVAL;
  13. /* copy_from_user should be SMP safe. */
  14. if (copy_from_user(a, args, len))
  15. return -EFAULT;
  16. err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
  17. if (err)
  18. return err;
  19. a0 = a[0];
  20. a1 = a[1];
  21. // 判断,然后运行相对应的函数
  22. switch (call) {
  23. case SYS_SOCKET: // 这里就是 sys_socket(),
  24. err = sys_socket(a0, a1, a[2]);
  25. break;
  26. case SYS_BIND:
  27. err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
  28. break;
  29. case SYS_CONNECT:
  30. err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
  31. break;
  32. case SYS_LISTEN:
  33. err = sys_listen(a0, a1);
  34. break;
  35. // ... ...
  36. default:
  37. err = -EINVAL;
  38. break;
  39. }
  40. return err;
  41. }
  1. // include/linux/syscalls.h
  2. asmlinkage long sys_socket(int, int, int);
  3. // net/socket.c
  4. SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
  5. {
  6. int retval;
  7. struct socket *sock;
  8. int flags;
  9. /* Check the SOCK_* constants for consistency. */
  10. BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
  11. BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
  12. BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
  13. BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);
  14. flags = type & ~SOCK_TYPE_MASK;
  15. if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
  16. return -EINVAL;
  17. type &= SOCK_TYPE_MASK;
  18. if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
  19. flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
  20. // 这里创建了 socket 结构体
  21. retval = sock_create(family, type, protocol, &sock);
  22. if (retval < 0)
  23. goto out;
  24. // 与文件系统进行关联
  25. retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
  26. if (retval < 0)
  27. goto out_release;
  28. out:
  29. /* It may be already another descriptor 8) Not kernel problem. */
  30. return retval;
  31. out_release:
  32. sock_release(sock);
  33. return retval;
  34. }
  • sock_create() 函数

  1. // include/linux/net.h
  2. int sock_create(int family, int type, int proto, struct socket **res);
  3. // net/socket.c
  4. int sock_create(int family, int type, int protocol, struct socket **res)
  5. {
  6. return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
  7. }
  8. EXPORT_SYMBOL(sock_create);
  9. // include/linux/net.h
  10. int __sock_create(struct net *net, int family, int type, int proto,
  11. struct socket **res, int kern);
  12. // net/socket.c
  13. int __sock_create(struct net *net, int family, int type, int protocol,
  14. struct socket **res, int kern)
  15. {
  16. int err;
  17. struct socket *sock;
  18. const struct net_proto_family *pf;
  19. /*
  20. * Check protocol is in range
  21. */
  22. // 检查 协议族是否在范围呢
  23. if (family < 0 || family >= NPROTO)
  24. return -EAFNOSUPPORT;
  25. if (type < 0 || type >= SOCK_MAX) // 检查类型
  26. return -EINVAL;
  27. /* Compatibility.
  28. This uglymoron is moved from INET layer to here to avoid
  29. deadlock in module load.
  30. */ // 检查用的是PF_INET 其实这个都是兼容的。
  31. if (family == PF_INET && type == SOCK_PACKET) {
  32. static int warned;
  33. if (!warned) {
  34. warned = 1;
  35. pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
  36. current->comm);
  37. }
  38. family = PF_PACKET;
  39. }
  40. // 安全机制检查
  41. err = security_socket_create(family, type, protocol, kern);
  42. if (err)
  43. return err;
  44. /*
  45. * Allocate the socket and allow the family to set things up. if
  46. * the protocol is 0, the family is instructed to select an appropriate
  47. * default.
  48. */ // ----> sock_alloc 接下面
  49. sock = sock_alloc();
  50. if (!sock) {
  51. net_warn_ratelimited("socket: no more sockets\n");
  52. return -ENFILE; /* Not exactly a match, but its the
  53. closest posix thing */
  54. }
  55. sock->type = type;
  56. // ... ...
  57. return 0;
  58. // ... ...
  59. }
  60. EXPORT_SYMBOL(__sock_create);
  • sock_alloc() 函数解析,被上面的 __sock_create() 函数调用

  1. // net/socket.c
  2. static struct socket *sock_alloc(void)
  3. {
  4. struct inode *inode;
  5. struct socket *sock;
  6. inode = new_inode_pseudo(sock_mnt->mnt_sb);
  7. if (!inode)
  8. return NULL;
  9. sock = SOCKET_I(inode);
  10. kmemcheck_annotate_bitfield(sock, type);
  11. inode->i_ino = get_next_ino();
  12. inode->i_mode = S_IFSOCK | S_IRWXUGO; // 模式
  13. inode->i_uid = current_fsuid(); // 获取当前的uid
  14. inode->i_gid = current_fsgid(); // 获取当前的gid
  15. inode->i_op = &sockfs_inode_ops; // 操作
  16. this_cpu_add(sockets_in_use, 1);
  17. return sock;
  18. }
  19. // 申请一个 socket 结构体 ,名字为 sock
  20. // 申请一个新的节点和一个新的 socket 项目, 绑定他们两个并且初始化
  21. // 如果申请inode 失败返回 NULL, 或者返回sock
  1. // 接下来我们再看到 SOCKET_I(inode);
  2. // include/net/sock.h
  3. static inline struct socket *SOCKET_I(struct inode *inode)
  4. {
  5. return &container_of(inode, struct socket_alloc, vfs_inode)->socket;
  6. }
  7. // 然后我们发现,返回的是 inode 内的socket 结构体。
  8. // 我们可以分析一个 container_of() 这个是怎么定义的。
  9. // include/linux/kernel.h
  10. #define container_of(ptr, type, member) ({ \
  11. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  12. (type *)( (char *)__mptr - offsetof(type,member) );})
  13. // typeof 将 ptr 的指针临时保存起来为 __mptr
  14. // 然后用这个 __mptr 指针减去下面的 member 的便宜量。
  15. // 得到的就是 type 这个结构体的头指针。
  16. // offsetof include/linux/stddef.h
  17. #undef offsetof
  18. #ifdef __compiler_offsetof
  19. #define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)
  20. #else
  21. #define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
  22. #endif
  23. // 反正这里有点难理解,最后得到的结果是 type 这个结构体的头指针。
  24. // 所以说 SOCKET_I() 得到的是 struct socket_alloc 的头指针
  25. // include/net/sock.h
  26. struct socket_alloc {
  27. struct socket socket;
  28. struct inode vfs_inode;
  29. };
  • 回到 __sock_create() 继续分析

  1. // net/socket.c --> __sock_create()
  2. #ifdef CONFIG_MODULES
  3. /* Attempt to load a protocol module if the find failed.
  4. *
  5. * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
  6. * requested real, full-featured networking support upon configuration.
  7. * Otherwise module support will break!
  8. */
  9. if (rcu_access_pointer(net_families[family]) == NULL)
  10. request_module("net-pf-%d", family);
  11. #endif
  1. 如果在 make menuconfig 中选上 编译成模块的选项,则会运行上面这个部分。
  2. 里面先是检查对应的协议族的操作表是否已经安装,如果没有安装则使用 request_module 进行安装,现在都是在 TCP/IP协议下进行分析,所以 family AF_INET , 也就是 2 所以实际检查的全局变量是 net_families[2], 这个全局变量是在系统初始化时由 net/ipv4/af_inet.c 文件进行安装,具体代码是:
  1. // net/ipv4/af_inet.c
  2. static int __init inet_init(void)
  3. {
  4. struct inet_protosw *q;
  5. struct list_head *r;
  6. int rc = -EINVAL;
  7. sock_skb_cb_check_size(sizeof(struct inet_skb_parm));
  8. // 各个协议的注册
  9. rc = proto_register(&tcp_prot, 1);
  10. if (rc)
  11. goto out;
  12. rc = proto_register(&udp_prot, 1);
  13. if (rc)
  14. goto out_unregister_tcp_proto;
  15. rc = proto_register(&raw_prot, 1);
  16. if (rc)
  17. goto out_unregister_udp_proto;
  18. rc = proto_register(&ping_prot, 1);
  19. if (rc)
  20. goto out_unregister_raw_proto;
  21. /*
  22. * Tell SOCKET that we are alive...
  23. */
  24. (void)sock_register(&inet_family_ops);
  25. #ifdef CONFIG_SYSCTL
  26. ip_static_sysctl_init();
  27. #endif
  28. /*
  29. * Add all the base protocols.
  30. */
  31. // 各个协议的添加,添加不成功则报错
  32. if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
  33. pr_crit("%s: Cannot add ICMP protocol\n", __func__);
  34. if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
  35. pr_crit("%s: Cannot add UDP protocol\n", __func__);
  36. if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
  37. pr_crit("%s: Cannot add TCP protocol\n", __func__);
  38. #ifdef CONFIG_IP_MULTICAST
  39. if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
  40. pr_crit("%s: Cannot add IGMP protocol\n", __func__);
  41. #endif
  42. /* Register the socket-side information for inet_create. */
  43. for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
  44. INIT_LIST_HEAD(r);
  45. // 把这个关键性的链接表一个个注册上去
  1. // ******************************************************
  2. // inetsw_array 结构体数组数组, 这里面有包含每个的协议,比如说tcp_prot
  3. static struct inet_protosw inetsw_array[] =
  4. {
  5. {
  6. .type = SOCK_STREAM,
  7. .protocol = IPPROTO_TCP,
  8. .prot = &tcp_prot,
  9. .ops = &inet_stream_ops,
  10. .flags = INET_PROTOSW_PERMANENT |
  11. INET_PROTOSW_ICSK,
  12. },
  13. {
  14. .type = SOCK_DGRAM,
  15. .protocol = IPPROTO_UDP,
  16. .prot = &udp_prot,
  17. .ops = &inet_dgram_ops,
  18. .flags = INET_PROTOSW_PERMANENT,
  19. },
  20. {
  21. .type = SOCK_DGRAM,
  22. .protocol = IPPROTO_ICMP,
  23. .prot = &ping_prot,
  24. .ops = &inet_dgram_ops,
  25. .flags = INET_PROTOSW_REUSE,
  26. },
  27. // ... ...
  28. }
  29. // tcp_prot ---> net/ipv4/tcp_ipv4.c
  30. struct proto tcp_prot = {
  31. .name = "TCP",
  32. .owner = THIS_MODULE,
  33. .close = tcp_close,
  34. .connect = tcp_v4_connect,
  35. .disconnect = tcp_disconnect,
  36. .accept = inet_csk_accept,
  37. .ioctl = tcp_ioctl,
  38. .init = tcp_v4_init_sock, // 这是init 函数会在后面被调用
  39. .destroy = tcp_v4_destroy_sock,
  40. .shutdown = tcp_shutdown,
  41. .setsockopt = tcp_setsockopt,
  42. .getsockopt = tcp_getsockopt,
  43. .recvmsg = tcp_recvmsg,
  44. .sendmsg = tcp_sendmsg,
  45. .sendpage = tcp_sendpage,
  46. .backlog_rcv = tcp_v4_do_rcv,
  47. .release_cb = tcp_release_cb,
  48. .hash = inet_hash,
  49. .unhash = inet_unhash,
  50. .get_port = inet_csk_get_port,
  51. .enter_memory_pressure = tcp_enter_memory_pressure,
  52. .stream_memory_free = tcp_stream_memory_free,
  53. .sockets_allocated = &tcp_sockets_allocated,
  54. .orphan_count = &tcp_orphan_count,
  55. .memory_allocated = &tcp_memory_allocated,
  56. .memory_pressure = &tcp_memory_pressure,
  57. .sysctl_mem = sysctl_tcp_mem,
  58. .sysctl_wmem = sysctl_tcp_wmem,
  59. .sysctl_rmem = sysctl_tcp_rmem,
  60. .max_header = MAX_TCP_HEADER,
  61. .obj_size = sizeof(struct tcp_sock),
  62. .slab_flags = SLAB_DESTROY_BY_RCU,
  63. .twsk_prot = &tcp_timewait_sock_ops,
  64. .rsk_prot = &tcp_request_sock_ops,
  65. .h.hashinfo = &tcp_hashinfo,
  66. .no_autobind = true,
  67. #ifdef CONFIG_COMPAT
  68. .compat_setsockopt = compat_tcp_setsockopt,
  69. .compat_getsockopt = compat_tcp_getsockopt,
  70. #endif
  71. #ifdef CONFIG_MEMCG_KMEM
  72. .init_cgroup = tcp_init_cgroup,
  73. .destroy_cgroup = tcp_destroy_cgroup,
  74. .proto_cgroup = tcp_proto_cgroup,
  75. #endif
  76. };
  77. EXPORT_SYMBOL(tcp_prot);
  78. // ***********************************************************
  1. for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
  2. inet_register_protosw(q);
  3. // 各个协议模块的初始化
  4. /*
  5. * Set the ARP module up
  6. */
  7. arp_init();
  8. /*
  9. * Set the IP module up
  10. */
  11. ip_init();
  12. tcp_v4_init();
  13. /* Setup TCP slab cache for open requests. */
  14. tcp_init();
  15. /* Setup UDP memory threshold */
  16. udp_init();
  17. /* Add UDP-Lite (RFC 3828) */
  18. udplite4_register();
  19. ping_init();
  20. /*
  21. * Set the ICMP layer up
  22. */
  23. if (icmp_init() < 0)
  24. panic("Failed to create the ICMP control socket.\n");
  25. /*
  26. * Initialise the multicast router
  27. */
  28. #if defined(CONFIG_IP_MROUTE)
  29. if (ip_mr_init())
  30. pr_crit("%s: Cannot init ipv4 mroute\n", __func__);
  31. #endif
  32. if (init_inet_pernet_ops())
  33. pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);
  34. /*
  35. * Initialise per-cpu ipv4 mibs
  36. */
  37. if (init_ipv4_mibs())
  38. pr_crit("%s: Cannot init ipv4 mibs\n", __func__);
  39. ipv4_proc_init();
  40. ipfrag_init();
  41. dev_add_pack(&ip_packet_type);
  42. ip_tunnel_core_init();
  43. rc = 0;
  44. out:
  45. return rc;
  46. out_unregister_raw_proto:
  47. proto_unregister(&raw_prot);
  48. out_unregister_udp_proto:
  49. proto_unregister(&udp_prot);
  50. out_unregister_tcp_proto:
  51. proto_unregister(&tcp_prot);
  52. goto out;
  53. }
  54. fs_initcall(inet_init);
  • 很粗浅的看完协议那一部分之后我们回到 __sock_create()

  1. // net/socket.c
  2. // 看到 这个回调函数的调用
  3. err = pf->create(net, sock, protocol, kern);
  4. if (err < 0)
  5. goto out_module_put;
  1. // 先看一个 inet_protosw 结构体
  2. // include/net/protocol.h
  3. /* This is used to register socket interfaces for IP protocols. */
  4. struct inet_protosw {
  5. struct list_head list;
  6. /* These two fields form the lookup key. */
  7. unsigned short type; /* This is the 2nd argument to socket(2). */
  8. unsigned short protocol; /* This is the L4 protocol number. */
  9. struct proto *prot;
  10. const struct proto_ops *ops;
  11. unsigned char flags; /* See INET_PROTOSW_* below. */
  12. };
  13. // 上面的 create 函数对应的是 net/ipv4/af_inet.c 里面的 inet_create 函数
  14. // net/ipv4/af_inet.c
  15. static int inet_create(struct net *net, struct socket *sock, int protocol,
  16. int kern)
  17. {
  18. struct sock *sk;
  19. struct inet_protosw *answer;
  20. struct inet_sock *inet;
  21. struct proto *answer_prot;
  22. unsigned char answer_flags;
  23. int try_loading_module = 0;
  24. int err;
  25. // 检查协议是否在范围之内
  26. if (protocol < 0 || protocol >= IPPROTO_MAX)
  27. return -EINVAL;
  28. // 设置状态为未连接
  29. sock->state = SS_UNCONNECTED;
  30. /* Look for the requested type/protocol pair. */
  31. // 遍历寻找请求的协议类型
  32. lookup_protocol:
  33. err = -ESOCKTNOSUPPORT;
  34. rcu_read_lock();
  35. // 遍历 inetsw[] 数组,其实就是次数而已
  36. list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {
  37. err = 0;
  38. // 检查对应的协议,然后再选择合适的协议
  39. /* Check the non-wild match. */
  40. // 找到对应的协议,如果找到对应的协议,但是protocol 不是 IPPRORO_IP,则直接退出
  41. if (protocol == answer->protocol) {
  42. if (protocol != IPPROTO_IP)
  43. break;
  44. } else {
  45. /* Check for the two wild cases. */
  46. if (IPPROTO_IP == protocol) {
  47. protocol = answer->protocol;
  48. break;
  49. }
  50. if (IPPROTO_IP == answer->protocol)
  51. break;
  52. }
  53. // 如果没有对应的协议则返回错误码
  54. err = -EPROTONOSUPPORT;
  55. }
  56. // 如果没有加载模块的保护措施
  57. if (unlikely(err)) {
  58. if (try_loading_module < 2) {
  59. rcu_read_unlock();
  60. /*
  61. * Be more specific, e.g. net-pf-2-proto-132-type-1
  62. * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)
  63. */
  64. if (++try_loading_module == 1)
  65. request_module("net-pf-%d-proto-%d-type-%d",
  66. PF_INET, protocol, sock->type);
  67. /*
  68. * Fall back to generic, e.g. net-pf-2-proto-132
  69. * (net-pf-PF_INET-proto-IPPROTO_SCTP)
  70. */
  71. else
  72. request_module("net-pf-%d-proto-%d",
  73. PF_INET, protocol);
  74. goto lookup_protocol;
  75. } else
  76. goto out_rcu_unlock;
  77. }
  78. err = -EPERM;
  79. // 检查通用性,只有root 权限然后使用原始套接字
  80. if (sock->type == SOCK_RAW && !kern &&
  81. !ns_capable(net->user_ns, CAP_NET_RAW))
  82. goto out_rcu_unlock;
  83. // 对socket 的操作集合进行了互联。
  84. sock->ops = answer->ops;
  85. answer_prot = answer->prot;
  86. answer_flags = answer->flags;
  87. rcu_read_unlock();
  88. WARN_ON(!answer_prot->slab);
  89. err = -ENOBUFS;
  90. /* 此处调用sk_alloc分配一个struct sock,该结构体庞大,其作用是网络层对socket的表示,意思就是IP协议下有很多东西比如IP地址,网卡接口,端口等等信息需要再socket层中有所体现从而使编程者方便使用,然后就利用指针等形式把内容进行一定程度上的映射。sk_alloc首先对sock->proto和sock_creator进行设置,设置成当前协议对应的proto调用sk_prot_alloc()根据是否提供了slab缓存而判断是使用slab缓存还是通用缓存。只要分配成功,则调用sock_lock_init()对缓存进行初始化,主要是对sock锁、等待队列以及进程数据结构中的网络空间结构进行分配。初始化完了后调用sock_net_set()函数对网络空间结构进行记录,然后最后增加一个net计数器。至此回到inet_create,判断是否成功分配 */
  91. sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern);
  92. if (!sk)
  93. goto out;
  94. err = 0;
  95. if (INET_PROTOSW_REUSE & answer_flags)
  96. sk->sk_reuse = SK_CAN_REUSE;
  97. // 返回一个 struct inet_sock 的指针给 inet
  98. inet = inet_sk(sk);
  99. // 判断是不是面向连通
  100. inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
  101. inet->nodefrag = 0;
  102. // 判断是不是原始套接字,如果是,新建IP头部。
  103. if (SOCK_RAW == sock->type) {
  104. inet->inet_num = protocol;
  105. if (IPPROTO_RAW == protocol)
  106. inet->hdrincl = 1;
  107. }
  108. // 判断是否采用路径 MTU 发现算法
  109. if (net->ipv4.sysctl_ip_no_pmtu_disc)
  110. inet->pmtudisc = IP_PMTUDISC_DONT;
  111. else
  112. inet->pmtudisc = IP_PMTUDISC_WANT;
  113. inet->inet_id = 0;
  114. // 进一步初始化结构体 sk (struct sock)
  115. // sock_init_data: 初始化接收,发送,错误信息队列,三个队列都是双向链表,属于sk_buff_head 结构体,其中会把 sk_buff 结构体串联在一起,初始化数据包发送定时器,变量,(主要是函数指针)
  116. sock_init_data(sock, sk);
  117. sk->sk_destruct = inet_sock_destruct;
  118. sk->sk_protocol = protocol;
  119. sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
  120. inet->uc_ttl = -1;
  121. inet->mc_loop = 1;
  122. inet->mc_ttl = 1;
  123. inet->mc_all = 1;
  124. inet->mc_index = 0;
  125. inet->mc_list = NULL;
  126. inet->rcv_tos = 0;
  127. sk_refcnt_debug_inc(sk);
  128. if (inet->inet_num) {
  129. /* It assumes that any protocol which allows
  130. * the user to assign a number at socket
  131. * creation time automatically
  132. * shares.
  133. */
  134. inet->inet_sport = htons(inet->inet_num);
  135. /* Add to protocol hash chains. */
  136. sk->sk_prot->hash(sk);
  137. }
  138. // 这里,就是调用了协议里面的 init 函数 tcp_v4_init_sock
  139. if (sk->sk_prot->init) {
  140. err = sk->sk_prot->init(sk);
  141. if (err)
  142. sk_common_release(sk);
  143. }
  144. out:
  145. return err;
  146. out_rcu_unlock:
  147. rcu_read_unlock();
  148. goto out;
  149. }
  • tcp_v4_init_sock 函数

  1. static int tcp_v4_init_sock(struct sock *sk)
  2. {
  3. // 强制转换类型
  4. struct inet_connection_sock *icsk = inet_csk(sk);
  5. // 调用这个进行初始化 ,里面就时关于tcp 的一些初始化了,到此为止
  6. tcp_init_sock(sk);
  7. // ipv4 专用操作
  8. icsk->icsk_af_ops = &ipv4_specific;
  9. #ifdef CONFIG_TCP_MD5SIG
  10. tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific;
  11. #endif
  12. return 0;
  13. }
  • 到此, sock_create 分析完毕

  • 最后回到 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)

  1. // net/socket.c
  2. // 刚才分析完毕
  3. retval = sock_create(family, type, protocol, &sock);
  4. if (retval < 0)
  5. goto out;
  6. // socket 映射到文件系统
  7. retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
  8. if (retval < 0)
  9. goto out_release;
  1. // net/socket.c
  2. static int sock_map_fd(struct socket *sock, int flags)
  3. {
  4. struct file *newfile;
  5. int fd = get_unused_fd_flags(flags);
  6. if (unlikely(fd < 0))
  7. return fd;
  8. // 申请一个 sock file 节点
  9. newfile = sock_alloc_file(sock, flags, NULL);
  10. if (likely(!IS_ERR(newfile))) {
  11. fd_install(fd, newfile);
  12. return fd;
  13. }
  14. put_unused_fd(fd);
  15. return PTR_ERR(newfile);
  16. }
  17. // 这里所展现的意思是,把socket当成一个文件节点进行操作,open, read,write ,ioctl 等

Linux kernel 之 socket 创建过程分析的更多相关文章

  1. Linux Kernel ‘/net/socket.c’本地信息泄露漏洞

    漏洞名称: Linux Kernel ‘/net/socket.c’本地信息泄露漏洞 CNNVD编号: CNNVD-201312-037 发布时间: 2013-12-04 更新时间: 2013-12- ...

  2. 上层应用与wpa_supplicant,wpa_supplicant与kernel 相关socket创建交互分析

    单独拿出来,分析以下上层应用与wpa_supplicant   wpa_supplicant与kernel 的socket交互. 关联上层应用与wpa_supplicant的socket的创建.连接流 ...

  3. Linux下进程的创建过程分析(_do_fork do_fork详解)--Linux进程的管理与调度(八)

    Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,clone(确切说vfork创造出来的是轻量 ...

  4. Linux内核Socket实现之------Socket创建(2) 文件描述符

    转载请注明:http://blog.chinaunix.net/uid-20788636-id-4408276.html 1.2 sock_map_fd函数 在用户空间创建了一个socket后,返回值 ...

  5. karottc A Simple linux-virus Analysis、Linux Kernel <= 2.6.37 - Local Privilege Escalation、CVE-2010-4258、CVE-2010-3849、CVE-2010-3850

    catalog . 程序功能概述 . 感染文件 . 前置知识 . 获取ROOT权限: Linux Kernel <= - Local Privilege Escalation 1. 程序功能概述 ...

  6. Intel 80x86 Linux Kernel Interrupt(中断)、Interrupt Priority、Interrupt nesting、Prohibit Things Whthin CPU In The Interrupt Off State

    目录 . 引言 . Linux 中断的概念 . 中断处理流程 . Linux 中断相关的源代码分析 . Linux 硬件中断 . Linux 软中断 . 中断优先级 . CPU在关中断状态下编程要注意 ...

  7. Linux 设备文件的创建和mdev

    引子 本文是嵌入式企鹅圈开篇--<linux字符设备驱动剖析>的姐妹篇,在上述文章里面我们具体描写叙述了字符设备驱动框架涉及的驱动注冊.通过设备文件来訪问驱动等知识.并明白通过device ...

  8. 深入linux kernel内核配置选项

    ============================================================================== 深入linux kernel内核配置选项 ...

  9. linux kernel 字符设备详解

    有关Linux kernel 字符设备分析: 参考:http://blog.jobbole.com/86531/ 一.linux kernel 将设备分为3大类,字符设备,块设备,网络设备. 字符设备 ...

随机推荐

  1. Git实战手册(三): stash解惑与妙用

    0. 介绍 教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步原文地址 有空就来看看个人技术小站, 我一直都在 在实际项目开发中,总会遇到代码写到一半(没法去打commit),去开启新 ...

  2. DOM.getBoundingClientRect()

  3. Linux常用基本命令:grep-从文件或者管道中筛选匹配的行

    grep命令 作用:从文本文件或管道数据流中筛选匹配的行及数据,配合正则表达式一起使用,功能更加强大. 格式: grep [options] [pattern] [file] 1,匹配包含" ...

  4. 微信小程序顶部(navigationBar)设置为透明

    我记得在微信小程序中导航栏的颜色可以在app.json.  window里面添加navigationBarBackgroundColor属性,但是颜色只能为纯色.不能使用rgb,或者rgba的色号. ...

  5. JS中数组去重的九方法

            数组去重方法        方法一:运用set结构特点:存储的数据没有重复的,结果为对象,再用Array.from()转换成数组   var arr = [1,1,2,1,3,4,5] ...

  6. 谷歌迂回入华:Waymo无人车抢先进驻上海!

    谷歌迂回入华:Waymo无人车抢先进驻上海! https://mp.weixin.qq.com/s/d5Cw2uhykMJ9urb6Cs8aNw 谷歌又双叒叕要回归中国了?这已经是第不知道多少次的传言 ...

  7. 定时器setTimeout实现函数节流

    问题描述 文字输入查询的keyup或oninput事件,实现实时查询功能. 在用户输入过程中,用户可能只想需要 '小' 字的查询结果,但是以上两个事件会触发'x'.'i'.'a'.'o'.'小',一共 ...

  8. Android View体系(一)视图坐标系

    前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件,在这个系列中我会陆续讲到View坐标系.View的滑动.View的事件分发等文章来逐步介绍Android V ...

  9. vuejs组件库pk介绍

    vuejs可以说是近2年多以来最火的前端框架,随之而来就产生了非常多的组件库,我们来看看其中比较著名和人气旺盛的几个 1. Vuetify-符合material design设计理念, star数量7 ...

  10. Spring Data JPA方法定义规范

    Spring Data Jpa方法定义的规则: (1)简单条件查询 简单条件查询:查询某一个实体类或者集合. 按照Spring Data的规范的规定,查询方法以find | read | get开头, ...