⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * op        Operation to perform (add or remove, see the flags of *           sctp_bindx) * * Returns 0 if ok, <0 errno code on error. */SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,				      struct sockaddr __user *addrs,				      int addrs_size, int op){	struct sockaddr *kaddrs;	int err;	int addrcnt = 0;	int walk_size = 0;	struct sockaddr *sa_addr;	void *addr_buf;	struct sctp_af *af;	SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p"			  " addrs_size %d opt %d\n", sk, addrs, addrs_size, op);	if (unlikely(addrs_size <= 0))		return -EINVAL;	/* Check the user passed a healthy pointer.  */	if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))		return -EFAULT;	/* Alloc space for the address array in kernel memory.  */	kaddrs = kmalloc(addrs_size, GFP_KERNEL);	if (unlikely(!kaddrs))		return -ENOMEM;	if (__copy_from_user(kaddrs, addrs, addrs_size)) {		kfree(kaddrs);		return -EFAULT;	}	/* Walk through the addrs buffer and count the number of addresses. */	addr_buf = kaddrs;	while (walk_size < addrs_size) {		sa_addr = (struct sockaddr *)addr_buf;		af = sctp_get_af_specific(sa_addr->sa_family);		/* If the address family is not supported or if this address		 * causes the address buffer to overflow return EINVAL.		 */		if (!af || (walk_size + af->sockaddr_len) > addrs_size) {			kfree(kaddrs);			return -EINVAL;		}		addrcnt++;		addr_buf += af->sockaddr_len;		walk_size += af->sockaddr_len;	}	/* Do the work. */	switch (op) {	case SCTP_BINDX_ADD_ADDR:		err = sctp_bindx_add(sk, kaddrs, addrcnt);		if (err)			goto out;		err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt);		break;	case SCTP_BINDX_REM_ADDR:		err = sctp_bindx_rem(sk, kaddrs, addrcnt);		if (err)			goto out;		err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt);		break;	default:		err = -EINVAL;		break;	}out:	kfree(kaddrs);	return err;}/* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size) * * Common routine for handling connect() and sctp_connectx(). * Connect will come in with just a single address. */static int __sctp_connect(struct sock* sk,			  struct sockaddr *kaddrs,			  int addrs_size){	struct sctp_sock *sp;	struct sctp_endpoint *ep;	struct sctp_association *asoc = NULL;	struct sctp_association *asoc2;	struct sctp_transport *transport;	union sctp_addr to;	struct sctp_af *af;	sctp_scope_t scope;	long timeo;	int err = 0;	int addrcnt = 0;	int walk_size = 0;	union sctp_addr *sa_addr = NULL;	void *addr_buf;	unsigned short port;	unsigned int f_flags = 0;	sp = sctp_sk(sk);	ep = sp->ep;	/* connect() cannot be done on a socket that is already in ESTABLISHED	 * state - UDP-style peeled off socket or a TCP-style socket that	 * is already connected.	 * It cannot be done even on a TCP-style listening socket.	 */	if (sctp_sstate(sk, ESTABLISHED) ||	    (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) {		err = -EISCONN;		goto out_free;	}	/* Walk through the addrs buffer and count the number of addresses. */	addr_buf = kaddrs;	while (walk_size < addrs_size) {		sa_addr = (union sctp_addr *)addr_buf;		af = sctp_get_af_specific(sa_addr->sa.sa_family);		port = ntohs(sa_addr->v4.sin_port);		/* If the address family is not supported or if this address		 * causes the address buffer to overflow return EINVAL.		 */		if (!af || (walk_size + af->sockaddr_len) > addrs_size) {			err = -EINVAL;			goto out_free;		}		/* Save current address so we can work with it */		memcpy(&to, sa_addr, af->sockaddr_len);		err = sctp_verify_addr(sk, &to, af->sockaddr_len);		if (err)			goto out_free;		/* Make sure the destination port is correctly set		 * in all addresses.		 */		if (asoc && asoc->peer.port && asoc->peer.port != port)			goto out_free;		/* Check if there already is a matching association on the		 * endpoint (other than the one created here).		 */		asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport);		if (asoc2 && asoc2 != asoc) {			if (asoc2->state >= SCTP_STATE_ESTABLISHED)				err = -EISCONN;			else				err = -EALREADY;			goto out_free;		}		/* If we could not find a matching association on the endpoint,		 * make sure that there is no peeled-off association matching		 * the peer address even on another socket.		 */		if (sctp_endpoint_is_peeled_off(ep, &to)) {			err = -EADDRNOTAVAIL;			goto out_free;		}		if (!asoc) {			/* If a bind() or sctp_bindx() is not called prior to			 * an sctp_connectx() call, the system picks an			 * ephemeral port and will choose an address set			 * equivalent to binding with a wildcard address.			 */			if (!ep->base.bind_addr.port) {				if (sctp_autobind(sk)) {					err = -EAGAIN;					goto out_free;				}			} else {				/*				 * If an unprivileged user inherits a 1-many				 * style socket with open associations on a				 * privileged port, it MAY be permitted to				 * accept new associations, but it SHOULD NOT				 * be permitted to open new associations.				 */				if (ep->base.bind_addr.port < PROT_SOCK &&				    !capable(CAP_NET_BIND_SERVICE)) {					err = -EACCES;					goto out_free;				}			}			scope = sctp_scope(&to);			asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);			if (!asoc) {				err = -ENOMEM;				goto out_free;			}		}		/* Prime the peer's transport structures.  */		transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL,						SCTP_UNKNOWN);		if (!transport) {			err = -ENOMEM;			goto out_free;		}		addrcnt++;		addr_buf += af->sockaddr_len;		walk_size += af->sockaddr_len;	}	err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);	if (err < 0) {		goto out_free;	}	err = sctp_primitive_ASSOCIATE(asoc, NULL);	if (err < 0) {		goto out_free;	}	/* Initialize sk's dport and daddr for getpeername() */	inet_sk(sk)->dport = htons(asoc->peer.port);	af = sctp_get_af_specific(sa_addr->sa.sa_family);	af->to_sk_daddr(sa_addr, sk);	sk->sk_err = 0;	/* in-kernel sockets don't generally have a file allocated to them	 * if all they do is call sock_create_kern().	 */	if (sk->sk_socket->file)		f_flags = sk->sk_socket->file->f_flags;	timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);	err = sctp_wait_for_connect(asoc, &timeo);	/* Don't free association on exit. */	asoc = NULL;out_free:	SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"			  " kaddrs: %p err: %d\n",			  asoc, kaddrs, err);	if (asoc)		sctp_association_free(asoc);	return err;}/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() * * API 8.9 * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt); * * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. * If the sd is an IPv6 socket, the addresses passed can either be IPv4 * or IPv6 addresses. * * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see * Section 3.1.2 for this usage. * * addrs is a pointer to an array of one or more socket addresses. Each * address is contained in its appropriate structure (i.e. struct * sockaddr_in or struct sockaddr_in6) the family of the address type * must be used to distengish the address length (note that this * representation is termed a "packed array" of addresses). The caller * specifies the number of addresses in the array with addrcnt. * * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns * -1, and sets errno to the appropriate error code. * * For SCTP, the port given in each socket address must be the same, or * sctp_connectx() will fail, setting errno to EINVAL. * * An application can use sctp_connectx to initiate an association with * an endpoint that is multi-homed.  Much like sctp_bindx() this call * allows a caller to specify multiple addresses at which a peer can be * reached.  The way the SCTP stack uses the list of addresses to set up * the association is implementation dependant.  This function only * specifies that the stack will try to make use of all the addresses in * the list when needed. * * Note that the list of addresses passed in is only used for setting up * the association.  It does not necessarily equal the set of addresses * the peer uses for the resulting association.  If the caller wants to * find out the set of peer addresses, it must use sctp_getpaddrs() to * retrieve them after the association has been set up. * * Basically do nothing but copying the addresses from user to kernel * land and invoking either sctp_connectx(). This is used for tunneling * the sctp_connectx() request through sctp_setsockopt() from userspace. * * We don't use copy_from_user() for optimization: we first do the * sanity checks (buffer size -fast- and access check-healthy * pointer); if all of those succeed, then we can alloc the memory * (expensive operation) needed to copy the data to kernel. Then we do * the copying without checking the user space area * (__copy_from_user()). * * On exit there is no need to do sockfd_put(), sys_setsockopt() does * it. * * sk        The sk of the socket * addrs     The pointer to the addresses in user land * addrssize Size of the addrs buffer * * Returns 0 if ok, <0 errno code on error. */SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,				      struct sockaddr __user *addrs,				      int addrs_size){	int err = 0;	struct sockaddr *kaddrs;	SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",			  __FUNCTION__, sk, addrs, addrs_size);	if (unlikely(addrs_size <= 0))		return -EINVAL;	/* Check the user passed a healthy pointer.  */	if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))		return -EFAULT;	/* Alloc space for the address array in kernel memory.  */	kaddrs = kmalloc(addrs_size, GFP_KERNEL);	if (unlikely(!kaddrs))		return -ENOMEM;	if (__copy_from_user(kaddrs, addrs, addrs_size)) {		err = -EFAULT;	} else {		err = __sctp_connect(sk, kaddrs, addrs_size);	}	kfree(kaddrs);	return err;}/* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented * by a UDP-style socket. * * The syntax is * *   ret = close(int sd); * *   sd      - the socket descriptor of the associations to be closed. * * To gracefully shutdown a specific association represented by the * UDP-style socket, an application should use the sendmsg() call, * passing no user data, but including the appropriate flag in the * ancillary data (see Section xxxx). * * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. * * 4.1.6 close() - TCP Style Syntax * * Applications use close() to gracefully close down an association. * * The syntax is: * *    int close(int sd); * *      sd      - the socket descriptor of the association to be closed. * * After an application calls close() on a socket descriptor, no further * socket operations will succeed on that descriptor. * * API 7.1.4 SO_LINGER * * An application using the TCP-style socket can use this option to * perform the SCTP ABORT primitive.  The linger option structure is: * *  struct  linger { *     int     l_onoff;                // option on/off *     int     l_linger;               // linger time * }; * * To enable the option, set l_onoff to 1.  If the l_linger value is set * to 0, calling close() is the same as the ABORT primitive.  If the * value is set to a negative value, the setsockopt() call will return * an error.  If the value is set to a positive value linger_time, the * close() can be blocked for at most linger_time ms.  If the graceful * shutdown phase does not finish during this period, close() will * return but the graceful shutdown phase continues in the system. */SCTP_STATIC void sctp_close(struct sock *sk, long timeout){	struct sctp_endpoint *ep;	struct sctp_association *asoc;	struct list_head *pos, *temp;	SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);	sctp_lock_sock(sk);	sk->sk_shutdown = SHUTDOWN_MASK;	ep = sctp_sk(sk)->ep;	/* Walk all associations on an endpoint.  */	list_for_each_safe(pos, temp, &ep->asocs) {		asoc = list_entry(pos, struct sctp_association, asocs);		if (sctp_style(sk, TCP)) {			/* A closed association can still be in the list if			 * it belongs to a TCP-style listening socket that is			 * not yet accepted. If so, free it. If not, send an			 * ABORT or SHUTDOWN based on the linger options.			 */			if (sctp_state(asoc, CLOSED)) {				sctp_unhash_established(asoc);				sctp_association_free(asoc);				continue;			}		}		if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {			struct sctp_chunk *chunk;			chunk = sctp_make_abort_user(asoc, NULL, 0);			if (chunk)				sctp_primitive_ABORT(asoc, chunk);		} else			sctp_primitive_SHUTDOWN(asoc, NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -