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; }
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_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_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_write(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *pupd; int todo, space; if ((todo = size) <= 0) return 0; if (sock->state != SS_CONNECTED) { 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))) { sock->flags |= SO_NOSPACE; if (nonblock) return -EAGAIN; sock->flags &= ~SO_NOSPACE; interruptible_sleep_on(sock->wait); if (current->signal /* & ~current->blocked */ ) return -ERESTARTSYS; if (sock->state == SS_DISCONNECTING) { 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. */ down(&pupd->sem); do { int part, cando; if (space <= 0) { printk("UNIX: write: SPACE IS NEGATIVE (%d)!!!\n", space); 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); up(&pupd->sem); return -EPIPE; } if ((cando = todo) > space) cando = space; if (cando > (part = UN_BUF_SIZE - pupd->bp_head)) cando = part; memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); pupd->bp_head = (pupd->bp_head + 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, 1); #endif } space = UN_BUF_SPACE(pupd); } while (todo && space); up(&pupd->sem); 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 int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) { struct unix_proto_data *pupd; int todo, space; if ((todo = size) <= 0) return 0; if (sock->state != SS_CONNECTED) { PRINTK("unix_proto_write: socket not connected\n"); if (sock->state == SS_DISCONNECTING) { send_sig(SIGPIPE,current,1); return -EINTR; } return -EINVAL; } pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ while (!(space = UN_BUF_SPACE(pupd))) { PRINTK("unix_proto_write: no space left...\n"); if (nonblock) return -EAGAIN; interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { PRINTK("unix_proto_write: interrupted\n"); return -ERESTARTSYS; } if (sock->state == SS_DISCONNECTING) { PRINTK("unix_proto_write: disconnected (SIGPIPE)\n"); send_sig(SIGPIPE,current,1); return -EINTR; } } /* * copy from the user's buffer to the write buffer, watching for * wraparound. then we wake up the reader */ do { int part, cando; if (space <= 0) { PRINTK("unix_proto_write: SPACE IS NEGATIVE!!!\n"); send_sig(SIGKILL,current,1); return -EINTR; } /* * 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); return -EINTR; } if ((cando = todo) > space) cando = space; if (cando > (part = BUF_SIZE - pupd->bp_head)) cando = part; PRINTK("unix_proto_write: space=%d, todo=%d, cando=%d\n", space, todo, cando); verify_area(ubuf, cando); 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(sock->conn->wait); space = UN_BUF_SPACE(pupd); } while (todo && space); return size - todo; }