static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct unix_proto_data *upd, *peerupd; upd = UN_DATA(sock); peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL; switch (cmd) { case TIOCINQ: verify_area((void *)arg, sizeof(unsigned long)); if (UN_BUF_AVAIL(upd) || peerupd) put_fs_long(UN_BUF_AVAIL(upd), (unsigned long *)arg); else put_fs_long(1, (unsigned long *)arg); /* read EOF */ break; case TIOCOUTQ: verify_area((void *)arg, sizeof(unsigned long)); 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 int unix_proto_select(struct socket *sock, int which) { struct unix_proto_data *upd, *peerupd; if (which == SEL_IN) { upd = UN_DATA(sock); PRINTK("unix_proto_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) { PRINTK("unix_proto_select: socket not connected (read EOF)\n"); return 1; } else return 0; } if (which == SEL_OUT) { if (sock->state != SS_CONNECTED) { PRINTK("unix_proto_select: socket not connected (write EOF)\n"); return 1; } peerupd = UN_DATA(sock->conn); PRINTK("unix_proto_select: there is%s space available\n", UN_BUF_SPACE(peerupd) ? "" : " no"); return (UN_BUF_SPACE(peerupd) > 0); } /* SEL_EX */ PRINTK("unix_proto_select: there are no exceptions here?!\n"); return 0; }
/* * we read from our own buf. */ static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *upd; int todo, avail; if ((todo = size) <= 0) return 0; upd = UN_DATA(sock); while (!(avail = UN_BUF_AVAIL(upd))) { if (sock->state != SS_CONNECTED) { PRINTK("unix_proto_read: socket not connected\n"); return (sock->state == SS_DISCONNECTING) ? 0 : -EINVAL; } PRINTK("unix_proto_read: no data available...\n"); if (nonblock) return -EAGAIN; interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { PRINTK("unix_proto_read: interrupted\n"); return -ERESTARTSYS; } if (sock->state == SS_DISCONNECTING) { PRINTK("unix_proto_read: disconnected\n"); return 0; } } /* * copy from the read buffer into the user's buffer, watching for * wraparound. then we wake up the writer */ do { int part, cando; if (avail <= 0) { PRINTK("unix_proto_read: AVAIL IS NEGATIVE!!!\n"); send_sig(SIGKILL,current,1); return -EINTR; } if ((cando = todo) > avail) cando = avail; if (cando > (part = BUF_SIZE - upd->bp_tail)) cando = part; PRINTK("unix_proto_read: avail=%d, todo=%d, cando=%d\n", avail, todo, cando); verify_area(ubuf, cando); 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(sock->conn->wait); avail = UN_BUF_AVAIL(upd); } while (todo && avail); return size - todo; }
static int unix_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) { PRINTK("sock_select: %sconnections pending\n", sock->iconn ? "" : "no "); if (sock->iconn) return 1; select_wait(sock->wait, wait); return sock->iconn ? 1 : 0; } PRINTK("sock_select: nothing else for server socket\n"); select_wait(sock->wait, wait); return 0; } if (sel_type == SEL_IN) { upd = UN_DATA(sock); PRINTK("unix_proto_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) { PRINTK("unix_proto_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) { PRINTK("unix_proto_select: socket not connected (write EOF)\n"); return 1; } peerupd = UN_DATA(sock->conn); PRINTK("unix_proto_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 */ PRINTK("unix_proto_select: there are no exceptions here?!\n"); return 0; }
static int unix_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) { if (sock->iconn) return 1; select_wait(sock->wait, wait); return (sock->iconn ? 1 : 0); } select_wait(sock->wait, wait); return 0; } if (sel_type == SEL_IN) { upd = UN_DATA(sock); if (UN_BUF_AVAIL(upd)) /* even if disconnected */ return 1; else if (sock->state != SS_CONNECTED) return 1; select_wait(sock->wait, wait); return 0; } if (sel_type == SEL_OUT) { if (sock->state != SS_CONNECTED) return 1; peerupd = UN_DATA(sock->conn); if (UN_BUF_SPACE(peerupd) > 0) return 1; select_wait(sock->wait, wait); return 0; } /* * Exceptions - SEL_EX */ return 0; }
static int unix_read(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *upd; int todo, avail; if ((todo = size) <= 0) return 0; upd = UN_DATA(sock); while (!(avail = UN_BUF_AVAIL(upd))) { if (sock->state != SS_CONNECTED) return ((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); if (nonblock) return -EAGAIN; sock->flags |= SO_WAITDATA; interruptible_sleep_on(sock->wait); sock->flags &= ~SO_WAITDATA; if (current->signal /* & ~current->blocked */ ) return -ERESTARTSYS; } /* * Copy from the read buffer into the user's buffer, * watching for wraparound. Then we wake up the writer. */ down(&upd->sem); do { int part, cando; if (avail <= 0) { printk("UNIX: read: AVAIL IS NEGATIVE (%d)!!!\n", avail); send_sig(SIGKILL, current, 1); return -EPIPE; } if ((cando = todo) > avail) cando = avail; if (cando > (part = UN_BUF_SIZE - upd->bp_tail)) cando = part; memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); upd->bp_tail = (upd->bp_tail + cando) & (UN_BUF_SIZE - 1); ubuf += cando; todo -= cando; if (sock->state == SS_CONNECTED) { wake_up_interruptible(sock->conn->wait); #if 0 sock_wake_async(sock->conn, 2); #endif } avail = UN_BUF_AVAIL(upd); } while (todo && avail); up(&upd->sem); return (size - todo); }