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

📄 socket.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/* 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;}/* 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 a socket, not 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);			} else if (sock_flag(sk, SOCK_LINGER) &&				   !sk->sk_lingertime)				sctp_primitive_ABORT(asoc, NULL);			else				sctp_primitive_SHUTDOWN(asoc, NULL);		} else			sctp_primitive_SHUTDOWN(asoc, NULL);	}	/* Clean up any skbs sitting on the receive queue.  */	sctp_queue_purge_ulpevents(&sk->sk_receive_queue);	sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);	/* On a TCP-style socket, block for at most linger_time if set. */	if (sctp_style(sk, TCP) && timeout)		sctp_wait_for_close(sk, timeout);	/* This will run the backlog queue.  */	sctp_release_sock(sk);	/* Supposedly, no process has access to the socket, but	 * the net layers still may.	 */	sctp_local_bh_disable();	sctp_bh_lock_sock(sk);	/* Hold the sock, since sk_common_release() will put sock_put()	 * and we have just a little more cleanup.	 */	sock_hold(sk);	sk_common_release(sk);	sctp_bh_unlock_sock(sk);	sctp_local_bh_enable();	sock_put(sk);	SCTP_DBG_OBJCNT_DEC(sock);}/* Handle EPIPE error. */static int sctp_error(struct sock *sk, int flags, int err){	if (err == -EPIPE)		err = sock_error(sk) ? : -EPIPE;	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))		send_sig(SIGPIPE, current, 0);	return err;}/* API 3.1.3 sendmsg() - UDP Style Syntax * * An application uses sendmsg() and recvmsg() calls to transmit data to * and receive data from its peer. * *  ssize_t sendmsg(int socket, const struct msghdr *message, *                  int flags); * *  socket  - the socket descriptor of the endpoint. *  message - pointer to the msghdr structure which contains a single *            user message and possibly some ancillary data. * *            See Section 5 for complete description of the data *            structures. * *  flags   - flags sent or received with the user message, see Section *            5 for complete description of the flags. * * Note:  This function could use a rewrite especially when explicit * connect support comes in. *//* BUG:  We do not implement the equivalent of sk_stream_wait_memory(). */SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,			     struct msghdr *msg, size_t msg_len){	struct sctp_sock *sp;	struct sctp_endpoint *ep;	struct sctp_association *new_asoc=NULL, *asoc=NULL;	struct sctp_transport *transport, *chunk_tp;	struct sctp_chunk *chunk;	union sctp_addr to;	struct sockaddr *msg_name = NULL;	struct sctp_sndrcvinfo default_sinfo = { 0 };	struct sctp_sndrcvinfo *sinfo;	struct sctp_initmsg *sinit;	sctp_assoc_t associd = 0;	sctp_cmsgs_t cmsgs = { NULL };	int err;	sctp_scope_t scope;	long timeo;	__u16 sinfo_flags = 0;	struct sctp_datamsg *datamsg;	struct list_head *pos;	int msg_flags = msg->msg_flags;	SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %zu)\n",			  sk, msg, msg_len);	err = 0;	sp = sctp_sk(sk);	ep = sp->ep;	SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);	/* We cannot send a message over a TCP-style listening socket. */	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) {		err = -EPIPE;		goto out_nounlock;	}	/* Parse out the SCTP CMSGs.  */	err = sctp_msghdr_parse(msg, &cmsgs);	if (err) {		SCTP_DEBUG_PRINTK("msghdr parse err = %x\n", err);		goto out_nounlock;	}	/* Fetch the destination address for this packet.  This	 * address only selects the association--it is not necessarily	 * the address we will send to.	 * For a peeled-off socket, msg_name is ignored.	 */	if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) {		int msg_namelen = msg->msg_namelen;		err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name,				       msg_namelen);		if (err)			return err;		if (msg_namelen > sizeof(to))			msg_namelen = sizeof(to);		memcpy(&to, msg->msg_name, msg_namelen);		SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is "				  "0x%x:%u.\n",				  to.v4.sin_addr.s_addr, to.v4.sin_port);		to.v4.sin_port = ntohs(to.v4.sin_port);		msg_name = msg->msg_name;	}	sinfo = cmsgs.info;	sinit = cmsgs.init;	/* Did the user specify SNDRCVINFO?  */	if (sinfo) {		sinfo_flags = sinfo->sinfo_flags;		associd = sinfo->sinfo_assoc_id;	}	SCTP_DEBUG_PRINTK("msg_len: %zu, sinfo_flags: 0x%x\n",			  msg_len, sinfo_flags);	/* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */	if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) {		err = -EINVAL;		goto out_nounlock;	}	/* If MSG_EOF is set, no data can be sent. Disallow sending zero	 * length messages when MSG_EOF|MSG_ABORT is not set.	 * If MSG_ABORT is set, the message length could be non zero with	 * the msg_iov set to the user abort reason. 	 */	if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) ||	    (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) {		err = -EINVAL;		goto out_nounlock;	}	/* If MSG_ADDR_OVER is set, there must be an address	 * specified in msg_name.	 */	if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) {		err = -EINVAL;		goto out_nounlock;	}	transport = NULL;	SCTP_DEBUG_PRINTK("About to look up association.\n");	sctp_lock_sock(sk);	/* If a msg_name has been specified, assume this is to be used.  */	if (msg_name) {		/* Look for a matching association on the endpoint. */		asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);		if (!asoc) {			/* If we could not find a matching association on the			 * endpoint, make sure that it is not a TCP-style			 * socket that already has an association or there is			 * no peeled-off association on another socket.			 */			if ((sctp_style(sk, TCP) &&			     sctp_sstate(sk, ESTABLISHED)) ||			    sctp_endpoint_is_peeled_off(ep, &to)) {				err = -EADDRNOTAVAIL;				goto out_unlock;			}		}	} else {		asoc = sctp_id2assoc(sk, associd);		if (!asoc) {			err = -EPIPE;			goto out_unlock;		}	}	if (asoc) {		SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);		/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED		 * socket that has an association in CLOSED state. This can		 * happen when an accepted socket has an association that is		 * already CLOSED.		 */		if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) {			err = -EPIPE;			goto out_unlock;		}		if (sinfo_flags & MSG_EOF) {			SCTP_DEBUG_PRINTK("Shutting down association: %p\n",					  asoc);			sctp_primitive_SHUTDOWN(asoc, NULL);			err = 0;			goto out_unlock;		}		if (sinfo_flags & MSG_ABORT) {			SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);			sctp_primitive_ABORT(asoc, msg);			err = 0;			goto out_unlock;		}	}	/* Do we need to create the association?  */	if (!asoc) {		SCTP_DEBUG_PRINTK("There is no association yet.\n");		if (sinfo_flags & (MSG_EOF | MSG_ABORT)) {			err = -EINVAL;			goto out_unlock;		}		/* Check for invalid stream against the stream counts,		 * either the default or the user specified stream counts.		 */		if (sinfo) {			if (!sinit || (sinit && !sinit->sinit_num_ostreams)) {				/* Check against the defaults. */				if (sinfo->sinfo_stream >=				    sp->initmsg.sinit_num_ostreams) {					err = -EINVAL;					goto out_unlock;				}			} else {				/* Check against the requested.  */				if (sinfo->sinfo_stream >=				    sinit->sinit_num_ostreams) {					err = -EINVAL;					goto out_unlock;				}			}		}		/*		 * API 3.1.2 bind() - UDP Style Syntax		 * If a bind() or sctp_bindx() is not called prior to a		 * sendmsg() call that initiates a new association, 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_unlock;			}		}		scope = sctp_scope(&to);		new_asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);		if (!new_asoc) {			err = -ENOMEM;			goto out_unlock;		}		asoc = new_asoc;		/* If the SCTP_INIT ancillary data is specified, set all		 * the association init values accordingly.		 */		if (sinit) {			if (sinit->sinit_num_ostreams) {				asoc->c.sinit_num_ostreams =					sinit->sinit_num_ostreams;			}			if (sinit->sinit_max_instreams) {				asoc->c.sinit_max_instreams =					sinit->sinit_max_instreams;			}			if (sinit->sinit_max_attempts) {				asoc->max_init_attempts					= sinit->sinit_max_attempts;			}			if (sinit->sinit_max_init_timeo) {				asoc->max_init_timeo = 				 msecs_to_jiffies(sinit->sinit_max_init_timeo);			}		}		/* Prime the peer's transport structures.  */		transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL);		if (!transport) {			err = -ENOMEM;			goto out_free;		}		err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);		if (err < 0) {			err = -ENOMEM;			goto out_free;		}	}	/* ASSERT: we have a valid association at this point.  */	SCTP_DEBUG_PRINTK("We have a valid association.\n");	if (!sinfo) {		/* If the user didn't specify SNDRCVINFO, make up one with		 * some defaults.		 */		default_sinfo.sinfo_stream = asoc->default_stream;		default_sinfo.sinfo_flags = asoc->default_flags;

⌨️ 快捷键说明

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