📄 socket.c
字号:
msg.msg_name=NULL; msg.msg_namelen=0; msg.msg_iov=&iov; msg.msg_iovlen=1; msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_flags=!(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; if (sock->type == SOCK_SEQPACKET) msg.msg_flags |= MSG_EOR; iov.iov_base=(void *)ubuf; iov.iov_len=size; return sock_sendmsg(sock, &msg, size);}ssize_t sock_sendpage(struct file *file, struct page *page, int offset, size_t size, loff_t *ppos, int more){ struct socket *sock; int flags; if (ppos != &file->f_pos) return -ESPIPE; sock = socki_lookup(file->f_dentry->d_inode); flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; if (more) flags |= MSG_MORE; return sock->ops->sendpage(sock, page, offset, size, flags);}int sock_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * iov, long count, long size){ struct msghdr msg; struct socket *sock; sock = socki_lookup(inode); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_iov = (struct iovec *) iov; msg.msg_iovlen = count; msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; /* read() does a VERIFY_WRITE */ if (type == VERIFY_WRITE) return sock_recvmsg(sock, &msg, size, msg.msg_flags); if (sock->type == SOCK_SEQPACKET) msg.msg_flags |= MSG_EOR; return sock_sendmsg(sock, &msg, size);}static ssize_t sock_readv(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos){ size_t tot_len = 0; int i; for (i = 0 ; i < count ; i++) tot_len += vector[i].iov_len; return sock_readv_writev(VERIFY_WRITE, file->f_dentry->d_inode, file, vector, count, tot_len);} static ssize_t sock_writev(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos){ size_t tot_len = 0; int i; for (i = 0 ; i < count ; i++) tot_len += vector[i].iov_len; return sock_readv_writev(VERIFY_READ, file->f_dentry->d_inode, file, vector, count, tot_len);}/* * With an ioctl arg may well be a user mode pointer, but we don't know what to do * with it - that's up to the protocol still. */int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct socket *sock; int err; unlock_kernel(); sock = socki_lookup(inode); err = sock->ops->ioctl(sock, cmd, arg); lock_kernel(); return err;}/* No kernel lock held - perfect */static unsigned int sock_poll(struct file *file, poll_table * wait){ struct socket *sock; /* * We can't return errors to poll, so it's either yes or no. */ sock = socki_lookup(file->f_dentry->d_inode); return sock->ops->poll(file, sock, wait);}static int sock_mmap(struct file * file, struct vm_area_struct * vma){ struct socket *sock = socki_lookup(file->f_dentry->d_inode); return sock->ops->mmap(file, sock, vma);}int sock_close(struct inode *inode, struct file *filp){ /* * It was possible the inode is NULL we were * closing an unfinished socket. */ if (!inode) { printk(KERN_DEBUG "sock_close: NULL inode\n"); return 0; } sock_fasync(-1, filp, 0); sock_release(socki_lookup(inode)); return 0;}/* * Update the socket async list * * Fasync_list locking strategy. * * 1. fasync_list is modified only under process context socket lock * i.e. under semaphore. * 2. fasync_list is used under read_lock(&sk->callback_lock) * or under socket lock. * 3. fasync_list can be used from softirq context, so that * modification under socket lock have to be enhanced with * write_lock_bh(&sk->callback_lock). * --ANK (990710) */static int sock_fasync(int fd, struct file *filp, int on){ struct fasync_struct *fa, *fna=NULL, **prev; struct socket *sock; struct sock *sk; if (on) { fna=(struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); if(fna==NULL) return -ENOMEM; } sock = socki_lookup(filp->f_dentry->d_inode); if ((sk=sock->sk) == NULL) return -EINVAL; lock_sock(sk); prev=&(sock->fasync_list); for (fa=*prev; fa!=NULL; prev=&fa->fa_next,fa=*prev) if (fa->fa_file==filp) break; if(on) { if(fa!=NULL) { write_lock_bh(&sk->callback_lock); fa->fa_fd=fd; write_unlock_bh(&sk->callback_lock); kfree(fna); goto out; } fna->fa_file=filp; fna->fa_fd=fd; fna->magic=FASYNC_MAGIC; fna->fa_next=sock->fasync_list; write_lock_bh(&sk->callback_lock); sock->fasync_list=fna; write_unlock_bh(&sk->callback_lock); } else { if (fa!=NULL) { write_lock_bh(&sk->callback_lock); *prev=fa->fa_next; write_unlock_bh(&sk->callback_lock); kfree(fa); } }out: release_sock(sock->sk); return 0;}/* This function may be called only under socket lock or callback_lock */int sock_wake_async(struct socket *sock, int how, int band){ if (!sock || !sock->fasync_list) return -1; switch (how) { case 1: if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) break; goto call_kill; case 2: if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) break; /* fall through */ case 0: call_kill: __kill_fasync(sock->fasync_list, SIGIO, band); break; case 3: __kill_fasync(sock->fasync_list, SIGURG, band); } return 0;}int sock_create(int family, int type, int protocol, struct socket **res){ int i; struct socket *sock; /* * Check protocol is in range */ if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; if (type < 0 || type >= SOCK_MAX) return -EINVAL; /* Compatibility. This uglymoron is moved from INET layer to here to avoid deadlock in module load. */ if (family == PF_INET && type == SOCK_PACKET) { static int warned; if (!warned) { warned = 1; printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); } family = PF_PACKET; } #if defined(CONFIG_KMOD) && defined(CONFIG_NET) /* Attempt to load a protocol module if the find failed. * * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user * requested real, full-featured networking support upon configuration. * Otherwise module support will break! */ if (net_families[family]==NULL) { char module_name[30]; sprintf(module_name,"net-pf-%d",family); request_module(module_name); }#endif net_family_read_lock(); if (net_families[family] == NULL) { i = -EAFNOSUPPORT; goto out; }/* * 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())) { printk(KERN_WARNING "socket: no more sockets\n"); i = -ENFILE; /* Not exactly a match, but its the closest posix thing */ goto out; } sock->type = type; if ((i = net_families[family]->create(sock, protocol)) < 0) { sock_release(sock); goto out; } *res = sock;out: net_family_read_unlock(); return i;}asmlinkage long sys_socket(int family, int type, int protocol){ int retval; struct socket *sock; retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out; retval = sock_map_fd(sock); if (retval < 0) goto out_release;out: /* It may be already another descriptor 8) Not kernel problem. */ return retval;out_release: sock_release(sock); return retval;}/* * Create a pair of connected sockets. */asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2]){ struct socket *sock1, *sock2; int fd1, fd2, err; /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. */ err = sock_create(family, type, protocol, &sock1); if (err < 0) goto out; err = sock_create(family, type, protocol, &sock2); if (err < 0) goto out_release_1; err = sock1->ops->socketpair(sock1, sock2); if (err < 0) goto out_release_both; fd1 = fd2 = -1; err = sock_map_fd(sock1); if (err < 0) goto out_release_both; fd1 = err; err = sock_map_fd(sock2); if (err < 0) goto out_close_1; fd2 = err; /* fd1 and fd2 may be already another descriptors. * Not kernel problem. */ err = put_user(fd1, &usockvec[0]); if (!err) err = put_user(fd2, &usockvec[1]); if (!err) return 0; sys_close(fd2); sys_close(fd1); return err;out_close_1: sock_release(sock2); sys_close(fd1); return err;out_release_both: sock_release(sock2);out_release_1: sock_release(sock1);out: return err;}/* * Bind a name to a socket. Nothing much to do here since it's * the protocol's responsibility to handle the local address. * * We move the socket address to kernel space before we call * the protocol layer (having also checked the address is ok). */asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen){ struct socket *sock; char address[MAX_SOCK_ADDR]; int err; if((sock = sockfd_lookup(fd,&err))!=NULL) { if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); sockfd_put(sock); } return err;}/* * 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. */asmlinkage long sys_listen(int fd, int backlog){ struct socket *sock; int err; if ((sock = sockfd_lookup(fd, &err)) != NULL) { if ((unsigned) backlog > SOMAXCONN) backlog = SOMAXCONN; err=sock->ops->listen(sock, backlog); sockfd_put(sock); } return err;}/* * 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. We collect the address of the connector in kernel * space and move it to user at the very end. This is unclean because * we open the socket then return an error. * * 1003.1g adds the ability to recvmsg() to query connection pending * status to recvmsg. We need to add that support in a way thats * clean when we restucture accept also. */asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen){ struct socket *sock, *newsock; int err, len; char address[MAX_SOCK_ADDR]; sock = sockfd_lookup(fd, &err); if (!sock) goto out; err = -EMFILE; if (!(newsock = sock_alloc())) goto out_put; newsock->type = sock->type; newsock->ops = sock->ops; err = sock->ops->accept(sock, newsock, sock->file->f_flags); if (err < 0) goto out_release; if (upeer_sockaddr) { if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { err = -ECONNABORTED; goto out_release; } err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); if (err < 0) goto out_release; } /* File flags are not inherited via accept() unlike another OSes. */ if ((err = sock_map_fd(newsock)) < 0) goto out_release;out_put: sockfd_put(sock);out: return err;out_release: sock_release(newsock); goto out_put;}/* * Attempt to connect to a socket with the server address. The address * is in user space so we verify it is OK and move it to kernel space. * * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to * break bindings * * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and * other SEQPACKET protocols that take time to connect() as it doesn't * include the -EINPROGRESS status for such sockets. */asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen){ struct socket *sock; char address[MAX_SOCK_ADDR]; int err; sock = sockfd_lookup(fd, &err); if (!sock) goto out; err = move_addr_to_kernel(uservaddr, addrlen, address); if (err < 0) goto out_put; err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, sock->file->f_flags);out_put: sockfd_put(sock);out: return err;}/* * Get the local address ('name') of a socket object. Move the obtained * name to user space. */asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len){ struct socket *sock; char address[MAX_SOCK_ADDR]; int len, err; sock = sockfd_lookup(fd, &err); if (!sock) goto out; err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); if (err) goto out_put; err = move_addr_to_user(address, len, usockaddr, usockaddr_len);out_put: sockfd_put(sock);out: return err;}/* * Get the remote address ('name') of a socket object. Move the obtained * name to user space. */asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len){ struct socket *sock; char address[MAX_SOCK_ADDR]; int len, err; if ((sock = sockfd_lookup(fd, &err))!=NULL) { err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); if (!err) err=move_addr_to_user(address,len, usockaddr, usockaddr_len); sockfd_put(sock); } return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -