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

📄 socket.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 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 MSG_ADDR_OVER flag is set in the UDP model.	 */	if ((sctp_style(sk, TCP) && msg_name) ||	    (sinfo_flags & MSG_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");	}	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.		 */		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;	sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ;	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; *  }; * *   spp_assoc_id    - (UDP 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.  A value of 0, when modifying the *                     parameter, specifies that the heartbeat on this *                     address should be disabled. A value of UINT32_MAX *                     (4294967295), when modifying the parameter, *                     specifies that a heartbeat should be sent *                     immediately to the peer address, and the current *                     interval should remain unchanged. *   spp_pathmaxrxt  - This contains the maximum number of *                     retransmissions before this address shall be *                     considered unreachable. */static int sctp_setsockopt_peer_addr_params(struct sock *sk,					    char __user *optval, int optlen){	struct sctp_paddrparams params;	struct sctp_transport *trans;	int error;	if (optlen != sizeof(struct sctp_paddrparams))		return -EINVAL;	if (copy_from_user(&params, optval, optlen))		return -EFAULT;	/*	 * API 7. Socket Options (setting the default value for the endpoint)	 * All options that support specific settings on an association by	 * filling in either an association id variable or a sockaddr_storage	 * SHOULD also support setting of the same value for the entire endpoint	 * (i.e. future associations). To accomplish this the following logic is	 * used when setting one of these options:	 * c) If neither the sockaddr_storage or association identification is	 *    set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and	 *    the association identification is 0, the settings are a default	 *    and to be applied to the endpoint (all future associations).	 */	/* update default value for endpoint (all future associations) */	if (!params.spp_assoc_id && 	    sctp_is_any(( union sctp_addr *)&params.spp_address)) {		/* Manual heartbeat on an endpoint is invalid. */		if (0xffffffff == params.spp_hbinterval)			return -EINVAL;		else if (params.spp_hbinterval)			sctp_sk(sk)->paddrparam.spp_hbinterval =						params.spp_hbinterval;		if (params.spp_pathmaxrxt)			sctp_sk(sk)->paddrparam.spp_pathmaxrxt =						params.spp_pathmaxrxt;		return 0;	}	trans = sctp_addr_id2transport(sk, &params.spp_address,				       params.spp_assoc_id);	if (!trans)		return -EINVAL;	/* 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 value of the heartbeat interval, in milliseconds. A value of	 * UINT32_MAX (4294967295), when modifying the parameter, specifies	 * that a heartbeat should be sent immediately to the peer address,	 * and the current interval should remain unchanged.	 */	if (0xffffffff == params.spp_hbinterval) {		error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);		if (error)			return error;	} else {	/* The value of the heartbeat interval, in milliseconds. A value of 0,	 * when modifying the parameter, specifies that the heartbeat on this	 * address should be disabled.	 */		if (params.spp_hbinterval) {			trans->hb_allowed = 1;			trans->hb_interval = 				msecs_to_jiffies(params.spp_hbinterval);		} else

⌨️ 快捷键说明

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