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

📄 sock.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  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/sched.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/smp_lock.h>#include <net/scm.h>#include <net/ip.h>#include <linux/smb_fs.h>#include <linux/smb.h>#include <linux/smbno.h>#include <asm/uaccess.h>#include "smb_debug.h"#include "proto.h"static int_recvfrom(struct socket *socket, unsigned char *ubuf, int size,	  unsigned flags){	struct iovec iov;	struct msghdr msg;	struct scm_cookie scm;	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	msg.msg_control = NULL;	iov.iov_base = ubuf;	iov.iov_len = size;		memset(&scm, 0,sizeof(scm));	size=socket->ops->recvmsg(socket, &msg, size, flags, &scm);	if(size>=0)		scm_recv(socket,&msg,&scm,flags);	return size;}static int_send(struct socket *socket, const void *buff, int len){	struct iovec iov;	struct msghdr msg;	struct scm_cookie scm;	int err;	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	msg.msg_control = NULL;	msg.msg_controllen = 0;		iov.iov_base = (void *)buff;	iov.iov_len = len;	msg.msg_flags = 0;	err = scm_send(socket, &msg, &scm);        if (err >= 0)	{		err = socket->ops->sendmsg(socket, &msg, len, &scm);		scm_destroy(&scm);	}	return err;}struct data_callback {	struct tq_struct cb;	struct sock *sk;};/* * N.B. What happens if we're in here when the socket closes?? */static voidfound_data(struct sock *sk){	/*	 * FIXME: copied from sock_def_readable, it should be a call to	 * server->data_ready()	-- manfreds@colorfullife.com	 */	read_lock(&sk->callback_lock);	if(!sk->dead) {		wake_up_interruptible(sk->sleep);		sock_wake_async(sk->socket,1,POLL_IN);	}	read_unlock(&sk->callback_lock);}static voidsmb_data_callback(void* ptr){	struct data_callback* job=ptr;	struct socket *socket = job->sk->socket;	unsigned char peek_buf[4];	int result = 0;	mm_segment_t fs;	int count = 100;   /* this is a lot, we should have some data waiting */	int found = 0;	fs = get_fs();	set_fs(get_ds());	lock_kernel();	while (count-- > 0) {		peek_buf[0] = 0;		result = -EIO;		if (job->sk->dead) {			PARANOIA("sock dead!\n");			break;		}		result = _recvfrom(socket, (void *) peek_buf, 1,				   MSG_PEEK | MSG_DONTWAIT);		if (result < 0)			break;		if (peek_buf[0] != 0x85)			break;		/* got SESSION KEEP ALIVE */		result = _recvfrom(socket, (void *) peek_buf, 4,				   MSG_DONTWAIT);		DEBUG1("got SESSION KEEPALIVE\n");		if (result < 0)			break;		found = 1;	}	unlock_kernel();	set_fs(fs);	DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);	if (found)		found_data(job->sk);	smb_kfree(ptr);}static voidsmb_data_ready(struct sock *sk, int len){	struct data_callback* job;	job = smb_kmalloc(sizeof(struct data_callback),GFP_ATOMIC);	if(job == 0) {		printk("smb_data_ready: lost SESSION KEEPALIVE due to OOM.\n");		found_data(sk);		return;	}	INIT_LIST_HEAD(&job->cb.list);	job->cb.sync = 0;	job->cb.routine = smb_data_callback;	job->cb.data = job;	job->sk = sk;	schedule_task(&job->cb);}intsmb_valid_socket(struct inode * inode){	return (inode && S_ISSOCK(inode->i_mode) && 		inode->u.socket_i.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_dentry->d_inode))			PARANOIA("bad socket!\n");#endif		return &file->f_dentry->d_inode->u.socket_i;	}	return NULL;}intsmb_catch_keepalive(struct smb_sb_info *server){	struct socket *socket;	struct sock *sk;	void *data_ready;	int error;	error = -EINVAL;	socket = server_sock(server);	if (!socket)	{		printk(KERN_DEBUG "smb_catch_keepalive: did not get valid server!\n");		server->data_ready = NULL;		goto out;	}	sk = socket->sk;	if (sk == NULL)	{		DEBUG1("sk == NULL");		server->data_ready = NULL;		goto out;	}	DEBUG1("sk->d_r = %x, server->d_r = %x\n",		 (unsigned int) (sk->data_ready),		 (unsigned int) (server->data_ready));	/*	 * Install the callback atomically to avoid races ...	 */	data_ready = xchg(&sk->data_ready, smb_data_ready);	if (data_ready != smb_data_ready) {		server->data_ready = data_ready;		error = 0;	} else		printk(KERN_ERR "smb_catch_keepalive: already done\n");out:	return error;}intsmb_dont_catch_keepalive(struct smb_sb_info *server){	struct socket *socket;	struct sock *sk;	void * data_ready;	int error;	error = -EINVAL;	socket = server_sock(server);	if (!socket)	{		printk(KERN_DEBUG "smb_dont_catch_keepalive: did not get valid server!\n");		goto out;	}	sk = socket->sk;	if (sk == NULL)	{		DEBUG1("sk == NULL");		goto out;	}	/* Is this really an error?? */	if (server->data_ready == NULL)	{		printk(KERN_DEBUG "smb_dont_catch_keepalive: "		       "server->data_ready == NULL\n");		goto out;	}	DEBUG1("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",	       (unsigned int) (sk->data_ready),	       (unsigned int) (server->data_ready));	/*	 * Restore the original callback atomically to avoid races ...	 */	data_ready = xchg(&sk->data_ready, server->data_ready);	server->data_ready = NULL;	if (data_ready != smb_data_ready)	{		printk(KERN_ERR "smb_dont_catch_keepalive: "		       "sk->data_ready != smb_data_ready\n");	}	error = 0;out:	return error;}/* * Called with the server locked. */voidsmb_close_socket(struct smb_sb_info *server){	struct file * file = server->sock_file;	if (file)	{		VERBOSE("closing socket %p\n", server_sock(server));#ifdef SMBFS_PARANOIA		if (server_sock(server)->sk->data_ready == smb_data_ready)			PARANOIA("still catching keepalives!\n");#endif		server->sock_file = NULL;		fput(file);	}}static intsmb_send_raw(struct socket *socket, unsigned char *source, int length){	int result;	int already_sent = 0;	while (already_sent < length)	{		result = _send(socket,			       (void *) (source + already_sent),			       length - already_sent);		if (result == 0)		{			return -EIO;		}		if (result < 0)		{			DEBUG1("smb_send_raw: sendto error = %d\n", -result);			return result;		}		already_sent += result;	}	return already_sent;}static intsmb_receive_raw(struct socket *socket, unsigned char *target, int length){	int result;	int already_read = 0;	while (already_read < length)	{		result = _recvfrom(socket,				   (void *) (target + already_read),				   length - already_read, 0);		if (result == 0)		{			return -EIO;		}		if (result < 0)		{			DEBUG1("recvfrom error = %d\n", -result);			return result;		}		already_read += result;	}	return already_read;}static intsmb_get_length(struct socket *socket, unsigned char *header){	int result;	unsigned char peek_buf[4];	mm_segment_t fs;      re_recv:	fs = get_fs();	set_fs(get_ds());	result = smb_receive_raw(socket, peek_buf, 4);	set_fs(fs);	if (result < 0)	{		PARANOIA("recv error = %d\n", -result);		return result;	}	switch (peek_buf[0])	{	case 0x00:	case 0x82:		break;	case 0x85:		DEBUG1("Got SESSION KEEP ALIVE\n");		goto re_recv;	default:		PARANOIA("Invalid NBT packet, code=%x\n", peek_buf[0]);		return -EIO;	}	if (header != NULL)	{		memcpy(header, peek_buf, 4);	}	/* The length in the RFC NB header is the raw data length */	return smb_len(peek_buf);}/* * Since we allocate memory in increments of PAGE_SIZE, * round up the packet length to the next multiple. */intsmb_round_length(int len){	return (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);} /* * smb_receive * fs points to the correct segment */static intsmb_receive(struct smb_sb_info *server){	struct socket *socket = server_sock(server);	unsigned char * packet = server->packet;	int len, result;	unsigned char peek_buf[4];	result = smb_get_length(socket, peek_buf);	if (result < 0)		goto out;	len = result;	/*	 * Some servers do not respect our max_xmit and send	 * larger packets.  Try to allocate a new packet,	 * but don't free the old one unless we succeed.	 */	if (len + 4 > server->packet_size)	{		int new_len = smb_round_length(len + 4);		result = -ENOMEM;		packet = smb_vmalloc(new_len);		if (packet == NULL)			goto out;		smb_vfree(server->packet);		server->packet = packet;		server->packet_size = new_len;	}

⌨️ 快捷键说明

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