1/*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <sys/queue.h>
20#include <sys/socket.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include "private.h"
25
26static int
27knote_cmp(struct knote *a, struct knote *b)
28{
29    return memcmp(&a->kev.ident, &b->kev.ident, sizeof(a->kev.ident));
30}
31
32RB_GENERATE(knt, knote, kntree_ent, knote_cmp)
33
34struct knote *
35knote_new(void)
36{
37    struct knote *dst;
38
39    if ((dst = calloc(1, sizeof(*dst))) == NULL)
40        return (NULL);
41
42    return (dst);
43}
44
45void
46knote_insert(struct filter *filt, struct knote *kn)
47{
48    RB_INSERT(knt, &filt->kf_knote, kn);
49}
50
51void
52knote_free(struct filter *filt, struct knote *kn)
53{
54    dbg_printf("filter=%s, ident=%u",
55            filter_name(kn->kev.filter), (unsigned int) kn->kev.ident);
56	RB_REMOVE(knt, &filt->kf_knote, kn);
57    if (kn->event_ent.tqe_prev) //XXX-FIXME what if this is the 1st entry??
58        TAILQ_REMOVE(&filt->kf_event, kn, event_ent);
59    filt->kn_delete(filt, kn);
60	free(kn);
61}
62
63void
64knote_free_all(struct filter *filt)
65{
66    struct knote *n1, *n2;
67
68    /* Destroy all pending events */
69    for (n1 = TAILQ_FIRST(&filt->kf_event); n1 != NULL; n1 = n2) {
70        n2 = TAILQ_NEXT(n1, event_ent);
71        free(n1);
72    }
73
74    /* Distroy all knotes */
75    for (n1 = RB_MIN(knt, &filt->kf_knote); n1 != NULL; n1 = n2) {
76        n2 = RB_NEXT(knt, filt->kf_knote, n1);
77        RB_REMOVE(knt, &filt->kf_knote, n1);
78        free(n1);
79    }
80}
81
82/* TODO: rename to knote_lookup_ident */
83struct knote *
84knote_lookup(struct filter *filt, uintptr_t ident)
85{
86    struct knote query;
87    struct knote *ent = NULL;
88
89    query.kev.ident = ident;
90    ent = RB_FIND(knt, &filt->kf_knote, &query);
91
92    /* dbg_printf("id=%d ent=%p", ident, ent); */
93
94    return (ent);
95}
96
97struct knote *
98knote_lookup_data(struct filter *filt, intptr_t data)
99{
100    struct knote *kn;
101
102    RB_FOREACH(kn, knt, &filt->kf_knote) {
103        if (data == kn->kev.data)
104            break;
105    }
106    return (kn);
107}
108
109void
110knote_enqueue(struct filter *filt, struct knote *kn)
111{
112    /* XXX-FIXME: check if the knote is already on the eventlist */
113    TAILQ_INSERT_TAIL(&filt->kf_event, kn, event_ent);
114}
115
116struct knote *
117knote_dequeue(struct filter *filt)
118{
119    struct knote *kn;
120
121    if (TAILQ_EMPTY(&filt->kf_event)) {
122        kn = NULL;
123        dbg_puts("no events are pending");
124    } else {
125        kn = TAILQ_FIRST(&filt->kf_event);
126        TAILQ_REMOVE(&filt->kf_event, kn, event_ent);
127        memset(&kn->event_ent, 0, sizeof(kn->event_ent));
128    }
129
130    return (kn);
131}
132
133int
134knote_events_pending(struct filter *filt)
135{
136    int res;
137
138    res = TAILQ_EMPTY(&filt->kf_event);
139
140    return (res);
141}
142
143/*
144 * Test if a socket is active or passive.
145 */
146int
147knote_get_socket_type(struct knote *kn)
148{
149    socklen_t slen;
150    int i, lsock;
151
152    slen = sizeof(lsock);
153    lsock = 0;
154    i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, &lsock, &slen);
155    if (i < 0) {
156        switch (errno) {
157            case ENOTSOCK:   /* same as lsock = 0 */
158                return (0);
159                break;
160            default:
161                dbg_printf("getsockopt(3) failed: %s", strerror(errno));
162                return (-1);
163        }
164    } else {
165        if (lsock)
166            kn->flags |= KNFL_PASSIVE_SOCKET;
167        return (0);
168    }
169}
170