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

📄 socket.c

📁 LINUX 1.0 内核c源代码,是一份精简的linux内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  }
  return(0);
}


/*
 * Perform a listen. Basically, we allow the protocol to do anything
 * necessary for a listen, and if that works, we mark the socket as
 * ready for listening.
 */
static int
sock_listen(int fd, int backlog)
{
  struct socket *sock;

  DPRINTF((net_debug, "NET: sock_listen: 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 (sock->state != SS_UNCONNECTED) {
	DPRINTF((net_debug, "NET: sock_listen: socket isn't unconnected\n"));
	return(-EINVAL);
  }
  if (sock->ops && sock->ops->listen) sock->ops->listen(sock, backlog);
  sock->flags |= SO_ACCEPTCON;
  return(0);
}


/*
 * For accept, we attempt to create a new socket, set up the link
 * with the client, wake up the client, then return the new
 * connected fd.
 */
static int
sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
{
  struct file *file;
  struct socket *sock, *newsock;
  int i;

  DPRINTF((net_debug, "NET: sock_accept: fd = %d\n", fd));
  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  
  if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK);
  if (sock->state != SS_UNCONNECTED) {
	DPRINTF((net_debug, "NET: sock_accept: socket isn't unconnected\n"));
	return(-EINVAL);
  }
  if (!(sock->flags & SO_ACCEPTCON)) {
	DPRINTF((net_debug,
		"NET: sock_accept: socket not accepting connections!\n"));
	return(-EINVAL);
  }

  if (!(newsock = sock_alloc(0))) {
	printk("NET: sock_accept: no more sockets\n");
	return(-EAGAIN);
  }
  newsock->type = sock->type;
  newsock->ops = sock->ops;
  if ((i = sock->ops->dup(newsock, sock)) < 0) {
	sock_release(newsock);
	return(i);
  }

  i = newsock->ops->accept(sock, newsock, file->f_flags);
  if ( i < 0) {
	sock_release(newsock);
	return(i);
  }

  if ((fd = get_fd(SOCK_INODE(newsock))) < 0) {
	sock_release(newsock);
	return(-EINVAL);
  }

  DPRINTF((net_debug, "NET: sock_accept: connected socket 0x%x via 0x%x\n",
							sock, newsock));

  if (upeer_sockaddr)
	newsock->ops->getname(newsock, upeer_sockaddr, upeer_addrlen, 1);

  return(fd);
}


/* Attempt to connect to a socket with the server address. */
static int
sock_connect(int fd, struct sockaddr *uservaddr, int addrlen)
{
  struct socket *sock;
  struct file *file;
  int i;

  DPRINTF((net_debug, "NET: sock_connect: fd = %d\n", fd));
  if (fd < 0 || fd >= NR_OPEN || (file=current->filp[fd]) == NULL)
								return(-EBADF);
  
  if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK);
  switch(sock->state) {
	case SS_UNCONNECTED:
		/* This is ok... continue with connect */
		break;
	case SS_CONNECTED:
		/* Socket is already connected */
		return -EISCONN;
	case SS_CONNECTING:
		/* Not yet connected... we will check this. */
		return(sock->ops->connect(sock, uservaddr,
					  addrlen, file->f_flags));
	default:
		DPRINTF((net_debug,
			"NET: sock_connect: socket not unconnected\n"));
		return(-EINVAL);
  }
  i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags);
  if (i < 0) {
	DPRINTF((net_debug, "NET: sock_connect: connect failed\n"));
	return(i);
  }
  return(0);
}


static int
sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
{
  struct socket *sock;

  DPRINTF((net_debug, "NET: sock_getsockname: fd = %d\n", fd));
  if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
  return(sock->ops->getname(sock, usockaddr, usockaddr_len, 0));
}


static int
sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
{
  struct socket *sock;

  DPRINTF((net_debug, "NET: sock_getpeername: fd = %d\n", fd));
  if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
			return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
  return(sock->ops->getname(sock, usockaddr, usockaddr_len, 1));
}


static int
sock_send(int fd, void * buff, int len, unsigned flags)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug,
	"NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)\n",
       							fd, buff, len, flags));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->send(sock, buff, len, (file->f_flags & O_NONBLOCK), flags));
}


static int
sock_sendto(int fd, void * buff, int len, unsigned flags,
	   struct sockaddr *addr, int addr_len)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug,
	"NET: sock_sendto(fd = %d, buff = %X, len = %d, flags = %X,"
	 " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->sendto(sock, buff, len, (file->f_flags & O_NONBLOCK),
			   flags, addr, addr_len));
}


static int
sock_recv(int fd, void * buff, int len, unsigned flags)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug,
	"NET: sock_recv(fd = %d, buff = %X, len = %d, flags = %X)\n",
							fd, buff, len, flags));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->recv(sock, buff, len,(file->f_flags & O_NONBLOCK), flags));
}


static int
sock_recvfrom(int fd, void * buff, int len, unsigned flags,
	     struct sockaddr *addr, int *addr_len)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug,
	"NET: sock_recvfrom(fd = %d, buff = %X, len = %d, flags = %X,"
	" addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->recvfrom(sock, buff, len, (file->f_flags & O_NONBLOCK),
			     flags, addr, addr_len));
}


static int
sock_setsockopt(int fd, int level, int optname, char *optval, int optlen)
{
  struct socket *sock;
  struct file *file;
	
  DPRINTF((net_debug, "NET: sock_setsockopt(fd=%d, level=%d, optname=%d,\n",
							fd, level, optname));
  DPRINTF((net_debug, "                     optval = %X, optlen = %d)\n",
							optval, optlen));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->setsockopt(sock, level, optname, optval, optlen));
}


static int
sock_getsockopt(int fd, int level, int optname, char *optval, int *optlen)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug, "NET: sock_getsockopt(fd=%d, level=%d, optname=%d,\n",
						fd, level, optname));
  DPRINTF((net_debug, "                     optval = %X, optlen = %X)\n",
						optval, optlen));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);
  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
	    
  if (!sock->ops || !sock->ops->getsockopt) return(0);
  return(sock->ops->getsockopt(sock, level, optname, optval, optlen));
}


static int
sock_shutdown(int fd, int how)
{
  struct socket *sock;
  struct file *file;

  DPRINTF((net_debug, "NET: sock_shutdown(fd = %d, how = %d)\n", fd, how));

  if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
								return(-EBADF);

  if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);

  return(sock->ops->shutdown(sock, how));
}


int
sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  struct socket *sock;

  sock = socki_lookup (filp->f_inode);
  if (sock != NULL && sock->ops != NULL && sock->ops->fcntl != NULL)
				return(sock->ops->fcntl(sock, cmd, arg));
  return(-EINVAL);
}


/*
 * System call vectors. Since I (RIB) want to rewrite sockets as streams,
 * we have this level of indirection. Not a lot of overhead, since more of
 * the work is done via read/write/select directly.
 */
asmlinkage int
sys_socketcall(int call, unsigned long *args)
{
  int er;
  switch(call) {
	case SYS_SOCKET:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_socket(get_fs_long(args+0),
				   get_fs_long(args+1),
				   get_fs_long(args+2)));
	case SYS_BIND:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_bind(get_fs_long(args+0),
				 (struct sockaddr *)get_fs_long(args+1),
				 get_fs_long(args+2)));
	case SYS_CONNECT:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_connect(get_fs_long(args+0),
				    (struct sockaddr *)get_fs_long(args+1),
				    get_fs_long(args+2)));
	case SYS_LISTEN:
		er=verify_area(VERIFY_READ, args, 2 * sizeof(long));
		if(er)
			return er;
		return(sock_listen(get_fs_long(args+0),
				   get_fs_long(args+1)));
	case SYS_ACCEPT:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_accept(get_fs_long(args+0),
				   (struct sockaddr *)get_fs_long(args+1),
				   (int *)get_fs_long(args+2)));
	case SYS_GETSOCKNAME:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_getsockname(get_fs_long(args+0),
					(struct sockaddr *)get_fs_long(args+1),
					(int *)get_fs_long(args+2)));
	case SYS_GETPEERNAME:
		er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
		if(er)
			return er;
		return(sock_getpeername(get_fs_long(args+0),
					(struct sockaddr *)get_fs_long(args+1),
					(int *)get_fs_long(args+2)));
	case SYS_SOCKETPAIR:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(long));
		if(er)
			return er;
		return(sock_socketpair(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (unsigned long *)get_fs_long(args+3)));
	case SYS_SEND:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_send(get_fs_long(args+0),
				 (void *)get_fs_long(args+1),
				 get_fs_long(args+2),
				 get_fs_long(args+3)));
	case SYS_SENDTO:
		er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_sendto(get_fs_long(args+0),
				   (void *)get_fs_long(args+1),
				   get_fs_long(args+2),
				   get_fs_long(args+3),
				   (struct sockaddr *)get_fs_long(args+4),
				   get_fs_long(args+5)));
	case SYS_RECV:
		er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_recv(get_fs_long(args+0),
				 (void *)get_fs_long(args+1),
				 get_fs_long(args+2),
				 get_fs_long(args+3)));
	case SYS_RECVFROM:
		er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
		if(er)
			return er;
		return(sock_recvfrom(get_fs_long(args+0),
				     (void *)get_fs_long(args+1),
				     get_fs_long(args+2),
				     get_fs_long(args+3),
				     (struct sockaddr *)get_fs_long(args+4),
				     (int *)get_fs_long(args+5)));
	case SYS_SHUTDOWN:
		er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long));
		if(er)
			return er;
		return(sock_shutdown(get_fs_long(args+0),
				     get_fs_long(args+1)));
	case SYS_SETSOCKOPT:
		er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
		if(er)
			return er;
		return(sock_setsockopt(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (char *)get_fs_long(args+3),
				       get_fs_long(args+4)));
	case SYS_GETSOCKOPT:
		er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
		if(er)
			return er;
		return(sock_getsockopt(get_fs_long(args+0),
				       get_fs_long(args+1),
				       get_fs_long(args+2),
				       (char *)get_fs_long(args+3),
				       (int *)get_fs_long(args+4)));
	default:
		return(-EINVAL);
  }
}


static int
net_ioctl(unsigned int cmd, unsigned long arg)
{
  int er;
  switch(cmd) {
	case DDIOCSDBG:
		er=verify_area(VERIFY_READ, (void *)arg, sizeof(long));
		if(er)
			return er;
		net_debug = get_fs_long((long *)arg);
		if (net_debug != 0 && net_debug != 1) {
			net_debug = 0;
			return(-EINVAL);
		}
		return(0);
	default:
		return(-EINVAL);
  }
  /*NOTREACHED*/
  return(0);
}


/*
 * Handle the IOCTL system call for the NET devices.  This basically
 * means I/O control for the SOCKET layer (future expansions could be
 * a variable number of socket table entries, et al), and for the more
 * general protocols like ARP.  The latter currently lives in the INET
 * module, so we have to get ugly a tiny little bit.  Later... -FvK
 */
static int
net_fioctl(struct inode *inode, struct file *file,
	   unsigned int cmd, unsigned long arg)
{
  extern int arp_ioctl(unsigned int, void *);

  /* Dispatch on the minor device. */
  switch(MINOR(inode->i_rdev)) {
	case 0:		/* NET (SOCKET) */
		DPRINTF((net_debug, "NET: SOCKET level I/O control request.\n"));
		return(net_ioctl(cmd, arg));
#ifdef CONFIG_INET
	case 1:		/* ARP */
		DPRINTF((net_debug, "NET: ARP level I/O control request.\n"));
		return(arp_ioctl(cmd, (void *) arg));
#endif
	default:
		return(-ENODEV);
  }
  /*NOTREACHED*/
  return(-EINVAL);
}


static struct file_operations net_fops = {
  NULL,		/* LSEEK	*/
  NULL,		/* READ		*/
  NULL,		/* WRITE	*/
  NULL,		/* READDIR	*/
  NULL,		/* SELECT	*/
  net_fioctl,	/* IOCTL	*/
  NULL,		/* MMAP		*/
  NULL,		/* OPEN		*/
  NULL		/* CLOSE	*/
};


/*
 * This function is called by a protocol handler that wants to
 * advertise its address family, and have it linked into the
 * SOCKET module.
 */
int
sock_register(int family, struct proto_ops *ops)
{
  int i;

  cli();
  for(i = 0; i < NPROTO; i++) {
	if (pops[i] != NULL) continue;
	pops[i] = ops;
	pops[i]->family = family;
	sti();
	DPRINTF((net_debug, "NET: Installed protocol %d in slot %d (0x%X)\n",
						family, i, (long)ops));
	return(i);
  }
  sti();
  return(-ENOMEM);
}


void
sock_init(void)
{
  struct socket *sock;
  int i;

  /* Set up our SOCKET VFS major device. */
  if (register_chrdev(SOCKET_MAJOR, "socket", &net_fops) < 0) {
	printk("NET: cannot register major device %d!\n", SOCKET_MAJOR);
	return;
  }

  /* Release all sockets. */
  for (sock = sockets; sock <= last_socket; ++sock) sock->state = SS_FREE;

  /* Initialize all address (protocol) families. */
  for (i = 0; i < NPROTO; ++i) pops[i] = NULL;

  /* Initialize the DDI module. */
  ddi_init();

  /* Initialize the ARP module. */
#if 0
  arp_init();
#endif
}

⌨️ 快捷键说明

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