首页 > 其他分享 >socket创建过程

socket创建过程

时间:2023-06-01 10:36:24浏览次数:31  
标签:protocol socket err 创建 sock module sk 过程 inet

SYSCALL_DEFINE3( 
socket, int, family, int, type, int, protocol) 

 { 

int retval; 

struct socket *sock; 

int flags; 



/* Check the SOCK_* constants for consistency.  */ 

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); 



flags = type & ~SOCK_TYPE_MASK; 

if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 

return -EINVAL; 

type &= SOCK_TYPE_MASK; 



if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 

flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 



 
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: 

/* It may be already another descriptor 8) Not kernel problem. */ 

return retval; 



 out_release: 

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);
 }
 EXPORT_SYMBOL(sock_create);
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;


/*
*      Check protocol is in range
*/
if (family < 0 || family >= NPROTO)
return -EAFNOSUPPORT;
if (type < 0 || type >= SOCK_MAX)
return -EINVAL;


/* Compatibility.


  This uglymoron is moved from INET layer to here to avoid
  deadlock in module load.
*/
if (family == PF_INET && type == SOCK_PACKET) {
pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
    current->comm);
family = PF_PACKET;
}


err = security_socket_create(family, type, protocol, kern);
if (err)
return err;


/*
* Allocate the socket and allow the family to set things up. if
* the protocol is 0, the family is instructed to select an appropriate
* default.
*/
sock = sock_alloc();
if (!sock) {
net_warn_ratelimited("socket: no more sockets\n");
return -ENFILE; /* Not exactly a match, but its the
  closest posix thing */
}


sock->type = type;


 #ifdef CONFIG_MODULES
/* Attempt to load a protocol module if the find failed.
*
* 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
* requested real, full-featured networking support upon configuration.
* Otherwise module support will break!
*/
if (rcu_access_pointer(net_families[family]) == NULL)
request_module("net-pf-%d", family);
 #endif


rcu_read_lock();
pf = rcu_dereference(net_families[family]);
err = -EAFNOSUPPORT;
if (!pf)
goto out_release;


/*
* We will call the ->create function, that possibly is in a loadable
* module, so we have to bump that loadable module refcnt first.
*/
if (!try_module_get(pf->owner))
goto out_release;


/* Now protected by module ref count */
rcu_read_unlock();


err = pf->create(net, sock, protocol, kern);
if (err < 0)
goto out_module_put;


/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
*/
if (!try_module_get(sock->ops->owner))
goto out_module_busy;


/*
* Now that we're done with the ->create function, the [loadable]
* module can have its refcnt decremented
*/
module_put(pf->owner);
err = security_socket_post_create(sock, family, type, protocol, kern);
if (err)
goto out_sock_release;
*res = sock;


return 0;


 out_module_busy:
err = -EAFNOSUPPORT;
 out_module_put:
sock->ops = NULL;
module_put(pf->owner);
 out_sock_release:
sock_release(sock);
return err;


 out_release:
rcu_read_unlock();
goto out_sock_release;
 }
static const struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner  = THIS_MODULE,
 };
 /*
  * Create an inet socket.
  */


 static int inet_create(struct net *net, struct socket *sock, int protocol,
      int kern)
 {
struct sock *sk;
struct inet_protosw *answer;
struct inet_sock *inet;
struct proto *answer_prot;
unsigned char answer_flags;
int try_loading_module = 0;
int err;


if (protocol < 0 || protocol >= IPPROTO_MAX)
return -EINVAL;


sock->state = SS_UNCONNECTED;


/* Look for the requested type/protocol pair. */
 lookup_protocol:
err = -ESOCKTNOSUPPORT;
rcu_read_lock();
list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {


err = 0;
/* Check the non-wild match. */
if (protocol == answer->protocol) {
if (protocol != IPPROTO_IP)
break;
} else {
/* Check for the two wild cases. */
if (IPPROTO_IP == protocol) {
protocol = answer->protocol;
break;
}
if (IPPROTO_IP == answer->protocol)
break;
}
err = -EPROTONOSUPPORT;
}


if (unlikely(err)) {
if (try_loading_module < 2) {
rcu_read_unlock();
/*
* Be more specific, e.g. net-pf-2-proto-132-type-1
* (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)
*/
if (++try_loading_module == 1)
request_module("net-pf-%d-proto-%d-type-%d",
      PF_INET, protocol, sock->type);
/*
* Fall back to generic, e.g. net-pf-2-proto-132
* (net-pf-PF_INET-proto-IPPROTO_SCTP)
*/
else
request_module("net-pf-%d-proto-%d",
      PF_INET, protocol);
goto lookup_protocol;
} else
goto out_rcu_unlock;
}


err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
   !ns_capable(net->user_ns, CAP_NET_RAW))
goto out_rcu_unlock;


sock->ops = answer->ops;
answer_prot = answer->prot;
answer_flags = answer->flags;
rcu_read_unlock();


WARN_ON(!answer_prot->slab);


err = -ENOBUFS;
sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern);
if (!sk)
goto out;


err = 0;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = SK_CAN_REUSE;


inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;


inet->nodefrag = 0;


if (SOCK_RAW == sock->type) {
inet->inet_num = protocol;
if (IPPROTO_RAW == protocol)
inet->hdrincl = 1;
}


if (net->ipv4.sysctl_ip_no_pmtu_disc)
inet->pmtudisc = IP_PMTUDISC_DONT;
else
inet->pmtudisc = IP_PMTUDISC_WANT;


inet->inet_id = 0;


sock_init_data(sock, sk);


sk->sk_destruct   = inet_sock_destruct;
sk->sk_protocol   = protocol;
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;


inet->uc_ttl  = -1;
inet->mc_loop  = 1;
inet->mc_ttl  = 1;
inet->mc_all  = 1;
inet->mc_index = 0;
inet->mc_list  = NULL;
inet->rcv_tos  = 0;


sk_refcnt_debug_inc(sk);


if (inet->inet_num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
inet->inet_sport = htons(inet->inet_num);
/* Add to protocol hash chains. */
err = sk->sk_prot->hash(sk);
if (err) {
sk_common_release(sk);
goto out;
}
}


if (sk->sk_prot->init) {
err = sk->sk_prot->init(sk);
if (err)
sk_common_release(sk);
}
 out:
return err;
 out_rcu_unlock:
rcu_read_unlock();
goto out;
 }

标签:protocol,socket,err,创建,sock,module,sk,过程,inet
From: https://blog.51cto.com/u_11860992/6392699

相关文章

  • Linux创建socket
    staticconststructnet_proto_familyinet_family_ops={.family=PF_INET,.create=inet_create,.owner=THIS_MODULE,};/**Createaninetsocket.*/staticintinet_create(structnet*net,structsocket*sock,intprotocol,intkern)......
  • Git分支教程:详解分支创建、合并、删除等操作
    Git是一种强大的分布式版本控制系统,它的分支功能使得团队协作和代码管理变得更加灵活和高效。分支可以让开发人员在不影响主线开发的情况下进行并行开发和实验性工作。本篇博客将详解Git分支的创建、合并、删除等操作,帮助你更好地理解和使用Git的分支功能。分支的基本概念在开......
  • 如何在Java中创建数组列表
    为了在Java中存储动态大小的元素,我们使用了ArrayList。每当添加新元素时,它会自动增加其大小。ArrayList实现Java的List接口和Java的Collection的一部分。由于其功能和灵活性,它被广泛使用。ArrayList的关键点An ArrayList是一个可调整大小的数组,也称为动态数组。它根据新元素增加其......
  • 如何使用Next.js创建全栈应用程序
    Next.js乍一看似乎令人生畏,因为有这么多新概念需要掌握。但别担心——在这个循序渐进的教程中,我将为您提供使用Next.js创建您的第一个现代全栈应用程序所需的所有基本信息。在本教程中,我将带您了解Next.js的基础知识,并指导您创建您的第一个全栈应用程序。在本教程结束时,您将......
  • Revit二次开发系列教程01-如何在Revit中创建模型过程的理解
    目录01案例02步骤讲解03关键类理解04总结05源码地址01案例创建一个结构墙usingAutodesk.Revit.Attributes;usingAutodesk.Revit.DB;usingAutodesk.Revit.UI;usingSystem.Linq;namespaceExampleBasic{[Transaction(TransactionMode.Manual)][Regener......
  • mysql创建索引
    使用createindex创建createindexontablename(columnname(限制长度))使用altertable创建ALTERTABLEtableNameADDINDEXindexName(columnName);创建表时创建索引CREATETABLEtableName(idINTNOTNULL,columnNamecolumnType,INDEX[indexName](colum......
  • 计网:实验一 vlan的创建与划分
    一、实验目的: 1.了解vlan的工作原理;2.学习基于端口划分vlan的方法;3.了解跨交换机的相同vlan之间的通信;4.进一步学习交换机端口的配置命令。二、实验原理:VLAN(VirtualLocalAreaNetwork)即虚拟局域网,是一种通过将局域网内的设备逻辑地而不是物理地划分成一个个网段从而实现虚拟......
  • Python连接es笔记四之创建和删除操作
    本文首发于公众号:Hunter后端原文链接:Python连接es笔记四之创建和删除操作这一篇笔记介绍一下索引和数据的创建和删除。其实对于索引来说,如果可以接触到kibana的话,可以很方便的在界面进行操作,这里简单介绍一下如何使用代码来操作索引的创建和删除。索引的创建和删除操作使......
  • 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程
    2023-05-31:给定一个整数数组A,你可以从某一起始索引出发,跳跃一定次数在你跳跃的过程中,第1、3、5...次跳跃称为奇数跳跃而第2、4、6...次跳跃称为偶数跳跃你可以按以下方式从索引i向后跳转到索引j(其中i<j):在进行奇数跳跃时(如,第1,3,5...次跳跃),你将会跳到索引j使得A[......
  • 【Azure K8S】演示修复因AKS密钥过期而导致创建服务不成功的问题(The provided client
    问题描述在AzureKubernetes服务中,创建一个InternalLoadBalancer服务,使用以下yaml内容:internallb.yamlapiVersion:v1kind:Servicemetadata:name:ilb-myappannotations:service.beta.kubernetes.io/azure-load-balancer-internal:"true"spec:type:LoadBala......