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

📄 socket.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/* 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: %p.\n", ep);	/* 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);		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);	/* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */	if (sctp_style(sk, TCP) && (sinfo_flags & (SCTP_EOF | SCTP_ABORT))) {		err = -EINVAL;		goto out_nounlock;	}	/* If SCTP_EOF is set, no data can be sent. Disallow sending zero	 * length messages when SCTP_EOF|SCTP_ABORT is not set.	 * If SCTP_ABORT is set, the message length could be non zero with	 * the msg_iov set to the user abort reason.	 */	if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) ||	    (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) {		err = -EINVAL;		goto out_nounlock;	}	/* If SCTP_ADDR_OVER is set, there must be an address	 * specified in msg_name.	 */	if ((sinfo_flags & SCTP_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 & SCTP_EOF) {			SCTP_DEBUG_PRINTK("Shutting down association: %p\n",					  asoc);			sctp_primitive_SHUTDOWN(asoc, NULL);			err = 0;			goto out_unlock;		}		if (sinfo_flags & SCTP_ABORT) {			chunk = sctp_make_abort_user(asoc, msg, msg_len);			if (!chunk) {				err = -ENOMEM;				goto out_unlock;			}			SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);			sctp_primitive_ABORT(asoc, chunk);			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 & (SCTP_EOF | SCTP_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;			}		} else {			/*			 * If an unprivileged user inherits a one-to-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_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, SCTP_UNKNOWN);		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;		default_sinfo.sinfo_ppid = asoc->default_ppid;		default_sinfo.sinfo_context = asoc->default_context;		default_sinfo.sinfo_timetolive = asoc->default_timetolive;		default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);		sinfo = &default_sinfo;	}	/* API 7.1.7, the sndbuf size per association bounds the	 * maximum size of data that can be sent in a single send call.	 */	if (msg_len > sk->sk_sndbuf) {		err = -EMSGSIZE;		goto out_free;	}	if (asoc->pmtu_pending)		sctp_assoc_pending_pmtu(asoc);	/* If fragmentation is disabled and the message length exceeds the	 * association fragmentation point, return EMSGSIZE.  The I-D	 * does not specify what this error is, but this looks like	 * a great fit.	 */	if (sctp_sk(sk)->disable_fragments && (msg_len > asoc->frag_point)) {		err = -EMSGSIZE;		goto out_free;	}	if (sinfo) {		/* Check for invalid stream. */		if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) {			err = -EINVAL;			goto out_free;		}	}	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);	if (!sctp_wspace(asoc)) {		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);		if (err)			goto out_free;	}	/* If an address is passed with the sendto/sendmsg call, it is used	 * to override the primary destination address in the TCP model, or	 * when SCTP_ADDR_OVER flag is set in the UDP model.	 */	if ((sctp_style(sk, TCP) && msg_name) ||	    (sinfo_flags & SCTP_ADDR_OVER)) {		chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);		if (!chunk_tp) {			err = -EINVAL;			goto out_free;		}	} else		chunk_tp = NULL;	/* Auto-connect, if we aren't connected already. */	if (sctp_state(asoc, CLOSED)) {		err = sctp_primitive_ASSOCIATE(asoc, NULL);		if (err < 0)			goto out_free;		SCTP_DEBUG_PRINTK("We associated primitively.\n");	}	/* Break the message into multiple chunks of maximum size. */	datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len);	if (!datamsg) {		err = -ENOMEM;		goto out_free;	}	/* Now send the (possibly) fragmented message. */	list_for_each(pos, &datamsg->chunks) {		chunk = list_entry(pos, struct sctp_chunk, frag_list);		sctp_datamsg_track(chunk);		/* Do accounting for the write space.  */		sctp_set_owner_w(chunk);		chunk->transport = chunk_tp;		/* Send it to the lower layers.  Note:  all chunks		 * must either fail or succeed.   The lower layer		 * works that way today.  Keep it that way or this		 * breaks.		 */		err = sctp_primitive_SEND(asoc, chunk);		/* Did the lower layer accept the chunk? */		if (err)			sctp_chunk_free(chunk);		SCTP_DEBUG_PRINTK("We sent primitively.\n");

⌨️ 快捷键说明

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