diff options
Diffstat (limited to 'sys/kern/uipc_socket.c')
| -rw-r--r-- | sys/kern/uipc_socket.c | 61 |
1 files changed, 34 insertions, 27 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index dda845c8e880..0f04d17a94c5 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -64,21 +64,18 @@ static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); #endif /* INET */ -static int filt_sorattach(struct knote *kn); static void filt_sordetach(struct knote *kn); static int filt_soread(struct knote *kn, long hint); -static int filt_sowattach(struct knote *kn); static void filt_sowdetach(struct knote *kn); static int filt_sowrite(struct knote *kn, long hint); static int filt_solisten(struct knote *kn, long hint); static struct filterops solisten_filtops = - { 1, filt_sorattach, filt_sordetach, filt_solisten }; - -struct filterops so_rwfiltops[] = { - { 1, filt_sorattach, filt_sordetach, filt_soread }, - { 1, filt_sowattach, filt_sowdetach, filt_sowrite }, -}; + { 1, NULL, filt_sordetach, filt_solisten }; +static struct filterops soread_filtops = + { 1, NULL, filt_sordetach, filt_soread }; +static struct filterops sowrite_filtops = + { 1, NULL, filt_sowdetach, filt_sowrite }; struct vm_zone *socket_zone; so_gen_t so_gencnt; /* generation count for sockets */ @@ -1538,16 +1535,32 @@ sopoll(struct socket *so, int events, struct ucred *cred, struct proc *p) return (revents); } -static int -filt_sorattach(struct knote *kn) +int +sokqfilter(struct file *fp, struct knote *kn) { struct socket *so = (struct socket *)kn->kn_fp->f_data; - int s = splnet(); + struct sockbuf *sb; + int s; - if (so->so_options & SO_ACCEPTCONN) - kn->kn_fop = &solisten_filtops; - SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext); - so->so_rcv.sb_flags |= SB_KNOTE; + switch (kn->kn_filter) { + case EVFILT_READ: + if (so->so_options & SO_ACCEPTCONN) + kn->kn_fop = &solisten_filtops; + else + kn->kn_fop = &soread_filtops; + sb = &so->so_rcv; + break; + case EVFILT_WRITE: + kn->kn_fop = &sowrite_filtops; + sb = &so->so_snd; + break; + default: + return (1); + } + + s = splnet(); + SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext); + sb->sb_flags |= SB_KNOTE; splx(s); return (0); } @@ -1573,25 +1586,16 @@ filt_soread(struct knote *kn, long hint) kn->kn_data = so->so_rcv.sb_cc; if (so->so_state & SS_CANTRCVMORE) { kn->kn_flags |= EV_EOF; + kn->kn_fflags = so->so_error; return (1); } if (so->so_error) /* temporary udp error */ return (1); + if (kn->kn_sfflags & NOTE_LOWAT) + return (kn->kn_data >= kn->kn_sdata); return (kn->kn_data >= so->so_rcv.sb_lowat); } -static int -filt_sowattach(struct knote *kn) -{ - struct socket *so = (struct socket *)kn->kn_fp->f_data; - int s = splnet(); - - SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext); - so->so_snd.sb_flags |= SB_KNOTE; - splx(s); - return (0); -} - static void filt_sowdetach(struct knote *kn) { @@ -1613,6 +1617,7 @@ filt_sowrite(struct knote *kn, long hint) kn->kn_data = sbspace(&so->so_snd); if (so->so_state & SS_CANTSENDMORE) { kn->kn_flags |= EV_EOF; + kn->kn_fflags = so->so_error; return (1); } if (so->so_error) /* temporary udp error */ @@ -1620,6 +1625,8 @@ filt_sowrite(struct knote *kn, long hint) if (((so->so_state & SS_ISCONNECTED) == 0) && (so->so_proto->pr_flags & PR_CONNREQUIRED)) return (0); + if (kn->kn_sfflags & NOTE_LOWAT) + return (kn->kn_data >= kn->kn_sdata); return (kn->kn_data >= so->so_snd.sb_lowat); } |
