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