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

📄 socket.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	sctp_datamsg_free(datamsg);	if (err)		goto out_free;	else		err = msg_len;	/* If we are already past ASSOCIATE, the lower	 * layers are responsible for association cleanup.	 */	goto out_unlock;out_free:	if (new_asoc)		sctp_association_free(asoc);out_unlock:	sctp_release_sock(sk);out_nounlock:	return sctp_error(sk, msg_flags, err);#if 0do_sock_err:	if (msg_len)		err = msg_len;	else		err = sock_error(sk);	goto out;do_interrupted:	if (msg_len)		err = msg_len;	goto out;#endif /* 0 */}/* This is an extended version of skb_pull() that removes the data from the * start of a skb even when data is spread across the list of skb's in the * frag_list. len specifies the total amount of data that needs to be removed. * when 'len' bytes could be removed from the skb, it returns 0. * If 'len' exceeds the total skb length,  it returns the no. of bytes that * could not be removed. */static int sctp_skb_pull(struct sk_buff *skb, int len){	struct sk_buff *list;	int skb_len = skb_headlen(skb);	int rlen;	if (len <= skb_len) {		__skb_pull(skb, len);		return 0;	}	len -= skb_len;	__skb_pull(skb, skb_len);	for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {		rlen = sctp_skb_pull(list, len);		skb->len -= (len-rlen);		skb->data_len -= (len-rlen);		if (!rlen)			return 0;		len = rlen;	}	return len;}/* API 3.1.3  recvmsg() - UDP Style Syntax * *  ssize_t recvmsg(int socket, 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. */static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,			     struct msghdr *msg, size_t len, int noblock,			     int flags, int *addr_len){	struct sctp_ulpevent *event = NULL;	struct sctp_sock *sp = sctp_sk(sk);	struct sk_buff *skb;	int copied;	int err = 0;	int skb_len;	SCTP_DEBUG_PRINTK("sctp_recvmsg(%s: %p, %s: %p, %s: %zd, %s: %d, %s: "			  "0x%x, %s: %p)\n", "sk", sk, "msghdr", msg,			  "len", len, "knoblauch", noblock,			  "flags", flags, "addr_len", addr_len);	sctp_lock_sock(sk);	if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) {		err = -ENOTCONN;		goto out;	}	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;	/* Get the total length of the skb including any skb's in the	 * frag_list.	 */	skb_len = skb->len;	copied = skb_len;	if (copied > len)		copied = len;	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	event = sctp_skb2event(skb);	if (err)		goto out_free;	sock_recv_timestamp(msg, sk, skb);	if (sctp_ulpevent_is_notification(event)) {		msg->msg_flags |= MSG_NOTIFICATION;		sp->pf->event_msgname(event, msg->msg_name, addr_len);	} else {		sp->pf->skb_msgname(skb, msg->msg_name, addr_len);	}	/* Check if we allow SCTP_SNDRCVINFO. */	if (sp->subscribe.sctp_data_io_event)		sctp_ulpevent_read_sndrcvinfo(event, msg);#if 0	/* FIXME: we should be calling IP/IPv6 layers.  */	if (sk->sk_protinfo.af_inet.cmsg_flags)		ip_cmsg_recv(msg, skb);#endif	err = copied;	/* If skb's length exceeds the user's buffer, update the skb and	 * push it back to the receive_queue so that the next call to	 * recvmsg() will return the remaining data. Don't set MSG_EOR.	 */	if (skb_len > copied) {		msg->msg_flags &= ~MSG_EOR;		if (flags & MSG_PEEK)			goto out_free;		sctp_skb_pull(skb, copied);		skb_queue_head(&sk->sk_receive_queue, skb);		/* When only partial message is copied to the user, increase		 * rwnd by that amount. If all the data in the skb is read,		 * rwnd is updated when the event is freed.		 */		if (!sctp_ulpevent_is_notification(event))			sctp_assoc_rwnd_increase(event->asoc, copied);		goto out;	} else if ((event->msg_flags & MSG_NOTIFICATION) ||		   (event->msg_flags & MSG_EOR))		msg->msg_flags |= MSG_EOR;	else		msg->msg_flags &= ~MSG_EOR;out_free:	if (flags & MSG_PEEK) {		/* Release the skb reference acquired after peeking the skb in		 * sctp_skb_recv_datagram().		 */		kfree_skb(skb);	} else {		/* Free the event which includes releasing the reference to		 * the owner of the skb, freeing the skb and updating the		 * rwnd.		 */		sctp_ulpevent_free(event);	}out:	sctp_release_sock(sk);	return err;}/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) * * This option is a on/off flag.  If enabled no SCTP message * fragmentation will be performed.  Instead if a message being sent * exceeds the current PMTU size, the message will NOT be sent and * instead a error will be indicated to the user. */static int sctp_setsockopt_disable_fragments(struct sock *sk,					    char __user *optval, int optlen){	int val;	if (optlen < sizeof(int))		return -EINVAL;	if (get_user(val, (int __user *)optval))		return -EFAULT;	sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1;	return 0;}static int sctp_setsockopt_events(struct sock *sk, char __user *optval,					int optlen){	if (optlen > sizeof(struct sctp_event_subscribe))		return -EINVAL;	if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))		return -EFAULT;	return 0;}/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) * * This socket option is applicable to the UDP-style socket only.  When * set it will cause associations that are idle for more than the * specified number of seconds to automatically close.  An association * being idle is defined an association that has NOT sent or received * user data.  The special value of '0' indicates that no automatic * close of any associations should be performed.  The option expects an * integer defining the number of seconds of idle time before an * association is closed. */static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,					    int optlen){	struct sctp_sock *sp = sctp_sk(sk);	/* Applicable to UDP-style socket only */	if (sctp_style(sk, TCP))		return -EOPNOTSUPP;	if (optlen != sizeof(int))		return -EINVAL;	if (copy_from_user(&sp->autoclose, optval, optlen))		return -EFAULT;	return 0;}/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address of * an association, modify an address's heartbeat interval, force a * heartbeat to be sent immediately, and adjust the address's maximum * number of retransmissions sent before an address is considered * unreachable.  The following structure is used to access and modify an * address's parameters: * *  struct sctp_paddrparams { *     sctp_assoc_t            spp_assoc_id; *     struct sockaddr_storage spp_address; *     uint32_t                spp_hbinterval; *     uint16_t                spp_pathmaxrxt; *     uint32_t                spp_pathmtu; *     uint32_t                spp_sackdelay; *     uint32_t                spp_flags; * }; * *   spp_assoc_id    - (one-to-many style socket) This is filled in the *                     application, and identifies the association for *                     this query. *   spp_address     - This specifies which address is of interest. *   spp_hbinterval  - This contains the value of the heartbeat interval, *                     in milliseconds.  If a  value of zero *                     is present in this field then no changes are to *                     be made to this parameter. *   spp_pathmaxrxt  - This contains the maximum number of *                     retransmissions before this address shall be *                     considered unreachable. If a  value of zero *                     is present in this field then no changes are to *                     be made to this parameter. *   spp_pathmtu     - When Path MTU discovery is disabled the value *                     specified here will be the "fixed" path mtu. *                     Note that if the spp_address field is empty *                     then all associations on this address will *                     have this fixed path mtu set upon them. * *   spp_sackdelay   - When delayed sack is enabled, this value specifies *                     the number of milliseconds that sacks will be delayed *                     for. This value will apply to all addresses of an *                     association if the spp_address field is empty. Note *                     also, that if delayed sack is enabled and this *                     value is set to 0, no change is made to the last *                     recorded delayed sack timer value. * *   spp_flags       - These flags are used to control various features *                     on an association. The flag field may contain *                     zero or more of the following options. * *                     SPP_HB_ENABLE  - Enable heartbeats on the *                     specified address. Note that if the address *                     field is empty all addresses for the association *                     have heartbeats enabled upon them. * *                     SPP_HB_DISABLE - Disable heartbeats on the *                     speicifed address. Note that if the address *                     field is empty all addresses for the association *                     will have their heartbeats disabled. Note also *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are *                     mutually exclusive, only one of these two should *                     be specified. Enabling both fields will have *                     undetermined results. * *                     SPP_HB_DEMAND - Request a user initiated heartbeat *                     to be made immediately. * *                     SPP_HB_TIME_IS_ZERO - Specify's that the time for *                     heartbeat delayis to be set to the value of 0 *                     milliseconds. * *                     SPP_PMTUD_ENABLE - This field will enable PMTU *                     discovery upon the specified address. Note that *                     if the address feild is empty then all addresses *                     on the association are effected. * *                     SPP_PMTUD_DISABLE - This field will disable PMTU *                     discovery upon the specified address. Note that *                     if the address feild is empty then all addresses *                     on the association are effected. Not also that *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually *                     exclusive. Enabling both will have undetermined *                     results. * *                     SPP_SACKDELAY_ENABLE - Setting this flag turns *                     on delayed sack. The time specified in spp_sackdelay *                     is used to specify the sack delay for this address. Note *                     that if spp_address is empty then all addresses will *                     enable delayed sack and take on the sack delay *                     value specified in spp_sackdelay. *                     SPP_SACKDELAY_DISABLE - Setting this flag turns *                     off delayed sack. If the spp_address field is blank then *                     delayed sack is disabled for the entire association. Note *                     also that this field is mutually exclusive to *                     SPP_SACKDELAY_ENABLE, setting both will have undefined *                     results. */static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,				       struct sctp_transport   *trans,				       struct sctp_association *asoc,				       struct sctp_sock        *sp,				       int                      hb_change,				       int                      pmtud_change,				       int                      sackdelay_change){	int error;	if (params->spp_flags & SPP_HB_DEMAND && trans) {		error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);		if (error)			return error;	}	/* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of	 * this field is ignored.  Note also that a value of zero indicates	 * the current setting should be left unchanged.	 */	if (params->spp_flags & SPP_HB_ENABLE) {		/* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is		 * set.  This lets us use 0 value when this flag		 * is set.		 */		if (params->spp_flags & SPP_HB_TIME_IS_ZERO)			params->spp_hbinterval = 0;		if (params->spp_hbinterval ||		    (params->spp_flags & SPP_HB_TIME_IS_ZERO)) {			if (trans) {				trans->hbinterval =				    msecs_to_jiffies(params->spp_hbinterval);			} else if (asoc) {				asoc->hbinterval =				    msecs_to_jiffies(params->spp_hbinterval);			} else {				sp->hbinterval = params->spp_hbinterval;			}		}	}	if (hb_change) {		if (trans) {			trans->param_flags =				(trans->param_flags & ~SPP_HB) | hb_change;		} else if (asoc) {			asoc->param_flags =				(asoc->param_flags & ~SPP_HB) | hb_change;		} else {			sp->param_flags =				(sp->param_flags & ~SPP_HB) | hb_change;		}	}	/* When Path MTU discovery is disabled the value specified here will	 * be the "fixed" path mtu (i.e. the value of the spp_flags field must	 * include the flag SPP_PMTUD_DISABLE for this field to have any	 * effect).	 */	if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {		if (trans) {			trans->pathmtu = params->spp_pathmtu;			sctp_assoc_sync_pmtu(asoc);		} else if (asoc) {			asoc->pathmtu = params->spp_pathmtu;			sctp_frag_point(sp, params->spp_pathmtu);		} else {			sp->pathmtu = params->spp_pathmtu;		}	}	if (pmtud_change) {		if (trans) {			int update = (trans->param_flags & SPP_PMTUD_DISABLE) &&				(params->spp_flags & SPP_PMTUD_ENABLE);			trans->param_flags =				(trans->param_flags & ~SPP_PMTUD) | pmtud_change;			if (update) {				sctp_transport_pmtu(trans);				sctp_assoc_sync_pmtu(asoc);			}		} else if (asoc) {			asoc->param_flags =				(asoc->param_flags & ~SPP_PMTUD) | pmtud_chan

⌨️ 快捷键说明

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