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

📄 sock.c

📁 <Linux1.0核心游记>电子书+书后源码+Linux1.0源码
💻 C
📖 第 1 页 / 共 2 页
字号:
  memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);  fname[sockaddr_len-UN_PATH_OFFSET] = '\0';  old_fs = get_fs();  set_fs(get_ds());  i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);  set_fs(old_fs);  if (i < 0) {	dprintf(1, "UNIX: connect: can't open socket %s\n", fname);	return(i);  }  serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);  iput(inode);  if (!serv_upd) {	dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",								fname, inode);	return(-EINVAL);  }  if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {	dprintf(1, "UNIX: connect: can't await connection\n");	return(i);  }  if (sock->conn) {	unix_data_ref(UN_DATA(sock->conn));	UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */  }  return(0);}/* * To do a socketpair, we just connect the two datas, easy! * Since we always wait on the socket inode, they're no contention * for a wait area, and deadlock prevention in the case of a process * writing to itself is, ignored, in true unix fashion! */static intunix_proto_socketpair(struct socket *sock1, struct socket *sock2){  struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);  unix_data_ref(upd1);  unix_data_ref(upd2);  upd1->peerupd = upd2;  upd2->peerupd = upd1;  return(0);}/* On accept, we ref the peer's data for safe writes. */static intunix_proto_accept(struct socket *sock, struct socket *newsock, int flags){  struct socket *clientsock;  dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",							sock, newsock);  /*   * If there aren't any sockets awaiting connection,   * then wait for one, unless nonblocking.   */  while(!(clientsock = sock->iconn)) {	if (flags & O_NONBLOCK) return(-EAGAIN);	interruptible_sleep_on(sock->wait);	if (current->signal & ~current->blocked) {		dprintf(1, "UNIX: accept: sleep was interrupted\n");		return(-ERESTARTSYS);	}  }  /*   * Great. Finish the connection relative to server and client,   * wake up the client and return the new fd to the server.   */  sock->iconn = clientsock->next;  clientsock->next = NULL;  newsock->conn = clientsock;  clientsock->conn = newsock;  clientsock->state = SS_CONNECTED;  newsock->state = SS_CONNECTED;  unix_data_ref(UN_DATA(clientsock));  UN_DATA(newsock)->peerupd	       = UN_DATA(clientsock);  UN_DATA(newsock)->sockaddr_un        = UN_DATA(sock)->sockaddr_un;  UN_DATA(newsock)->sockaddr_len       = UN_DATA(sock)->sockaddr_len;  wake_up_interruptible(clientsock->wait);  return(0);}/* Gets the current name or the name of the connected socket. */static intunix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,		   int *usockaddr_len, int peer){  struct unix_proto_data *upd;  int len;  int er;  dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");  if (peer) {	if (sock->state != SS_CONNECTED) {		dprintf(1, "UNIX: getname: socket not connected\n");		return(-EINVAL);	}	upd = UN_DATA(sock->conn);  } else	upd = UN_DATA(sock);  er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));  if(er)  	return er;  if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);  if (len > upd->sockaddr_len) len = upd->sockaddr_len;  if (len) {	er=verify_area(VERIFY_WRITE, usockaddr, len);	if(er)		return er;	memcpy_tofs(usockaddr, &upd->sockaddr_un, len);  }  put_fs_long(len, usockaddr_len);  return(0);}/* We read from our own buf. */static intunix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock){  struct unix_proto_data *upd;  int todo, avail;  int er;  if ((todo = size) <= 0) return(0);  upd = UN_DATA(sock);  while(!(avail = UN_BUF_AVAIL(upd))) {	if (sock->state != SS_CONNECTED) {		dprintf(1, "UNIX: read: socket not connected\n");		return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);	}	dprintf(1, "UNIX: read: no data available...\n");	if (nonblock) return(-EAGAIN);	interruptible_sleep_on(sock->wait);	if (current->signal & ~current->blocked) {		dprintf(1, "UNIX: read: interrupted\n");		return(-ERESTARTSYS);	}  }  /*   * Copy from the read buffer into the user's buffer,   * watching for wraparound. Then we wake up the writer.   */     unix_lock(upd);  do {	int part, cando;	if (avail <= 0) {		printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");		send_sig(SIGKILL, current, 1);		return(-EPIPE);	}	if ((cando = todo) > avail) cando = avail;	if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;	dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",	       					avail, todo, cando);	if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)	{		unix_unlock(upd);		return er;	}	memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);	upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);	ubuf += cando;	todo -= cando;	if (sock->state == SS_CONNECTED)		wake_up_interruptible(sock->conn->wait);	avail = UN_BUF_AVAIL(upd);  } while(todo && avail);  unix_unlock(upd);  return(size - todo);}/* * We write to our peer's buf. When we connected we ref'd this * peer so we are safe that the buffer remains, even after the * peer has disconnected, which we check other ways. */static intunix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock){  struct unix_proto_data *pupd;  int todo, space;  int er;  if ((todo = size) <= 0) return(0);  if (sock->state != SS_CONNECTED) {	dprintf(1, "UNIX: write: socket not connected\n");	if (sock->state == SS_DISCONNECTING) {		send_sig(SIGPIPE, current, 1);		return(-EPIPE);	}	return(-EINVAL);  }  pupd = UN_DATA(sock)->peerupd;	/* safer than sock->conn */  while(!(space = UN_BUF_SPACE(pupd))) {	dprintf(1, "UNIX: write: no space left...\n");	if (nonblock) return(-EAGAIN);	interruptible_sleep_on(sock->wait);	if (current->signal & ~current->blocked) {		dprintf(1, "UNIX: write: interrupted\n");		return(-ERESTARTSYS);	}	if (sock->state == SS_DISCONNECTING) {		dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");		send_sig(SIGPIPE, current, 1);		return(-EPIPE);	}  }  /*   * Copy from the user's buffer to the write buffer,   * watching for wraparound. Then we wake up the reader.   */     unix_lock(pupd);    do {	int part, cando;	if (space <= 0) {		printk("UNIX: write: SPACE IS NEGATIVE!!!\n");		send_sig(SIGKILL, current, 1);		return(-EPIPE);	}	/*	 * We may become disconnected inside this loop, so watch	 * for it (peerupd is safe until we close).	 */	if (sock->state == SS_DISCONNECTING) {		send_sig(SIGPIPE, current, 1);		unix_unlock(pupd);		return(-EPIPE);	}	if ((cando = todo) > space) cando = space;	if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;	dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",	       					space, todo, cando);	er=verify_area(VERIFY_READ, ubuf, cando);	if(er)	{		unix_unlock(pupd);		return er;	}	memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);	pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);	ubuf += cando;	todo -= cando;	if (sock->state == SS_CONNECTED)		wake_up_interruptible(sock->conn->wait);	space = UN_BUF_SPACE(pupd);  } while(todo && space);  unix_unlock(pupd);  return(size - todo);}static intunix_proto_select(struct socket *sock, int sel_type, select_table * wait){  struct unix_proto_data *upd, *peerupd;  /* Handle server sockets specially. */  if (sock->flags & SO_ACCEPTCON) {	if (sel_type == SEL_IN) {		dprintf(1, "UNIX: select: %sconnections pending\n",		       				sock->iconn ? "" : "no ");		if (sock->iconn) return(1);		select_wait(sock->wait, wait);		return(sock->iconn ? 1 : 0);	}	dprintf(1, "UNIX: select: nothing else for server socket\n");	select_wait(sock->wait, wait);	return(0);  }  if (sel_type == SEL_IN) {	upd = UN_DATA(sock);	dprintf(1, "UNIX: select: there is%s data available\n",	       					UN_BUF_AVAIL(upd) ? "" : " no");	if (UN_BUF_AVAIL(upd))	/* even if disconnected */			return(1);	else if (sock->state != SS_CONNECTED) {		dprintf(1, "UNIX: select: socket not connected(read EOF)\n");		return(1);	}	select_wait(sock->wait,wait);	return(0);  }  if (sel_type == SEL_OUT) {	if (sock->state != SS_CONNECTED) {		dprintf(1, "UNIX: select: socket not connected(write EOF)\n");		return(1);	}	peerupd = UN_DATA(sock->conn);	dprintf(1, "UNIX: select: there is%s space available\n",	       				UN_BUF_SPACE(peerupd) ? "" : " no");	if (UN_BUF_SPACE(peerupd) > 0) return(1);	select_wait(sock->wait,wait);	return(0);  }  /* SEL_EX */  dprintf(1, "UNIX: select: there are no exceptions here?!\n");  return(0);}static intunix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){  struct unix_proto_data *upd, *peerupd;  int er;  upd = UN_DATA(sock);  peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;  switch(cmd) {	case TIOCINQ:		if (sock->flags & SO_ACCEPTCON) return(-EINVAL);		er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));		if(er)			return er;		if (UN_BUF_AVAIL(upd) || peerupd)			put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);		  else			put_fs_long(0,(unsigned long *)arg);		break;	case TIOCOUTQ:		if (sock->flags & SO_ACCEPTCON) return(-EINVAL);		er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));		if(er)			return er;		if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),				   		(unsigned long *)arg);		  else			put_fs_long(0,(unsigned long *)arg);		break;	default:		return(-EINVAL);  }  return(0);}static intunix_open(struct inode * inode, struct file * file){  int minor;  dprintf(1, "UNIX: open\n");  minor = MINOR(inode->i_rdev);  if (minor != 0) return(-ENODEV);  return(0);}static voidunix_close(struct inode * inode, struct file * file){  dprintf(1, "UNIX: close\n");}static intunix_ioctl(struct inode *inode, struct file *file,	 unsigned int cmd, unsigned long arg){  int minor, ret;  int er;  dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);  minor = MINOR(inode->i_rdev);  if (minor != 0) return(-ENODEV);  ret = -EINVAL;  switch(cmd) {	case DDIOCSDBG:		er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));		if(er)			return er;		unix_debug = get_fs_long((int *)arg);		if (unix_debug != 0 && unix_debug != 1) {			unix_debug = 0;			return(-EINVAL);		}		return(0);	case SIOCSIFLINK:		printk("UNIX: cannot link streams!\n");		break;	default:		break;  }  return(ret);}static struct file_operations unix_fops = {  NULL,		/* LSEEK	*/  NULL,		/* READ		*/  NULL,		/* WRITE	*/  NULL,		/* READDIR	*/  NULL,		/* SELECT	*/  unix_ioctl,	/* IOCTL	*/  NULL,		/* MMAP		*/  unix_open,	/* OPEN		*/  unix_close	/* CLOSE	*/};static struct proto_ops unix_proto_ops = {  AF_UNIX,  unix_proto_create,  unix_proto_dup,  unix_proto_release,  unix_proto_bind,  unix_proto_connect,  unix_proto_socketpair,  unix_proto_accept,  unix_proto_getname,  unix_proto_read,  unix_proto_write,  unix_proto_select,  unix_proto_ioctl,  unix_proto_listen,  unix_proto_send,  unix_proto_recv,  unix_proto_sendto,  unix_proto_recvfrom,  unix_proto_shutdown,  unix_proto_setsockopt,  unix_proto_getsockopt,  NULL				/* unix_proto_fcntl	*/};voidunix_proto_init(struct ddi_proto *pro){  struct unix_proto_data *upd;  dprintf(1, "%s: init: initializing...\n", pro->name);  if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) {	printk("%s: cannot register major device %d!\n",						pro->name, AF_UNIX_MAJOR);	return;  }  /* Tell SOCKET that we are alive... */  (void) sock_register(unix_proto_ops.family, &unix_proto_ops);  for(upd = unix_datas; upd <= last_unix_data; ++upd) {	upd->refcnt = 0;  }}

⌨️ 快捷键说明

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