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

📄 sock.c

📁 linux 内核源代码
💻 C
字号:
/* *  sock.c * *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke *  Copyright (C) 1997 by Volker Lendecke * *  Please add a note about your changes to smbfs in the ChangeLog file. */#include <linux/fs.h>#include <linux/time.h>#include <linux/errno.h>#include <linux/socket.h>#include <linux/fcntl.h>#include <linux/file.h>#include <linux/in.h>#include <linux/net.h>#include <linux/mm.h>#include <linux/netdevice.h>#include <linux/workqueue.h>#include <net/scm.h>#include <net/tcp_states.h>#include <net/ip.h>#include <linux/smb_fs.h>#include <linux/smb.h>#include <linux/smbno.h>#include <asm/uaccess.h>#include <asm/ioctls.h>#include "smb_debug.h"#include "proto.h"#include "request.h"static int_recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags){	struct kvec iov = {ubuf, size};	struct msghdr msg = {.msg_flags = flags};	msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;	return kernel_recvmsg(socket, &msg, &iov, 1, size, msg.msg_flags);}/* * Return the server this socket belongs to */static struct smb_sb_info *server_from_socket(struct socket *socket){	return socket->sk->sk_user_data;}/* * Called when there is data on the socket. */voidsmb_data_ready(struct sock *sk, int len){	struct smb_sb_info *server = server_from_socket(sk->sk_socket);	void (*data_ready)(struct sock *, int) = server->data_ready;	data_ready(sk, len);	VERBOSE("(%p, %d)\n", sk, len);	smbiod_wake_up();}intsmb_valid_socket(struct inode * inode){	return (inode && S_ISSOCK(inode->i_mode) && 		SOCKET_I(inode)->type == SOCK_STREAM);}static struct socket *server_sock(struct smb_sb_info *server){	struct file *file;	if (server && (file = server->sock_file))	{#ifdef SMBFS_PARANOIA		if (!smb_valid_socket(file->f_path.dentry->d_inode))			PARANOIA("bad socket!\n");#endif		return SOCKET_I(file->f_path.dentry->d_inode);	}	return NULL;}voidsmb_close_socket(struct smb_sb_info *server){	struct file * file = server->sock_file;	if (file) {		struct socket *sock = server_sock(server);		VERBOSE("closing socket %p\n", sock);		sock->sk->sk_data_ready = server->data_ready;		server->sock_file = NULL;		fput(file);	}}static intsmb_get_length(struct socket *socket, unsigned char *header){	int result;	result = _recvfrom(socket, header, 4, MSG_PEEK);	if (result == -EAGAIN)		return -ENODATA;	if (result < 0) {		PARANOIA("recv error = %d\n", -result);		return result;	}	if (result < 4)		return -ENODATA;	switch (header[0]) {	case 0x00:	case 0x82:		break;	case 0x85:		DEBUG1("Got SESSION KEEP ALIVE\n");		_recvfrom(socket, header, 4, 0);	/* read away */		return -ENODATA;	default:		PARANOIA("Invalid NBT packet, code=%x\n", header[0]);		return -EIO;	}	/* The length in the RFC NB header is the raw data length */	return smb_len(header);}intsmb_recv_available(struct smb_sb_info *server){	mm_segment_t oldfs;	int avail, err;	struct socket *sock = server_sock(server);	oldfs = get_fs();	set_fs(get_ds());	err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);	set_fs(oldfs);	return (err >= 0) ? avail : err;}/* * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc) */static intsmb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount){	struct kvec *iv = *data;	int i;	int len;	/*	 *	Eat any sent kvecs	 */	while (iv->iov_len <= amount) {		amount -= iv->iov_len;		iv++;		(*num)--;	}	/*	 *	And chew down the partial one	 */	vec[0].iov_len = iv->iov_len-amount;	vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;	iv++;	len = vec[0].iov_len;	/*	 *	And copy any others	 */	for (i = 1; i < *num; i++) {		vec[i] = *iv++;		len += vec[i].iov_len;	}	*data = vec;	return len;}/* * smb_receive_header * Only called by the smbiod thread. */intsmb_receive_header(struct smb_sb_info *server){	struct socket *sock;	int result = 0;	unsigned char peek_buf[4];	result = -EIO; 	sock = server_sock(server);	if (!sock)		goto out;	if (sock->sk->sk_state != TCP_ESTABLISHED)		goto out;	if (!server->smb_read) {		result = smb_get_length(sock, peek_buf);		if (result < 0) {			if (result == -ENODATA)				result = 0;			goto out;		}		server->smb_len = result + 4;		if (server->smb_len < SMB_HEADER_LEN) {			PARANOIA("short packet: %d\n", result);			server->rstate = SMB_RECV_DROP;			result = -EIO;			goto out;		}		if (server->smb_len > SMB_MAX_PACKET_SIZE) {			PARANOIA("long packet: %d\n", result);			server->rstate = SMB_RECV_DROP;			result = -EIO;			goto out;		}	}	result = _recvfrom(sock, server->header + server->smb_read,			   SMB_HEADER_LEN - server->smb_read, 0);	VERBOSE("_recvfrom: %d\n", result);	if (result < 0) {		VERBOSE("receive error: %d\n", result);		goto out;	}	server->smb_read += result;	if (server->smb_read == SMB_HEADER_LEN)		server->rstate = SMB_RECV_HCOMPLETE;out:	return result;}static char drop_buffer[PAGE_SIZE];/* * smb_receive_drop - read and throw away the data * Only called by the smbiod thread. * * FIXME: we are in the kernel, could we just tell the socket that we want * to drop stuff from the buffer? */intsmb_receive_drop(struct smb_sb_info *server){	struct socket *sock;	unsigned int flags;	struct kvec iov;	struct msghdr msg;	int rlen = smb_len(server->header) - server->smb_read + 4;	int result = -EIO;	if (rlen > PAGE_SIZE)		rlen = PAGE_SIZE;	sock = server_sock(server);	if (!sock)		goto out;	if (sock->sk->sk_state != TCP_ESTABLISHED)		goto out;	flags = MSG_DONTWAIT | MSG_NOSIGNAL;	iov.iov_base = drop_buffer;	iov.iov_len = PAGE_SIZE;	msg.msg_flags = flags;	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_control = NULL;	result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);	VERBOSE("read: %d\n", result);	if (result < 0) {		VERBOSE("receive error: %d\n", result);		goto out;	}	server->smb_read += result;	if (server->smb_read >= server->smb_len)		server->rstate = SMB_RECV_END;out:	return result;}/* * smb_receive * Only called by the smbiod thread. */intsmb_receive(struct smb_sb_info *server, struct smb_request *req){	struct socket *sock;	unsigned int flags;	struct kvec iov[4];	struct kvec *p = req->rq_iov;	size_t num = req->rq_iovlen;	struct msghdr msg;	int rlen;	int result = -EIO;	sock = server_sock(server);	if (!sock)		goto out;	if (sock->sk->sk_state != TCP_ESTABLISHED)		goto out;	flags = MSG_DONTWAIT | MSG_NOSIGNAL;	msg.msg_flags = flags;	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_control = NULL;	/* Dont repeat bytes and count available bufferspace */	rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd);	if (req->rq_rlen < rlen)		rlen = req->rq_rlen;	result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);	VERBOSE("read: %d\n", result);	if (result < 0) {		VERBOSE("receive error: %d\n", result);		goto out;	}	req->rq_bytes_recvd += result;	server->smb_read += result;out:	return result;}/* * Try to send a SMB request. This may return after sending only parts of the * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent. * * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c */intsmb_send_request(struct smb_request *req){	struct smb_sb_info *server = req->rq_server;	struct socket *sock;	struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};        int slen = req->rq_slen - req->rq_bytes_sent;	int result = -EIO;	struct kvec iov[4];	struct kvec *p = req->rq_iov;	size_t num = req->rq_iovlen;	sock = server_sock(server);	if (!sock)		goto out;	if (sock->sk->sk_state != TCP_ESTABLISHED)		goto out;	/* Dont repeat bytes */	if (req->rq_bytes_sent)		smb_move_iov(&p, &num, iov, req->rq_bytes_sent);	result = kernel_sendmsg(sock, &msg, p, num, slen);	if (result >= 0) {		req->rq_bytes_sent += result;		if (req->rq_bytes_sent >= req->rq_slen)			req->rq_flags |= SMB_REQ_TRANSMITTED;	}out:	return result;}

⌨️ 快捷键说明

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