[ Pobierz całość w formacie PDF ]
.filp=NULL;memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);cli();if(sunaddr==NULL){other=sk->protinfo.af_unix.other;if(sock->type==SOCK_DGRAM && other->dead){other->protinfo.af_unix.locks--;sk->protinfo.af_unix.other=NULL;sock->state=SS_UNCONNECTED;sti();kfree_skb(skb, FREE_WRITE);if(!sent)return -ECONNRESET;elsereturn sent;}}else{unix_mkname(sunaddr, msg->msg_namelen);other=unix_find_other(sunaddr->sun_path, &err);if(other==NULL){sti();kfree_skb(skb, FREE_WRITE);if(sent)return sent;elsereturn err;}}skb_queue_tail(&other->receive_queue, skb);sti();/* if we sent an fd, only do it once */other->data_ready(other,size);sent+=size;}return sent;}/** Sleep until data has arrive.But check for races.*/static void unix_data_wait(unix_socket * sk){cli();if (!skb_peek(&sk->receive_queue)) {sk->socket->flags |= SO_WAITDATA;interruptible_sleep_on(sk->sleep);sk->socket->flags &= ~SO_WAITDATA;}sti();}static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len){unix_socket *sk=sock->data;struct sockaddr_un *sunaddr=msg->msg_name;struct sk_buff *skb;int copied=0;unsigned char *sp;int len;int num;struct iovec *iov=msg->msg_iov;struct cmsghdr *cm=NULL;int ct=msg->msg_iovlen;if(flags&MSG_OOB)return -EOPNOTSUPP;if(addr_len)*addr_len=0;if(sk->err)return sock_error(sk);if(msg->msg_control){cm=unix_copyrights(msg->msg_control,msg->msg_controllen);if(msg->msg_controllen<sizeof(struct cmsghdr)#if 0/* investigate this further -- Stevens example doesn't seem to care */||cm->cmsg_type!=SCM_RIGHTS ||cm->cmsg_level!=SOL_SOCKET ||msg->msg_controllen!=cm->cmsg_len#endif){kfree(cm);/* printk("recvmsg: Bad msg_control\n");*/return -EINVAL;}}down(&sk->protinfo.af_unix.readsem); /* Lock the socket */while(ct--){int done=0;sp=iov->iov_base;len=iov->iov_len;iov++;while(done<len){if (copied && (flags & MSG_PEEK))goto out;if (copied == size)goto out;skb=skb_dequeue(&sk->receive_queue);if(skb==NULL){up(&sk->protinfo.af_unix.readsem);if(sk->shutdown & RCV_SHUTDOWN)return copied;if(copied)return copied;if(noblock)return -EAGAIN;if(current->signal & ~current->blocked)return -ERESTARTSYS;unix_data_wait(sk);down(&sk->protinfo.af_unix.readsem);continue;}if(msg->msg_name!=NULL){sunaddr->sun_family=AF_UNIX;if(skb->sk->protinfo.af_unix.name){memcpy(sunaddr->sun_path, skb->sk->protinfo.af_unix.name, 108);if(addr_len)*addr_len=strlen(sunaddr->sun_path)+sizeof(short);}elseif(addr_len)*addr_len=sizeof(short);}num=min(skb->len,len-done);memcpy_tofs(sp, skb->data, num);if (skb->h.filp!=NULL)unix_detach_fds(skb,cm);copied+=num;done+=num;sp+=num;if (!(flags & MSG_PEEK))skb_pull(skb, num);/* put the skb back if we didn't use it up.*/if (skb->len) {skb_queue_head(&sk->receive_queue, skb);continue;}kfree_skb(skb, FREE_WRITE);if(sock->type==SOCK_DGRAM || cm)goto out;}}out:up(&sk->protinfo.af_unix.readsem);if(cm)unix_returnrights(msg->msg_control,msg->msg_controllen,cm);return copied;}static int unix_shutdown(struct socket *sock, int mode){unix_socket *sk=(unix_socket *)sock->data;unix_socket *other=sk->protinfo.af_unix.other;if(mode&SEND_SHUTDOWN){sk->shutdown|=SEND_SHUTDOWN;sk->state_change(sk);if(other){other->shutdown|=RCV_SHUTDOWN;other->state_change(other);}}other=sk->protinfo.af_unix.other;if(mode&RCV_SHUTDOWN){sk->shutdown|=RCV_SHUTDOWN;sk->state_change(sk);if(other){other->shutdown|=SEND_SHUTDOWN;other->state_change(other);}}return 0;}static int unix_select(struct socket *sock, int sel_type, select_table *wait){return datagram_select(sock->data,sel_type,wait);}static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){unix_socket *sk=sock->data;int err;long amount=0;switch(cmd){case TIOCOUTQ:err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));if(err)return err;amount=sk->sndbuf-sk->wmem_alloc;if(amount<0)amount=0;put_fs_long(amount,(unsigned long *)arg);return 0;case TIOCINQ:{struct sk_buff *skb;if(sk->state==TCP_LISTEN)return -EINVAL;/* These two are safe on a single CPU system as only user tasks fiddle here */if((skb=skb_peek(&sk->receive_queue))!=NULL)amount=skb->len;err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));if(err)return err;put_fs_long(amount,(unsigned long *)arg);return 0;}default:return -EINVAL;}/*NOTREACHED*/return(0);}#ifdef CONFIG_PROC_FSstatic int unix_get_info(char *buffer, char **start, off_t offset, int length, int dummy){off_t pos=0;off_t begin=0;int len=0;unix_socket *s=unix_socket_list;len+= sprintf(buffer,"Num RefCount Protocol Flags Type St ""Inode Path\n");while(s!=NULL){len+=sprintf(buffer+len,"%p: %08X %08X %08lX %04X %02X %5ld",s,s->protinfo.af_unix.locks,0,s->socket->flags,s->socket->type,s->socket->state,s->socket->inode ? s->socket->inode->i_ino : 0);if(s->protinfo.af_unix.name!=NULL)len+=sprintf(buffer+len, " %s\n", s->protinfo.af_unix.name);elsebuffer[len++]='\n';pos=begin+len;if(pos<offset){len=0;begin=pos;}if(pos>offset+length)break;s=s->next;}*start=buffer+(offset-begin);len-=(offset-begin);if(len>length)len=length;return len;}#endifstruct proto_ops unix_proto_ops = {AF_UNIX,unix_create,unix_dup,unix_release,unix_bind,unix_connect,unix_socketpair,unix_accept,unix_getname,unix_select,unix_ioctl,unix_listen,unix_shutdown,unix_setsockopt,unix_getsockopt,unix_fcntl,unix_sendmsg,unix_recvmsg};void unix_proto_init(struct net_proto *pro){printk(KERN_INFO "NET3: Unix domain sockets 0.12 for Linux NET3.035.\n");sock_register(unix_proto_ops.family, &unix_proto_ops);#ifdef CONFIG_PROC_FSproc_net_register(&(struct proc_dir_entry) {PROC_NET_UNIX, 4, "unix",S_IFREG | S_IRUGO, 1, 0, 0,0, &proc_net_inode_operations,unix_get_info});#endif}/** Local variables:* compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c"* End:*/</body>
[ Pobierz całość w formacie PDF ]