diff options
author | alfred <alfred@FreeBSD.org> | 2000-06-20 01:09:23 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2000-06-20 01:09:23 +0000 |
commit | e3e72a583b17917255252eaad0aded3476d3652b (patch) | |
tree | ceab351ca57bd3ea52e7e08e2deff3f7092f493f /sys/kern/uipc_socket.c | |
parent | 3cb8680a56e346f425143b8ca251f6d6161f13d4 (diff) | |
download | FreeBSD-src-e3e72a583b17917255252eaad0aded3476d3652b.zip FreeBSD-src-e3e72a583b17917255252eaad0aded3476d3652b.tar.gz |
return of the accept filter part II
accept filters are now loadable as well as able to be compiled into
the kernel.
two accept filters are provided, one that returns sockets when data
arrives the other when an http request is completed (doesn't work
with 0.9 requests)
Reviewed by: jmg
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r-- | sys/kern/uipc_socket.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index b172d46..c2d0ad7 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -58,6 +58,8 @@ #include <machine/limits.h> +static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); + static int filt_sorattach(struct knote *kn); static void filt_sordetach(struct knote *kn); static int filt_soread(struct knote *kn, long hint); @@ -193,6 +195,15 @@ sodealloc(so) if (so->so_snd.sb_hiwat) (void)chgsbsize(so->so_cred->cr_uid, -(rlim_t)so->so_snd.sb_hiwat); + if (so->so_accf != NULL) { + if (so->so_accf->so_accept_filter != NULL && + so->so_accf->so_accept_filter->accf_destroy != NULL) { + so->so_accf->so_accept_filter->accf_destroy(so); + } + if (so->so_accf->so_accept_filter_str != NULL) + FREE(so->so_accf->so_accept_filter_str, M_ACCF); + FREE(so->so_accf, M_ACCF); + } crfree(so->so_cred); zfreei(so->so_zone, so); } @@ -977,6 +988,77 @@ sorflush(so) sbrelease(&asb, so); } +static int +do_setopt_accept_filter(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + struct accept_filter_arg *afap = NULL; + struct accept_filter *afp; + struct so_accf *af = so->so_accf; + int error = 0; + + /* removing the filter */ + if (sopt == NULL) { + if (af != NULL) { + if (af->so_accept_filter != NULL && + af->so_accept_filter->accf_destroy != NULL) { + af->so_accept_filter->accf_destroy(so); + } + if (af->so_accept_filter_str != NULL) { + FREE(af->so_accept_filter_str, M_ACCF); + } + FREE(af, M_ACCF); + so->so_accf = NULL; + } + so->so_options &= ~SO_ACCEPTFILTER; + return (0); + } + /* adding a filter */ + /* must remove previous filter first */ + if (af != NULL) { + error = EINVAL; + goto out; + } + /* don't put large objects on the kernel stack */ + MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK); + error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); + afap->af_name[sizeof(afap->af_name)-1] = '\0'; + afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; + if (error) + goto out; + afp = accept_filt_get(afap->af_name); + if (afp == NULL) { + error = ENOENT; + goto out; + } + MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK); + bzero(af, sizeof(*af)); + if (afp->accf_create != NULL) { + if (afap->af_name[0] != '\0') { + int len = strlen(afap->af_name) + 1; + + MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK); + strcpy(af->so_accept_filter_str, afap->af_name); + } + af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg); + if (af->so_accept_filter_arg == NULL) { + FREE(af->so_accept_filter_str, M_ACCF); + FREE(af, M_ACCF); + so->so_accf = NULL; + error = EINVAL; + goto out; + } + } + af->so_accept_filter = afp; + so->so_accf = af; + so->so_options |= SO_ACCEPTFILTER; +out: + if (afap != NULL) + FREE(afap, M_TEMP); + return (error); +} + /* * Perhaps this routine, and sooptcopyout(), below, ought to come in * an additional variant to handle the case where the option value needs @@ -1137,6 +1219,11 @@ sosetopt(so, sopt) } break; + case SO_ACCEPTFILTER: + error = do_setopt_accept_filter(so, sopt); + if (error) + goto bad; + break; default: error = ENOPROTOOPT; break; @@ -1190,6 +1277,7 @@ sogetopt(so, sopt) int error, optval; struct linger l; struct timeval tv; + struct accept_filter_arg *afap; error = 0; if (sopt->sopt_level != SOL_SOCKET) { @@ -1200,6 +1288,19 @@ sogetopt(so, sopt) return (ENOPROTOOPT); } else { switch (sopt->sopt_name) { + case SO_ACCEPTFILTER: + MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), + M_TEMP, M_WAITOK); + bzero(afap, sizeof(*afap)); + if ((so->so_options & SO_ACCEPTFILTER) != 0) { + strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name); + if (so->so_accf->so_accept_filter_str != NULL) + strcpy(afap->af_arg, so->so_accf->so_accept_filter_str); + } + error = sooptcopyout(sopt, afap, sizeof(*afap)); + FREE(afap, M_TEMP); + break; + case SO_LINGER: l.l_onoff = so->so_options & SO_LINGER; l.l_linger = so->so_linger; |