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

📄 socket.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (likely(res != -ELINKCONG)) {exit:			up(&tsock->sem);			return res;		}		if (m->msg_flags & MSG_DONTWAIT) {			res = -EWOULDBLOCK;			goto exit;		}		if (wait_event_interruptible(*sock->sk->sk_sleep,					     !tsock->p->congested)) {		    res = -ERESTARTSYS;		    goto exit;		}	} while (1);}/** * send_stream - send stream-oriented data * @iocb: (unused) * @sock: socket structure * @m: data to send * @total_len: total length of data to be sent * * Used for SOCK_STREAM data. * * Returns the number of bytes sent on success (or partial success), * or errno if no data sent */static int send_stream(struct kiocb *iocb, struct socket *sock,		       struct msghdr *m, size_t total_len){	struct tipc_port *tport;	struct msghdr my_msg;	struct iovec my_iov;	struct iovec *curr_iov;	int curr_iovlen;	char __user *curr_start;	u32 hdr_size;	int curr_left;	int bytes_to_send;	int bytes_sent;	int res;	/* Handle special cases where there is no connection */	if (unlikely(sock->state != SS_CONNECTED)) {		if (sock->state == SS_UNCONNECTED)			return send_packet(iocb, sock, m, total_len);		else if (sock->state == SS_DISCONNECTING)			return -EPIPE;		else			return -ENOTCONN;	}	if (unlikely(m->msg_name))		return -EISCONN;	/*	 * Send each iovec entry using one or more messages	 *	 * Note: This algorithm is good for the most likely case	 * (i.e. one large iovec entry), but could be improved to pass sets	 * of small iovec entries into send_packet().	 */	curr_iov = m->msg_iov;	curr_iovlen = m->msg_iovlen;	my_msg.msg_iov = &my_iov;	my_msg.msg_iovlen = 1;	my_msg.msg_flags = m->msg_flags;	my_msg.msg_name = NULL;	bytes_sent = 0;	tport = tipc_sk(sock->sk)->p;	hdr_size = msg_hdr_sz(&tport->phdr);	while (curr_iovlen--) {		curr_start = curr_iov->iov_base;		curr_left = curr_iov->iov_len;		while (curr_left) {			bytes_to_send = tport->max_pkt - hdr_size;			if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)				bytes_to_send = TIPC_MAX_USER_MSG_SIZE;			if (curr_left < bytes_to_send)				bytes_to_send = curr_left;			my_iov.iov_base = curr_start;			my_iov.iov_len = bytes_to_send;			if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {				if (bytes_sent != 0)					res = bytes_sent;				return res;			}			curr_left -= bytes_to_send;			curr_start += bytes_to_send;			bytes_sent += bytes_to_send;		}		curr_iov++;	}	return bytes_sent;}/** * auto_connect - complete connection setup to a remote port * @sock: socket structure * @tsock: TIPC-specific socket structure * @msg: peer's response message * * Returns 0 on success, errno otherwise */static int auto_connect(struct socket *sock, struct tipc_sock *tsock,			struct tipc_msg *msg){	struct tipc_portid peer;	if (msg_errcode(msg)) {		sock->state = SS_DISCONNECTING;		return -ECONNREFUSED;	}	peer.ref = msg_origport(msg);	peer.node = msg_orignode(msg);	tipc_connect2port(tsock->p->ref, &peer);	tipc_set_portimportance(tsock->p->ref, msg_importance(msg));	sock->state = SS_CONNECTED;	return 0;}/** * set_orig_addr - capture sender's address for received message * @m: descriptor for message info * @msg: received message header * * Note: Address is not captured if not requested by receiver. */static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg){	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;	if (addr) {		addr->family = AF_TIPC;		addr->addrtype = TIPC_ADDR_ID;		addr->addr.id.ref = msg_origport(msg);		addr->addr.id.node = msg_orignode(msg);		addr->addr.name.domain = 0;   	/* could leave uninitialized */		addr->scope = 0;   		/* could leave uninitialized */		m->msg_namelen = sizeof(struct sockaddr_tipc);	}}/** * anc_data_recv - optionally capture ancillary data for received message * @m: descriptor for message info * @msg: received message header * @tport: TIPC port associated with message * * Note: Ancillary data is not captured if not requested by receiver. * * Returns 0 if successful, otherwise errno */static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,				struct tipc_port *tport){	u32 anc_data[3];	u32 err;	u32 dest_type;	int has_name;	int res;	if (likely(m->msg_controllen == 0))		return 0;	/* Optionally capture errored message object(s) */	err = msg ? msg_errcode(msg) : 0;	if (unlikely(err)) {		anc_data[0] = err;		anc_data[1] = msg_data_sz(msg);		if ((res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data)))			return res;		if (anc_data[1] &&		    (res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1],				    msg_data(msg))))			return res;	}	/* Optionally capture message destination object */	dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;	switch (dest_type) {	case TIPC_NAMED_MSG:		has_name = 1;		anc_data[0] = msg_nametype(msg);		anc_data[1] = msg_namelower(msg);		anc_data[2] = msg_namelower(msg);		break;	case TIPC_MCAST_MSG:		has_name = 1;		anc_data[0] = msg_nametype(msg);		anc_data[1] = msg_namelower(msg);		anc_data[2] = msg_nameupper(msg);		break;	case TIPC_CONN_MSG:		has_name = (tport->conn_type != 0);		anc_data[0] = tport->conn_type;		anc_data[1] = tport->conn_instance;		anc_data[2] = tport->conn_instance;		break;	default:		has_name = 0;	}	if (has_name &&	    (res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data)))		return res;	return 0;}/** * recv_msg - receive packet-oriented message * @iocb: (unused) * @m: descriptor for message info * @buf_len: total size of user buffer area * @flags: receive flags * * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. * If the complete message doesn't fit in user area, truncate it. * * Returns size of returned message data, errno otherwise */static int recv_msg(struct kiocb *iocb, struct socket *sock,		    struct msghdr *m, size_t buf_len, int flags){	struct tipc_sock *tsock = tipc_sk(sock->sk);	struct sk_buff *buf;	struct tipc_msg *msg;	unsigned int q_len;	unsigned int sz;	u32 err;	int res;	/* Currently doesn't support receiving into multiple iovec entries */	if (m->msg_iovlen != 1)		return -EOPNOTSUPP;	/* Catch invalid receive attempts */	if (unlikely(!buf_len))		return -EINVAL;	if (sock->type == SOCK_SEQPACKET) {		if (unlikely(sock->state == SS_UNCONNECTED))			return -ENOTCONN;		if (unlikely((sock->state == SS_DISCONNECTING) &&			     (skb_queue_len(&sock->sk->sk_receive_queue) == 0)))			return -ENOTCONN;	}	/* Look for a message in receive queue; wait if necessary */	if (unlikely(down_interruptible(&tsock->sem)))		return -ERESTARTSYS;restart:	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&		     (flags & MSG_DONTWAIT))) {		res = -EWOULDBLOCK;		goto exit;	}	if ((res = wait_event_interruptible(		*sock->sk->sk_sleep,		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||		 (sock->state == SS_DISCONNECTING))) )) {		goto exit;	}	/* Catch attempt to receive on an already terminated connection */	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */	if (!q_len) {		res = -ENOTCONN;		goto exit;	}	/* Get access to first message in receive queue */	buf = skb_peek(&sock->sk->sk_receive_queue);	msg = buf_msg(buf);	sz = msg_data_sz(msg);	err = msg_errcode(msg);	/* Complete connection setup for an implied connect */	if (unlikely(sock->state == SS_CONNECTING)) {		if ((res = auto_connect(sock, tsock, msg)))			goto exit;	}	/* Discard an empty non-errored message & try again */	if ((!sz) && (!err)) {		advance_queue(tsock);		goto restart;	}	/* Capture sender's address (optional) */	set_orig_addr(m, msg);	/* Capture ancillary data (optional) */	if ((res = anc_data_recv(m, msg, tsock->p)))		goto exit;	/* Capture message data (if valid) & compute return value (always) */	if (!err) {		if (unlikely(buf_len < sz)) {			sz = buf_len;			m->msg_flags |= MSG_TRUNC;		}		if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg),					  sz))) {			res = -EFAULT;			goto exit;		}		res = sz;	} else {		if ((sock->state == SS_READY) ||		    ((err == TIPC_CONN_SHUTDOWN) || m->msg_control))			res = 0;		else			res = -ECONNRESET;	}	/* Consume received message (optional) */	if (likely(!(flags & MSG_PEEK))) {		if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))			tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);		advance_queue(tsock);	}exit:	up(&tsock->sem);	return res;}/** * recv_stream - receive stream-oriented data * @iocb: (unused) * @m: descriptor for message info * @buf_len: total size of user buffer area * @flags: receive flags * * Used for SOCK_STREAM messages only.  If not enough data is available * will optionally wait for more; never truncates data. * * Returns size of returned message data, errno otherwise */static int recv_stream(struct kiocb *iocb, struct socket *sock,		       struct msghdr *m, size_t buf_len, int flags){	struct tipc_sock *tsock = tipc_sk(sock->sk);	struct sk_buff *buf;	struct tipc_msg *msg;	unsigned int q_len;	unsigned int sz;	int sz_to_copy;	int sz_copied = 0;	int needed;	char __user *crs = m->msg_iov->iov_base;	unsigned char *buf_crs;	u32 err;	int res;	/* Currently doesn't support receiving into multiple iovec entries */	if (m->msg_iovlen != 1)		return -EOPNOTSUPP;	/* Catch invalid receive attempts */	if (unlikely(!buf_len))		return -EINVAL;	if (unlikely(sock->state == SS_DISCONNECTING)) {		if (skb_queue_len(&sock->sk->sk_receive_queue) == 0)			return -ENOTCONN;	} else if (unlikely(sock->state != SS_CONNECTED))		return -ENOTCONN;	/* Look for a message in receive queue; wait if necessary */	if (unlikely(down_interruptible(&tsock->sem)))		return -ERESTARTSYS;restart:	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&		     (flags & MSG_DONTWAIT))) {		res = -EWOULDBLOCK;		goto exit;	}	if ((res = wait_event_interruptible(		*sock->sk->sk_sleep,		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||		 (sock->state == SS_DISCONNECTING))) )) {		goto exit;	}	/* Catch attempt to receive on an already terminated connection */	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */	if (!q_len) {		res = -ENOTCONN;		goto exit;	}	/* Get access to first message in receive queue */	buf = skb_peek(&sock->sk->sk_receive_queue);	msg = buf_msg(buf);	sz = msg_data_sz(msg);	err = msg_errcode(msg);	/* Discard an empty non-errored message & try again */	if ((!sz) && (!err)) {		advance_queue(tsock);		goto restart;	}	/* Optionally capture sender's address & ancillary data of first msg */	if (sz_copied == 0) {		set_orig_addr(m, msg);		if ((res = anc_data_recv(m, msg, tsock->p)))			goto exit;	}	/* Capture message data (if valid) & compute return value (always) */	if (!err) {		buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);		sz = skb_tail_pointer(buf) - buf_crs;		needed = (buf_len - sz_copied);		sz_to_copy = (sz <= needed) ? sz : needed;		if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {			res = -EFAULT;			goto exit;		}		sz_copied += sz_to_copy;		if (sz_to_copy < sz) {			if (!(flags & MSG_PEEK))				TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy;			goto exit;		}		crs += sz_to_copy;	} else {		if (sz_copied != 0)			goto exit; /* can't add error msg to valid data */		if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)			res = 0;		else			res = -ECONNRESET;	}	/* Consume received message (optional) */	if (likely(!(flags & MSG_PEEK))) {		if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))			tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);		advance_queue(tsock);	}	/* Loop around if more data is required */	if ((sz_copied < buf_len)    /* didn't get all requested data */	    && (flags & MSG_WAITALL) /* ... and need to wait for more */	    && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */	    && (!err)                /* ... and haven't reached a FIN */	    )		goto restart;exit:	up(&tsock->sem);	return sz_copied ? sz_copied : res;}/** * queue_overloaded - test if queue overload condition exists * @queue_size: current size of queue * @base: nominal maximum size of queue * @msg: message to be added to queue * * Returns 1 if queue is currently overloaded, 0 otherwise */static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg){	u32 threshold;	u32 imp = msg_importance(msg);	if (imp == TIPC_LOW_IMPORTANCE)		threshold = base;	else if (imp == TIPC_MEDIUM_IMPORTANCE)		threshold = base * 2;	else if (imp == TIPC_HIGH_IMPORTANCE)		threshold = base * 100;	else		return 0;	if (msg_connected(msg))		threshold *= 4;	return (queue_size > threshold);}/** * async_disconnect - wrapper function used to disconnect port * @portref: TIPC port reference (passed as pointer-sized value) */static void async_disconnect(unsigned long portref){	tipc_disconnect((u32)portref);}/** * dispatch - handle arriving message * @tport: TIPC port that received message * @buf: message * * Called with port locked.  Must not take socket lock to avoid deadlock risk. * * Returns TIPC error status code (TIPC_OK if message is not to be rejected) */static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf){	struct tipc_msg *msg = buf_msg(buf);	struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;	struct socket *sock;	u32 recv_q_len;	/* Reject message if socket is closing */	if (!tsock)		return TIPC_ERR_NO_PORT;	/* Reject message if it is wrong sort of message for socket */	/*	 * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD?	 * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY	 * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC	 */	sock = tsock->sk.sk_socket;	if (sock->state == SS_READY) {		if (msg_connected(msg)) {			msg_dbg(msg, "dispatch filter 1\n");			return TIPC_ERR_NO_PORT;

⌨️ 快捷键说明

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