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

📄 socket.c

📁 linux 1.0 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * NET		An implementation of the SOCKET network access protocol. * * Version:	@(#)socket.c	1.0.5	05/25/93 * * Authors:	Orest Zborowski, <obz@Kodak.COM> *		Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * * Fixes: *		Anonymous	:	NOTSOCK/BADF cleanup. Error fix in *					shutdown() *		Alan Cox	:	verify_area() fixes * * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/stat.h>#include <linux/socket.h>#include <linux/fcntl.h>#include <linux/net.h>#include <linux/ddi.h>#include <asm/system.h>#include <asm/segment.h>#undef SOCK_DEBUG#ifdef SOCK_DEBUG#include <stdarg.h>#define DPRINTF(x) dprintf x#else#define DPRINTF(x) /**/#endifstatic int sock_lseek(struct inode *inode, struct file *file, off_t offset,		      int whence);static int sock_read(struct inode *inode, struct file *file, char *buf,		     int size);static int sock_write(struct inode *inode, struct file *file, char *buf,		      int size);static int sock_readdir(struct inode *inode, struct file *file,			struct dirent *dirent, int count);static void sock_close(struct inode *inode, struct file *file);static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);static int sock_ioctl(struct inode *inode, struct file *file,		      unsigned int cmd, unsigned long arg);static struct file_operations socket_file_ops = {  sock_lseek,  sock_read,  sock_write,  sock_readdir,  sock_select,  sock_ioctl,  NULL,			/* mmap */  NULL,			/* no special open code... */  sock_close};static struct socket sockets[NSOCKETS];static struct wait_queue *socket_wait_free = NULL;static struct proto_ops *pops[NPROTO];static int net_debug = 0;#define last_socket	(sockets + NSOCKETS - 1)#ifdef SOCK_DEBUG/* Module debugging. */static voiddprintf(int level, char *fmt, ...){  char buff[1024];  va_list args;  extern int vsprintf(char * buf, const char * fmt, va_list args);  if (level == 0) return;  va_start(args, fmt);  vsprintf(buff, fmt, args);  va_end(args);  printk(buff);}#endif/* Obtains the first available file descriptor and sets it up for use. */static intget_fd(struct inode *inode){  int fd;  struct file *file;  /* Find a file descriptor suitable for return to the user. */  file = get_empty_filp();  if (!file) return(-1);  for (fd = 0; fd < NR_OPEN; ++fd)	if (!current->filp[fd]) break;  if (fd == NR_OPEN) {	file->f_count = 0;	return(-1);  }  FD_CLR(fd, &current->close_on_exec);  current->filp[fd] = file;  file->f_op = &socket_file_ops;  file->f_mode = 3;  file->f_flags = 0;  file->f_count = 1;  file->f_inode = inode;  if (inode) inode->i_count++;  file->f_pos = 0;  return(fd);}/* * Reverses the action of get_fd() by releasing the file. it closes * the descriptor, but makes sure it does nothing more. Called when * an incomplete socket must be closed, along with sock_release(). */static inline voidtoss_fd(int fd){  sys_close(fd);		/* the count protects us from iput */}struct socket *socki_lookup(struct inode *inode){  struct socket *sock;  if ((sock = inode->i_socket) != NULL) {	if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)		return sock;	printk("socket.c: uhhuh. stale inode->i_socket pointer\n");  }  for (sock = sockets; sock <= last_socket; ++sock)	if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) {		printk("socket.c: uhhuh. Found socket despite no inode->i_socket pointer\n");		return(sock);	}  return(NULL);}static inline struct socket *sockfd_lookup(int fd, struct file **pfile){  struct file *file;  if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd])) return(NULL);  if (pfile) *pfile = file;  return(socki_lookup(file->f_inode));}static struct socket *sock_alloc(int wait){  struct socket *sock;  while (1) {	cli();	for (sock = sockets; sock <= last_socket; ++sock) {		if (sock->state == SS_FREE) {			sock->state = SS_UNCONNECTED;			sti();			sock->flags = 0;			sock->ops = NULL;			sock->data = NULL;			sock->conn = NULL;			sock->iconn = NULL;			/*			 * This really shouldn't be necessary, but everything			 * else depends on inodes, so we grab it.			 * Sleeps are also done on the i_wait member of this			 * inode.  The close system call will iput this inode			 * for us.			 */			if (!(SOCK_INODE(sock) = get_empty_inode())) {				printk("NET: sock_alloc: no more inodes\n");				sock->state = SS_FREE;				return(NULL);			}			SOCK_INODE(sock)->i_mode = S_IFSOCK;			SOCK_INODE(sock)->i_uid = current->euid;			SOCK_INODE(sock)->i_gid = current->egid;			SOCK_INODE(sock)->i_socket = sock;			sock->wait = &SOCK_INODE(sock)->i_wait;			DPRINTF((net_debug,				"NET: sock_alloc: sk 0x%x, ino 0x%x\n",				       			sock, SOCK_INODE(sock)));			return(sock);		}	}	sti();	if (!wait) return(NULL);	DPRINTF((net_debug, "NET: sock_alloc: no free sockets, sleeping...\n"));	interruptible_sleep_on(&socket_wait_free);	if (current->signal & ~current->blocked) {		DPRINTF((net_debug, "NET: sock_alloc: sleep was interrupted\n"));		return(NULL);	}	DPRINTF((net_debug, "NET: sock_alloc: wakeup... trying again...\n"));  }}static inline voidsock_release_peer(struct socket *peer){  peer->state = SS_DISCONNECTING;  wake_up_interruptible(peer->wait);}static voidsock_release(struct socket *sock){  int oldstate;  struct inode *inode;  struct socket *peersock, *nextsock;  DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n",						sock, SOCK_INODE(sock)));  if ((oldstate = sock->state) != SS_UNCONNECTED)			sock->state = SS_DISCONNECTING;  /* Wake up anyone waiting for connections. */  for (peersock = sock->iconn; peersock; peersock = nextsock) {	nextsock = peersock->next;	sock_release_peer(peersock);  }  /*   * Wake up anyone we're connected to. First, we release the   * protocol, to give it a chance to flush data, etc.   */  peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;  if (sock->ops) sock->ops->release(sock, peersock);  if (peersock) sock_release_peer(peersock);  inode = SOCK_INODE(sock);  sock->state = SS_FREE;		/* this really releases us */  wake_up_interruptible(&socket_wait_free);  /* We need to do this. If sock alloc was called we already have an inode. */  iput(inode);}static intsock_lseek(struct inode *inode, struct file *file, off_t offset, int whence){  DPRINTF((net_debug, "NET: sock_lseek: huh?\n"));  return(-ESPIPE);}static intsock_read(struct inode *inode, struct file *file, char *ubuf, int size){  struct socket *sock;  DPRINTF((net_debug, "NET: sock_read: buf=0x%x, size=%d\n", ubuf, size));  if (!(sock = socki_lookup(inode))) {	printk("NET: sock_read: can't find socket for inode!\n");	return(-EBADF);  }  if (sock->flags & SO_ACCEPTCON) return(-EINVAL);  return(sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK)));}static intsock_write(struct inode *inode, struct file *file, char *ubuf, int size){  struct socket *sock;  DPRINTF((net_debug, "NET: sock_write: buf=0x%x, size=%d\n", ubuf, size));  if (!(sock = socki_lookup(inode))) {	printk("NET: sock_write: can't find socket for inode!\n");	return(-EBADF);  }  if (sock->flags & SO_ACCEPTCON) return(-EINVAL);  return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));}static intsock_readdir(struct inode *inode, struct file *file, struct dirent *dirent,	     int count){  DPRINTF((net_debug, "NET: sock_readdir: huh?\n"));  return(-EBADF);}intsock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,	   unsigned long arg){  struct socket *sock;  DPRINTF((net_debug, "NET: sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n",							inode, cmd, arg));  if (!(sock = socki_lookup(inode))) {	printk("NET: sock_ioctl: can't find socket for inode!\n");	return(-EBADF);  }  return(sock->ops->ioctl(sock, cmd, arg));}static intsock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait){  struct socket *sock;  DPRINTF((net_debug, "NET: sock_select: inode = 0x%x, kind = %s\n", inode,       (sel_type == SEL_IN) ? "in" :       (sel_type == SEL_OUT) ? "out" : "ex"));  if (!(sock = socki_lookup(inode))) {	printk("NET: sock_select: can't find socket for inode!\n");	return(0);  }  /* We can't return errors to select, so its either yes or no. */  if (sock->ops && sock->ops->select)	return(sock->ops->select(sock, sel_type, wait));  return(0);}voidsock_close(struct inode *inode, struct file *file){  struct socket *sock;  DPRINTF((net_debug, "NET: sock_close: inode=0x%x (cnt=%d)\n",						inode, inode->i_count));  /* It's possible the inode is NULL if we're closing an unfinished socket. */  if (!inode) return;  if (!(sock = socki_lookup(inode))) {	printk("NET: sock_close: can't find socket for inode!\n");	return;  }  sock_release(sock);}intsock_awaitconn(struct socket *mysock, struct socket *servsock){  struct socket *last;  DPRINTF((net_debug,	"NET: sock_awaitconn: trying to connect socket 0x%x to 0x%x\n",							mysock, servsock));  if (!(servsock->flags & SO_ACCEPTCON)) {	DPRINTF((net_debug,		"NET: sock_awaitconn: server not accepting connections\n"));	return(-EINVAL);  }  /* Put ourselves on the server's incomplete connection queue. */  mysock->next = NULL;  cli();  if (!(last = servsock->iconn)) servsock->iconn = mysock;    else {	while (last->next) last = last->next;	last->next = mysock;  }  mysock->state = SS_CONNECTING;  mysock->conn = servsock;  sti();  /*   * Wake up server, then await connection. server will set state to   * SS_CONNECTED if we're connected.   */  wake_up_interruptible(servsock->wait);  if (mysock->state != SS_CONNECTED) {	interruptible_sleep_on(mysock->wait);	if (mysock->state != SS_CONNECTED &&	    mysock->state != SS_DISCONNECTING) {		/*		 * if we're not connected we could have been		 * 1) interrupted, so we need to remove ourselves		 *    from the server list		 * 2) rejected (mysock->conn == NULL), and have		 *    already been removed from the list		 */		if (mysock->conn == servsock) {			cli();			if ((last = servsock->iconn) == mysock)					servsock->iconn = mysock->next;			else {				while (last->next != mysock) last = last->next;				last->next = mysock->next;			}			sti();		}		return(mysock->conn ? -EINTR : -EACCES);	}  }  return(0);}/* * Perform the socket system call. we locate the appropriate * family, then create a fresh socket. */static intsock_socket(int family, int type, int protocol){  int i, fd;  struct socket *sock;  struct proto_ops *ops;  DPRINTF((net_debug,	"NET: sock_socket: family = %d, type = %d, protocol = %d\n",						family, type, protocol));  /* Locate the correct protocol family. */  for (i = 0; i < NPROTO; ++i) {	if (pops[i] == NULL) continue;	if (pops[i]->family == family) break;  }  if (i == NPROTO) {	DPRINTF((net_debug, "NET: sock_socket: family not found\n"));	return(-EINVAL);  }  ops = pops[i];  /*   * Check that this is a type that we know how to manipulate and   * the protocol makes sense here. The family can still reject the   * protocol later.   */  if ((type != SOCK_STREAM && type != SOCK_DGRAM &&       type != SOCK_SEQPACKET && type != SOCK_RAW &&       type != SOCK_PACKET) || protocol < 0)							return(-EINVAL);  /*   * allocate the socket and allow the family to set things up. if   * the protocol is 0, the family is instructed to select an appropriate   * default.   */  if (!(sock = sock_alloc(1))) {	printk("sock_socket: no more sockets\n");	return(-EAGAIN);  }  sock->type = type;  sock->ops = ops;  if ((i = sock->ops->create(sock, protocol)) < 0) {	sock_release(sock);	return(i);  }  if ((fd = get_fd(SOCK_INODE(sock))) < 0) {	sock_release(sock);	return(-EINVAL);  }  return(fd);}static intsock_socketpair(int family, int type, int protocol, unsigned long usockvec[2]){  int fd1, fd2, i;  struct socket *sock1, *sock2;  int er;  DPRINTF((net_debug,	"NET: sock_socketpair: family = %d, type = %d, protocol = %d\n",							family, type, protocol));  /*   * Obtain the first socket and check if the underlying protocol   * supports the socketpair call.   */  if ((fd1 = sock_socket(family, type, protocol)) < 0) return(fd1);  sock1 = sockfd_lookup(fd1, NULL);  if (!sock1->ops->socketpair) {	sys_close(fd1);	return(-EINVAL);  }  /* Now grab another socket and try to connect the two together. */  if ((fd2 = sock_socket(family, type, protocol)) < 0) {	sys_close(fd1);	return(-EINVAL);  }  sock2 = sockfd_lookup(fd2, NULL);  if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) {	sys_close(fd1);	sys_close(fd2);	return(i);  }  sock1->conn = sock2;  sock2->conn = sock1;  sock1->state = SS_CONNECTED;  sock2->state = SS_CONNECTED;  er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int));  if(er)  	return er;  put_fs_long(fd1, &usockvec[0]);  put_fs_long(fd2, &usockvec[1]);  return(0);}/* * Bind a name to a socket. Nothing much to do here since its * the protocol's responsibility to handle the local address. */static intsock_bind(int fd, struct sockaddr *umyaddr, int addrlen){  struct socket *sock;  int i;  DPRINTF((net_debug, "NET: sock_bind: fd = %d\n", fd));  if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)								return(-EBADF);  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);  if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) {	DPRINTF((net_debug, "NET: sock_bind: bind failed\n"));	return(i);

⌨️ 快捷键说明

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