lldpd-1.0.13/0000755000076400001440000000000014143730656013402 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/0000755000076400001440000000000014143730656015212 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/evport.c0000644000076400001440000002734514111362570016677 0ustar00bernatusers00000000000000/* * Submitted by David Pacheco (dp.spambait@gmail.com) * * Copyright 2006-2007 Niels Provos * Copyright 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 2007 Sun Microsystems. All rights reserved. * Use is subject to license terms. */ /* * evport.c: event backend using Solaris 10 event ports. See port_create(3C). * This implementation is loosely modeled after the one used for select(2) (in * select.c). * * The outstanding events are tracked in a data structure called evport_data. * Each entry in the ed_fds array corresponds to a file descriptor, and contains * pointers to the read and write events that correspond to that fd. (That is, * when the file is readable, the "read" event should handle it, etc.) * * evport_add and evport_del update this data structure. evport_dispatch uses it * to determine where to callback when an event occurs (which it gets from * port_getn). * * Helper functions are used: grow() grows the file descriptor array as * necessary when large fd's come in. reassociate() takes care of maintaining * the proper file-descriptor/event-port associations. * * As in the select(2) implementation, signals are handled by evsignal. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_EVENT_PORTS #include #include #include #include #include #include #include #include #include #include #include #include "event2/thread.h" #include "evthread-internal.h" #include "event-internal.h" #include "log-internal.h" #include "evsignal-internal.h" #include "evmap-internal.h" #define INITIAL_EVENTS_PER_GETN 8 #define MAX_EVENTS_PER_GETN 4096 /* * Per-file-descriptor information about what events we're subscribed to. These * fields are NULL if no event is subscribed to either of them. */ struct fd_info { /* combinations of EV_READ and EV_WRITE */ short fdi_what; /* Index of this fd within ed_pending, plus 1. Zero if this fd is * not in ed_pending. (The +1 is a hack so that memset(0) will set * it to a nil index. */ int pending_idx_plus_1; }; #define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ) #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE) #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi)) #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \ (FDI_HAS_WRITE(fdi) ? POLLOUT : 0) struct evport_data { int ed_port; /* event port for system events */ /* How many elements of ed_pending should we look at? */ int ed_npending; /* How many elements are allocated in ed_pending and pevtlist? */ int ed_maxevents; /* fdi's that we need to reassoc */ int *ed_pending; /* storage space for incoming events. */ port_event_t *ed_pevtlist; }; static void* evport_init(struct event_base *); static int evport_add(struct event_base *, int fd, short old, short events, void *); static int evport_del(struct event_base *, int fd, short old, short events, void *); static int evport_dispatch(struct event_base *, struct timeval *); static void evport_dealloc(struct event_base *); static int grow(struct evport_data *, int min_events); const struct eventop evportops = { "evport", evport_init, evport_add, evport_del, evport_dispatch, evport_dealloc, 1, /* need reinit */ 0, /* features */ sizeof(struct fd_info), /* fdinfo length */ }; /* * Initialize the event port implementation. */ static void* evport_init(struct event_base *base) { struct evport_data *evpd; if (!(evpd = mm_calloc(1, sizeof(struct evport_data)))) return (NULL); if ((evpd->ed_port = port_create()) == -1) { mm_free(evpd); return (NULL); } if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) { close(evpd->ed_port); mm_free(evpd); return NULL; } evpd->ed_npending = 0; evsig_init_(base); return (evpd); } static int grow(struct evport_data *data, int min_events) { int newsize; int *new_pending; port_event_t *new_pevtlist; if (data->ed_maxevents) { newsize = data->ed_maxevents; do { newsize *= 2; } while (newsize < min_events); } else { newsize = min_events; } new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize); if (new_pending == NULL) return -1; data->ed_pending = new_pending; new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize); if (new_pevtlist == NULL) return -1; data->ed_pevtlist = new_pevtlist; data->ed_maxevents = newsize; return 0; } #ifdef CHECK_INVARIANTS /* * Checks some basic properties about the evport_data structure. Because it * checks all file descriptors, this function can be expensive when the maximum * file descriptor ever used is rather large. */ static void check_evportop(struct evport_data *evpd) { EVUTIL_ASSERT(evpd); EVUTIL_ASSERT(evpd->ed_port > 0); } /* * Verifies very basic integrity of a given port_event. */ static void check_event(port_event_t* pevt) { /* * We've only registered for PORT_SOURCE_FD events. The only * other thing we can legitimately receive is PORT_SOURCE_ALERT, * but since we're not using port_alert either, we can assume * PORT_SOURCE_FD. */ EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD); } #else #define check_evportop(epop) #define check_event(pevt) #endif /* CHECK_INVARIANTS */ /* * (Re)associates the given file descriptor with the event port. The OS events * are specified (implicitly) from the fd_info struct. */ static int reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd) { int sysevents = FDI_TO_SYSEVENTS(fdip); if (sysevents != 0) { if (port_associate(epdp->ed_port, PORT_SOURCE_FD, fd, sysevents, fdip) == -1) { event_warn("port_associate"); return (-1); } } check_evportop(epdp); return (0); } /* * Main event loop - polls port_getn for some number of events, and processes * them. */ static int evport_dispatch(struct event_base *base, struct timeval *tv) { int i, res; struct evport_data *epdp = base->evbase; port_event_t *pevtlist = epdp->ed_pevtlist; /* * port_getn will block until it has at least nevents events. It will * also return how many it's given us (which may be more than we asked * for, as long as it's less than our maximum (ed_maxevents)) in * nevents. */ int nevents = 1; /* * We have to convert a struct timeval to a struct timespec * (only difference is nanoseconds vs. microseconds). If no time-based * events are active, we should wait for I/O (and tv == NULL). */ struct timespec ts; struct timespec *ts_p = NULL; if (tv != NULL) { ts.tv_sec = tv->tv_sec; ts.tv_nsec = tv->tv_usec * 1000; ts_p = &ts; } /* * Before doing anything else, we need to reassociate the events we hit * last time which need reassociation. See comment at the end of the * loop below. */ for (i = 0; i < epdp->ed_npending; ++i) { struct fd_info *fdi = NULL; const int fd = epdp->ed_pending[i]; if (fd != -1) { /* We might have cleared out this event; we need * to be sure that it's still set. */ fdi = evmap_io_get_fdinfo_(&base->io, fd); } if (fdi != NULL && FDI_HAS_EVENTS(fdi)) { reassociate(epdp, fdi, fd); /* epdp->ed_pending[i] = -1; */ fdi->pending_idx_plus_1 = 0; } } EVBASE_RELEASE_LOCK(base, th_base_lock); res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents, (unsigned int *) &nevents, ts_p); EVBASE_ACQUIRE_LOCK(base, th_base_lock); if (res == -1) { if (errno == EINTR || errno == EAGAIN) { return (0); } else if (errno == ETIME) { if (nevents == 0) return (0); } else { event_warn("port_getn"); return (-1); } } event_debug(("%s: port_getn reports %d events", __func__, nevents)); for (i = 0; i < nevents; ++i) { port_event_t *pevt = &pevtlist[i]; int fd = (int) pevt->portev_object; struct fd_info *fdi = pevt->portev_user; /*EVUTIL_ASSERT(evmap_io_get_fdinfo_(&base->io, fd) == fdi);*/ check_evportop(epdp); check_event(pevt); epdp->ed_pending[i] = fd; fdi->pending_idx_plus_1 = i + 1; /* * Figure out what kind of event it was * (because we have to pass this to the callback) */ res = 0; if (pevt->portev_events & (POLLERR|POLLHUP)) { res = EV_READ | EV_WRITE; } else { if (pevt->portev_events & POLLIN) res |= EV_READ; if (pevt->portev_events & POLLOUT) res |= EV_WRITE; } /* * Check for the error situations or a hangup situation */ if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL)) res |= EV_READ|EV_WRITE; evmap_io_active_(base, fd, res); } /* end of all events gotten */ epdp->ed_npending = nevents; if (nevents == epdp->ed_maxevents && epdp->ed_maxevents < MAX_EVENTS_PER_GETN) { /* we used all the space this time. We should be ready * for more events next time around. */ grow(epdp, epdp->ed_maxevents * 2); } check_evportop(epdp); return (0); } /* * Adds the given event (so that you will be notified when it happens via * the callback function). */ static int evport_add(struct event_base *base, int fd, short old, short events, void *p) { struct evport_data *evpd = base->evbase; struct fd_info *fdi = p; check_evportop(evpd); fdi->fdi_what |= events; return reassociate(evpd, fdi, fd); } /* * Removes the given event from the list of events to wait for. */ static int evport_del(struct event_base *base, int fd, short old, short events, void *p) { struct evport_data *evpd = base->evbase; struct fd_info *fdi = p; int associated = ! fdi->pending_idx_plus_1; check_evportop(evpd); fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE)); if (associated) { if (!FDI_HAS_EVENTS(fdi) && port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) { /* * Ignore EBADFD error the fd could have been closed * before event_del() was called. */ if (errno != EBADFD) { event_warn("port_dissociate"); return (-1); } } else { if (FDI_HAS_EVENTS(fdi)) { return (reassociate(evpd, fdi, fd)); } } } else { if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) { const int i = fdi->pending_idx_plus_1 - 1; EVUTIL_ASSERT(evpd->ed_pending[i] == fd); evpd->ed_pending[i] = -1; fdi->pending_idx_plus_1 = 0; } } return 0; } static void evport_dealloc(struct event_base *base) { struct evport_data *evpd = base->evbase; evsig_dealloc_(base); close(evpd->ed_port); if (evpd->ed_pending) mm_free(evpd->ed_pending); if (evpd->ed_pevtlist) mm_free(evpd->ed_pevtlist); mm_free(evpd); } #endif /* EVENT__HAVE_EVENT_PORTS */ lldpd-1.0.13/libevent/bufferevent_async.c0000644000076400001440000004436314111362570021067 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #ifdef EVENT__HAVE_STDARG_H #include #endif #ifdef EVENT__HAVE_UNISTD_H #include #endif #ifdef _WIN32 #include #include #include #endif #include #include "event2/util.h" #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/bufferevent_struct.h" #include "event2/event.h" #include "event2/util.h" #include "event-internal.h" #include "log-internal.h" #include "mm-internal.h" #include "bufferevent-internal.h" #include "util-internal.h" #include "iocp-internal.h" #ifndef SO_UPDATE_CONNECT_CONTEXT /* Mingw is sometimes missing this */ #define SO_UPDATE_CONNECT_CONTEXT 0x7010 #endif /* prototypes */ static int be_async_enable(struct bufferevent *, short); static int be_async_disable(struct bufferevent *, short); static void be_async_destruct(struct bufferevent *); static int be_async_flush(struct bufferevent *, short, enum bufferevent_flush_mode); static int be_async_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); struct bufferevent_async { struct bufferevent_private bev; struct event_overlapped connect_overlapped; struct event_overlapped read_overlapped; struct event_overlapped write_overlapped; size_t read_in_progress; size_t write_in_progress; unsigned ok : 1; unsigned read_added : 1; unsigned write_added : 1; }; const struct bufferevent_ops bufferevent_ops_async = { "socket_async", evutil_offsetof(struct bufferevent_async, bev.bev), be_async_enable, be_async_disable, NULL, /* Unlink */ be_async_destruct, bufferevent_generic_adj_timeouts_, be_async_flush, be_async_ctrl, }; static inline void be_async_run_eventcb(struct bufferevent *bev, short what, int options) { bufferevent_run_eventcb_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); } static inline void be_async_trigger_nolock(struct bufferevent *bev, short what, int options) { bufferevent_trigger_nolock_(bev, what, options|BEV_TRIG_DEFER_CALLBACKS); } static inline int fatal_error(int err) { switch (err) { /* We may have already associated this fd with a port. * Let's hope it's this port, and that the error code * for doing this neer changes. */ case ERROR_INVALID_PARAMETER: return 0; } return 1; } static inline struct bufferevent_async * upcast(struct bufferevent *bev) { struct bufferevent_async *bev_a; if (!BEV_IS_ASYNC(bev)) return NULL; bev_a = EVUTIL_UPCAST(bev, struct bufferevent_async, bev.bev); return bev_a; } static inline struct bufferevent_async * upcast_connect(struct event_overlapped *eo) { struct bufferevent_async *bev_a; bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, connect_overlapped); EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev)); return bev_a; } static inline struct bufferevent_async * upcast_read(struct event_overlapped *eo) { struct bufferevent_async *bev_a; bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, read_overlapped); EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev)); return bev_a; } static inline struct bufferevent_async * upcast_write(struct event_overlapped *eo) { struct bufferevent_async *bev_a; bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, write_overlapped); EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev)); return bev_a; } static void bev_async_del_write(struct bufferevent_async *beva) { struct bufferevent *bev = &beva->bev.bev; if (beva->write_added) { beva->write_added = 0; event_base_del_virtual_(bev->ev_base); } } static void bev_async_del_read(struct bufferevent_async *beva) { struct bufferevent *bev = &beva->bev.bev; if (beva->read_added) { beva->read_added = 0; event_base_del_virtual_(bev->ev_base); } } static void bev_async_add_write(struct bufferevent_async *beva) { struct bufferevent *bev = &beva->bev.bev; if (!beva->write_added) { beva->write_added = 1; event_base_add_virtual_(bev->ev_base); } } static void bev_async_add_read(struct bufferevent_async *beva) { struct bufferevent *bev = &beva->bev.bev; if (!beva->read_added) { beva->read_added = 1; event_base_add_virtual_(bev->ev_base); } } static void bev_async_consider_writing(struct bufferevent_async *beva) { size_t at_most; int limit; struct bufferevent *bev = &beva->bev.bev; /* Don't write if there's a write in progress, or we do not * want to write, or when there's nothing left to write. */ if (beva->write_in_progress || beva->bev.connecting) return; if (!beva->ok || !(bev->enabled&EV_WRITE) || !evbuffer_get_length(bev->output)) { bev_async_del_write(beva); return; } at_most = evbuffer_get_length(bev->output); /* This is safe so long as bufferevent_get_write_max never returns * more than INT_MAX. That's true for now. XXXX */ limit = (int)bufferevent_get_write_max_(&beva->bev); if (at_most >= (size_t)limit && limit >= 0) at_most = limit; if (beva->bev.write_suspended) { bev_async_del_write(beva); return; } /* XXXX doesn't respect low-water mark very well. */ bufferevent_incref_(bev); if (evbuffer_launch_write_(bev->output, at_most, &beva->write_overlapped)) { bufferevent_decref_(bev); beva->ok = 0; be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0); } else { beva->write_in_progress = at_most; bufferevent_decrement_write_buckets_(&beva->bev, at_most); bev_async_add_write(beva); } } static void bev_async_consider_reading(struct bufferevent_async *beva) { size_t cur_size; size_t read_high; size_t at_most; int limit; struct bufferevent *bev = &beva->bev.bev; /* Don't read if there is a read in progress, or we do not * want to read. */ if (beva->read_in_progress || beva->bev.connecting) return; if (!beva->ok || !(bev->enabled&EV_READ)) { bev_async_del_read(beva); return; } /* Don't read if we're full */ cur_size = evbuffer_get_length(bev->input); read_high = bev->wm_read.high; if (read_high) { if (cur_size >= read_high) { bev_async_del_read(beva); return; } at_most = read_high - cur_size; } else { at_most = 16384; /* FIXME totally magic. */ } /* XXXX This over-commits. */ /* XXXX see also not above on cast on bufferevent_get_write_max_() */ limit = (int)bufferevent_get_read_max_(&beva->bev); if (at_most >= (size_t)limit && limit >= 0) at_most = limit; if (beva->bev.read_suspended) { bev_async_del_read(beva); return; } bufferevent_incref_(bev); if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) { beva->ok = 0; be_async_run_eventcb(bev, BEV_EVENT_ERROR, 0); bufferevent_decref_(bev); } else { beva->read_in_progress = at_most; bufferevent_decrement_read_buckets_(&beva->bev, at_most); bev_async_add_read(beva); } return; } static void be_async_outbuf_callback(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent *bev = arg; struct bufferevent_async *bev_async = upcast(bev); /* If we added data to the outbuf and were not writing before, * we may want to write now. */ bufferevent_incref_and_lock_(bev); if (cbinfo->n_added) bev_async_consider_writing(bev_async); bufferevent_decref_and_unlock_(bev); } static void be_async_inbuf_callback(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent *bev = arg; struct bufferevent_async *bev_async = upcast(bev); /* If we drained data from the inbuf and were not reading before, * we may want to read now */ bufferevent_incref_and_lock_(bev); if (cbinfo->n_deleted) bev_async_consider_reading(bev_async); bufferevent_decref_and_unlock_(bev); } static int be_async_enable(struct bufferevent *buf, short what) { struct bufferevent_async *bev_async = upcast(buf); if (!bev_async->ok) return -1; if (bev_async->bev.connecting) { /* Don't launch anything during connection attempts. */ return 0; } if (what & EV_READ) BEV_RESET_GENERIC_READ_TIMEOUT(buf); if (what & EV_WRITE) BEV_RESET_GENERIC_WRITE_TIMEOUT(buf); /* If we newly enable reading or writing, and we aren't reading or writing already, consider launching a new read or write. */ if (what & EV_READ) bev_async_consider_reading(bev_async); if (what & EV_WRITE) bev_async_consider_writing(bev_async); return 0; } static int be_async_disable(struct bufferevent *bev, short what) { struct bufferevent_async *bev_async = upcast(bev); /* XXXX If we disable reading or writing, we may want to consider * canceling any in-progress read or write operation, though it might * not work. */ if (what & EV_READ) { BEV_DEL_GENERIC_READ_TIMEOUT(bev); bev_async_del_read(bev_async); } if (what & EV_WRITE) { BEV_DEL_GENERIC_WRITE_TIMEOUT(bev); bev_async_del_write(bev_async); } return 0; } static void be_async_destruct(struct bufferevent *bev) { struct bufferevent_async *bev_async = upcast(bev); struct bufferevent_private *bev_p = BEV_UPCAST(bev); evutil_socket_t fd; EVUTIL_ASSERT(!upcast(bev)->write_in_progress && !upcast(bev)->read_in_progress); bev_async_del_read(bev_async); bev_async_del_write(bev_async); fd = evbuffer_overlapped_get_fd_(bev->input); if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET && (bev_p->options & BEV_OPT_CLOSE_ON_FREE)) { evutil_closesocket(fd); evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET); } } /* GetQueuedCompletionStatus doesn't reliably yield WSA error codes, so * we use WSAGetOverlappedResult to translate. */ static void bev_async_set_wsa_error(struct bufferevent *bev, struct event_overlapped *eo) { DWORD bytes, flags; evutil_socket_t fd; fd = evbuffer_overlapped_get_fd_(bev->input); WSAGetOverlappedResult(fd, &eo->overlapped, &bytes, FALSE, &flags); } static int be_async_flush(struct bufferevent *bev, short what, enum bufferevent_flush_mode mode) { return 0; } static void connect_complete(struct event_overlapped *eo, ev_uintptr_t key, ev_ssize_t nbytes, int ok) { struct bufferevent_async *bev_a = upcast_connect(eo); struct bufferevent *bev = &bev_a->bev.bev; evutil_socket_t sock; BEV_LOCK(bev); EVUTIL_ASSERT(bev_a->bev.connecting); bev_a->bev.connecting = 0; sock = evbuffer_overlapped_get_fd_(bev_a->bev.bev.input); /* XXXX Handle error? */ setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); if (ok) bufferevent_async_set_connected_(bev); else bev_async_set_wsa_error(bev, eo); be_async_run_eventcb(bev, ok ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0); event_base_del_virtual_(bev->ev_base); bufferevent_decref_and_unlock_(bev); } static void read_complete(struct event_overlapped *eo, ev_uintptr_t key, ev_ssize_t nbytes, int ok) { struct bufferevent_async *bev_a = upcast_read(eo); struct bufferevent *bev = &bev_a->bev.bev; short what = BEV_EVENT_READING; ev_ssize_t amount_unread; BEV_LOCK(bev); EVUTIL_ASSERT(bev_a->read_in_progress); amount_unread = bev_a->read_in_progress - nbytes; evbuffer_commit_read_(bev->input, nbytes); bev_a->read_in_progress = 0; if (amount_unread) bufferevent_decrement_read_buckets_(&bev_a->bev, -amount_unread); if (!ok) bev_async_set_wsa_error(bev, eo); if (bev_a->ok) { if (ok && nbytes) { BEV_RESET_GENERIC_READ_TIMEOUT(bev); be_async_trigger_nolock(bev, EV_READ, 0); bev_async_consider_reading(bev_a); } else if (!ok) { what |= BEV_EVENT_ERROR; bev_a->ok = 0; be_async_run_eventcb(bev, what, 0); } else if (!nbytes) { what |= BEV_EVENT_EOF; bev_a->ok = 0; be_async_run_eventcb(bev, what, 0); } } bufferevent_decref_and_unlock_(bev); } static void write_complete(struct event_overlapped *eo, ev_uintptr_t key, ev_ssize_t nbytes, int ok) { struct bufferevent_async *bev_a = upcast_write(eo); struct bufferevent *bev = &bev_a->bev.bev; short what = BEV_EVENT_WRITING; ev_ssize_t amount_unwritten; BEV_LOCK(bev); EVUTIL_ASSERT(bev_a->write_in_progress); amount_unwritten = bev_a->write_in_progress - nbytes; evbuffer_commit_write_(bev->output, nbytes); bev_a->write_in_progress = 0; if (amount_unwritten) bufferevent_decrement_write_buckets_(&bev_a->bev, -amount_unwritten); if (!ok) bev_async_set_wsa_error(bev, eo); if (bev_a->ok) { if (ok && nbytes) { BEV_RESET_GENERIC_WRITE_TIMEOUT(bev); be_async_trigger_nolock(bev, EV_WRITE, 0); bev_async_consider_writing(bev_a); } else if (!ok) { what |= BEV_EVENT_ERROR; bev_a->ok = 0; be_async_run_eventcb(bev, what, 0); } else if (!nbytes) { what |= BEV_EVENT_EOF; bev_a->ok = 0; be_async_run_eventcb(bev, what, 0); } } bufferevent_decref_and_unlock_(bev); } struct bufferevent * bufferevent_async_new_(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_async *bev_a; struct bufferevent *bev; struct event_iocp_port *iocp; options |= BEV_OPT_THREADSAFE; if (!(iocp = event_base_get_iocp_(base))) return NULL; if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) { if (fatal_error(GetLastError())) return NULL; } if (!(bev_a = mm_calloc(1, sizeof(struct bufferevent_async)))) return NULL; bev = &bev_a->bev.bev; if (!(bev->input = evbuffer_overlapped_new_(fd))) { mm_free(bev_a); return NULL; } if (!(bev->output = evbuffer_overlapped_new_(fd))) { evbuffer_free(bev->input); mm_free(bev_a); return NULL; } if (bufferevent_init_common_(&bev_a->bev, base, &bufferevent_ops_async, options)<0) goto err; evbuffer_add_cb(bev->input, be_async_inbuf_callback, bev); evbuffer_add_cb(bev->output, be_async_outbuf_callback, bev); event_overlapped_init_(&bev_a->connect_overlapped, connect_complete); event_overlapped_init_(&bev_a->read_overlapped, read_complete); event_overlapped_init_(&bev_a->write_overlapped, write_complete); bufferevent_init_generic_timeout_cbs_(bev); bev_a->ok = fd >= 0; return bev; err: bufferevent_free(&bev_a->bev.bev); return NULL; } void bufferevent_async_set_connected_(struct bufferevent *bev) { struct bufferevent_async *bev_async = upcast(bev); bev_async->ok = 1; /* Now's a good time to consider reading/writing */ be_async_enable(bev, bev->enabled); } int bufferevent_async_can_connect_(struct bufferevent *bev) { const struct win32_extension_fns *ext = event_get_win32_extension_fns_(); if (BEV_IS_ASYNC(bev) && event_base_get_iocp_(bev->ev_base) && ext && ext->ConnectEx) return 1; return 0; } int bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd, const struct sockaddr *sa, int socklen) { BOOL rc; struct bufferevent_async *bev_async = upcast(bev); struct sockaddr_storage ss; const struct win32_extension_fns *ext = event_get_win32_extension_fns_(); EVUTIL_ASSERT(ext && ext->ConnectEx && fd >= 0 && sa != NULL); /* ConnectEx() requires that the socket be bound to an address * with bind() before using, otherwise it will fail. We attempt * to issue a bind() here, taking into account that the error * code is set to WSAEINVAL when the socket is already bound. */ memset(&ss, 0, sizeof(ss)); if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)&ss; sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; sin6->sin6_family = AF_INET6; sin6->sin6_addr = in6addr_any; } else { /* Well, the user will have to bind() */ return -1; } if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 && WSAGetLastError() != WSAEINVAL) return -1; event_base_add_virtual_(bev->ev_base); bufferevent_incref_(bev); rc = ext->ConnectEx(fd, sa, socklen, NULL, 0, NULL, &bev_async->connect_overlapped.overlapped); if (rc || WSAGetLastError() == ERROR_IO_PENDING) return 0; event_base_del_virtual_(bev->ev_base); bufferevent_decref_(bev); return -1; } static int be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data) { switch (op) { case BEV_CTRL_GET_FD: data->fd = evbuffer_overlapped_get_fd_(bev->input); return 0; case BEV_CTRL_SET_FD: { struct bufferevent_async *bev_a = upcast(bev); struct event_iocp_port *iocp; if (data->fd == evbuffer_overlapped_get_fd_(bev->input)) return 0; if (!(iocp = event_base_get_iocp_(bev->ev_base))) return -1; if (event_iocp_port_associate_(iocp, data->fd, 1) < 0) { if (fatal_error(GetLastError())) return -1; } evbuffer_overlapped_set_fd_(bev->input, data->fd); evbuffer_overlapped_set_fd_(bev->output, data->fd); bev_a->ok = data->fd >= 0; return 0; } case BEV_CTRL_CANCEL_ALL: { struct bufferevent_async *bev_a = upcast(bev); evutil_socket_t fd = evbuffer_overlapped_get_fd_(bev->input); if (fd != (evutil_socket_t)EVUTIL_INVALID_SOCKET && (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) { closesocket(fd); evbuffer_overlapped_set_fd_(bev->input, EVUTIL_INVALID_SOCKET); } bev_a->ok = 0; return 0; } case BEV_CTRL_GET_UNDERLYING: default: return -1; } } lldpd-1.0.13/libevent/Doxyfile0000644000076400001440000002431014111362570016707 0ustar00bernatusers00000000000000# Doxyfile 1.5.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = $(PROJECT)-$(VERSION) # Place all output under 'doxygen/' OUTPUT_DIRECTORY = $(DOCDIR) # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = include/ #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = \ $(SRCDIR)/include/event2/buffer.h \ $(SRCDIR)/include/event2/buffer_compat.h \ $(SRCDIR)/include/event2/bufferevent.h \ $(SRCDIR)/include/event2/bufferevent_compat.h \ $(SRCDIR)/include/event2/bufferevent_ssl.h \ $(SRCDIR)/include/event2/dns.h \ $(SRCDIR)/include/event2/dns_compat.h \ $(SRCDIR)/include/event2/event.h \ $(SRCDIR)/include/event2/event_compat.h \ $(SRCDIR)/include/event2/http.h \ $(SRCDIR)/include/event2/http_compat.h \ $(SRCDIR)/include/event2/listener.h \ $(SRCDIR)/include/event2/rpc.h \ $(SRCDIR)/include/event2/rpc_compat.h \ $(SRCDIR)/include/event2/tag.h \ $(SRCDIR)/include/event2/tag_compat.h \ $(SRCDIR)/include/event2/thread.h \ $(SRCDIR)/include/event2/util.h #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = $(GENERATE_HTML) #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = $(GENERATE_LATEX) # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = $(GENERATE_MAN) # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = YES #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = TAILQ_ENTRY RB_ENTRY EVENT_DEFINED_TQENTRY_ EVENT_IN_DOXYGEN_ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES lldpd-1.0.13/libevent/log.c0000644000076400001440000001253114111362570016130 0ustar00bernatusers00000000000000/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ /* * log.c * * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code. * * Copyright (c) 2005-2012 Niels Provos and Nick Mathewson * * Copyright (c) 2000 Dug Song * * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include #include #include "event2/event.h" #include "event2/util.h" #include "log-internal.h" static void event_log(int severity, const char *msg); static void event_exit(int errcode) EV_NORETURN; static event_fatal_cb fatal_fn = NULL; #ifdef EVENT_DEBUG_LOGGING_ENABLED #ifdef USE_DEBUG #define DEFAULT_MASK EVENT_DBG_ALL #else #define DEFAULT_MASK 0 #endif EVENT2_EXPORT_SYMBOL ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK; #endif /* EVENT_DEBUG_LOGGING_ENABLED */ void event_enable_debug_logging(ev_uint32_t which) { #ifdef EVENT_DEBUG_LOGGING_ENABLED event_debug_logging_mask_ = which; #endif } void event_set_fatal_callback(event_fatal_cb cb) { fatal_fn = cb; } static void event_exit(int errcode) { if (fatal_fn) { fatal_fn(errcode); exit(errcode); /* should never be reached */ } else if (errcode == EVENT_ERR_ABORT_) abort(); else exit(errcode); } void event_err(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_ERR, strerror(errno), fmt, ap); va_end(ap); event_exit(eval); } void event_warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_WARN, strerror(errno), fmt, ap); va_end(ap); } void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) { va_list ap; int err = evutil_socket_geterror(sock); va_start(ap, fmt); event_logv_(EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap); va_end(ap); event_exit(eval); } void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) { va_list ap; int err = evutil_socket_geterror(sock); va_start(ap, fmt); event_logv_(EVENT_LOG_WARN, evutil_socket_error_to_string(err), fmt, ap); va_end(ap); } void event_errx(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_ERR, NULL, fmt, ap); va_end(ap); event_exit(eval); } void event_warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_WARN, NULL, fmt, ap); va_end(ap); } void event_msgx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_MSG, NULL, fmt, ap); va_end(ap); } void event_debugx_(const char *fmt, ...) { va_list ap; va_start(ap, fmt); event_logv_(EVENT_LOG_DEBUG, NULL, fmt, ap); va_end(ap); } void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap) { char buf[1024]; size_t len; if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_()) return; if (fmt != NULL) evutil_vsnprintf(buf, sizeof(buf), fmt, ap); else buf[0] = '\0'; if (errstr) { len = strlen(buf); if (len < sizeof(buf) - 3) { evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr); } } event_log(severity, buf); } static event_log_cb log_fn = NULL; void event_set_log_callback(event_log_cb cb) { log_fn = cb; } static void event_log(int severity, const char *msg) { if (log_fn) log_fn(severity, msg); else { const char *severity_str; switch (severity) { case EVENT_LOG_DEBUG: severity_str = "debug"; break; case EVENT_LOG_MSG: severity_str = "msg"; break; case EVENT_LOG_WARN: severity_str = "warn"; break; case EVENT_LOG_ERR: severity_str = "err"; break; default: severity_str = "???"; break; } (void)fprintf(stderr, "[%s] %s\n", severity_str, msg); } } lldpd-1.0.13/libevent/evrpc.c0000644000076400001440000007127114111362570016474 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #undef WIN32_LEAN_AND_MEAN #endif #include #ifndef _WIN32 #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #ifndef _WIN32 #include #endif #include #include #include #include #include "event2/event.h" #include "event2/event_struct.h" #include "event2/rpc.h" #include "event2/rpc_struct.h" #include "evrpc-internal.h" #include "event2/http.h" #include "event2/buffer.h" #include "event2/tag.h" #include "event2/http_struct.h" #include "event2/http_compat.h" #include "event2/util.h" #include "util-internal.h" #include "log-internal.h" #include "mm-internal.h" struct evrpc_base * evrpc_init(struct evhttp *http_server) { struct evrpc_base* base = mm_calloc(1, sizeof(struct evrpc_base)); if (base == NULL) return (NULL); /* we rely on the tagging sub system */ evtag_init(); TAILQ_INIT(&base->registered_rpcs); TAILQ_INIT(&base->input_hooks); TAILQ_INIT(&base->output_hooks); TAILQ_INIT(&base->paused_requests); base->http_server = http_server; return (base); } void evrpc_free(struct evrpc_base *base) { struct evrpc *rpc; struct evrpc_hook *hook; struct evrpc_hook_ctx *pause; int r; while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) { r = evrpc_unregister_rpc(base, rpc->uri); EVUTIL_ASSERT(r == 0); } while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) { TAILQ_REMOVE(&base->paused_requests, pause, next); mm_free(pause); } while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) { r = evrpc_remove_hook(base, EVRPC_INPUT, hook); EVUTIL_ASSERT(r); } while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) { r = evrpc_remove_hook(base, EVRPC_OUTPUT, hook); EVUTIL_ASSERT(r); } mm_free(base); } void * evrpc_add_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *), void *cb_arg) { struct evrpc_hooks_ *base = vbase; struct evrpc_hook_list *head = NULL; struct evrpc_hook *hook = NULL; switch (hook_type) { case EVRPC_INPUT: head = &base->in_hooks; break; case EVRPC_OUTPUT: head = &base->out_hooks; break; default: EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT); } hook = mm_calloc(1, sizeof(struct evrpc_hook)); EVUTIL_ASSERT(hook != NULL); hook->process = cb; hook->process_arg = cb_arg; TAILQ_INSERT_TAIL(head, hook, next); return (hook); } static int evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle) { struct evrpc_hook *hook = NULL; TAILQ_FOREACH(hook, head, next) { if (hook == handle) { TAILQ_REMOVE(head, hook, next); mm_free(hook); return (1); } } return (0); } /* * remove the hook specified by the handle */ int evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle) { struct evrpc_hooks_ *base = vbase; struct evrpc_hook_list *head = NULL; switch (hook_type) { case EVRPC_INPUT: head = &base->in_hooks; break; case EVRPC_OUTPUT: head = &base->out_hooks; break; default: EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT); } return (evrpc_remove_hook_internal(head, handle)); } static int evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx, struct evhttp_request *req, struct evbuffer *evbuf) { struct evrpc_hook *hook; TAILQ_FOREACH(hook, head, next) { int res = hook->process(ctx, req, evbuf, hook->process_arg); if (res != EVRPC_CONTINUE) return (res); } return (EVRPC_CONTINUE); } static void evrpc_pool_schedule(struct evrpc_pool *pool); static void evrpc_request_cb(struct evhttp_request *, void *); /* * Registers a new RPC with the HTTP server. The evrpc object is expected * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn * calls this function. */ static char * evrpc_construct_uri(const char *uri) { char *constructed_uri; size_t constructed_uri_len; constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1; if ((constructed_uri = mm_malloc(constructed_uri_len)) == NULL) event_err(1, "%s: failed to register rpc at %s", __func__, uri); memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX)); memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri)); constructed_uri[constructed_uri_len - 1] = '\0'; return (constructed_uri); } int evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc, void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg) { char *constructed_uri = evrpc_construct_uri(rpc->uri); rpc->base = base; rpc->cb = cb; rpc->cb_arg = cb_arg; TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next); evhttp_set_cb(base->http_server, constructed_uri, evrpc_request_cb, rpc); mm_free(constructed_uri); return (0); } int evrpc_unregister_rpc(struct evrpc_base *base, const char *name) { char *registered_uri = NULL; struct evrpc *rpc; int r; /* find the right rpc; linear search might be slow */ TAILQ_FOREACH(rpc, &base->registered_rpcs, next) { if (strcmp(rpc->uri, name) == 0) break; } if (rpc == NULL) { /* We did not find an RPC with this name */ return (-1); } TAILQ_REMOVE(&base->registered_rpcs, rpc, next); registered_uri = evrpc_construct_uri(name); /* remove the http server callback */ r = evhttp_del_cb(base->http_server, registered_uri); EVUTIL_ASSERT(r == 0); mm_free(registered_uri); mm_free((char *)rpc->uri); mm_free(rpc); return (0); } static int evrpc_pause_request(void *vbase, void *ctx, void (*cb)(void *, enum EVRPC_HOOK_RESULT)); static void evrpc_request_cb_closure(void *, enum EVRPC_HOOK_RESULT); static void evrpc_request_cb(struct evhttp_request *req, void *arg) { struct evrpc *rpc = arg; struct evrpc_req_generic *rpc_state = NULL; /* let's verify the outside parameters */ if (req->type != EVHTTP_REQ_POST || evbuffer_get_length(req->input_buffer) <= 0) goto error; rpc_state = mm_calloc(1, sizeof(struct evrpc_req_generic)); if (rpc_state == NULL) goto error; rpc_state->rpc = rpc; rpc_state->http_req = req; rpc_state->rpc_data = NULL; if (TAILQ_FIRST(&rpc->base->input_hooks) != NULL) { int hook_res; evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon); /* * allow hooks to modify the outgoing request */ hook_res = evrpc_process_hooks(&rpc->base->input_hooks, rpc_state, req, req->input_buffer); switch (hook_res) { case EVRPC_TERMINATE: goto error; case EVRPC_PAUSE: evrpc_pause_request(rpc->base, rpc_state, evrpc_request_cb_closure); return; case EVRPC_CONTINUE: break; default: EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE || hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE); } } evrpc_request_cb_closure(rpc_state, EVRPC_CONTINUE); return; error: if (rpc_state) evrpc_reqstate_free_(rpc_state); evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); return; } static void evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res) { struct evrpc_req_generic *rpc_state = arg; struct evrpc *rpc; struct evhttp_request *req; EVUTIL_ASSERT(rpc_state); rpc = rpc_state->rpc; req = rpc_state->http_req; if (hook_res == EVRPC_TERMINATE) goto error; /* let's check that we can parse the request */ rpc_state->request = rpc->request_new(rpc->request_new_arg); if (rpc_state->request == NULL) goto error; if (rpc->request_unmarshal( rpc_state->request, req->input_buffer) == -1) { /* we failed to parse the request; that's a bummer */ goto error; } /* at this point, we have a well formed request, prepare the reply */ rpc_state->reply = rpc->reply_new(rpc->reply_new_arg); if (rpc_state->reply == NULL) goto error; /* give the rpc to the user; they can deal with it */ rpc->cb(rpc_state, rpc->cb_arg); return; error: evrpc_reqstate_free_(rpc_state); evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); return; } void evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state) { struct evrpc *rpc; EVUTIL_ASSERT(rpc_state != NULL); rpc = rpc_state->rpc; /* clean up all memory */ if (rpc_state->hook_meta != NULL) evrpc_hook_context_free_(rpc_state->hook_meta); if (rpc_state->request != NULL) rpc->request_free(rpc_state->request); if (rpc_state->reply != NULL) rpc->reply_free(rpc_state->reply); if (rpc_state->rpc_data != NULL) evbuffer_free(rpc_state->rpc_data); mm_free(rpc_state); } static void evrpc_request_done_closure(void *, enum EVRPC_HOOK_RESULT); void evrpc_request_done(struct evrpc_req_generic *rpc_state) { struct evhttp_request *req; struct evrpc *rpc; EVUTIL_ASSERT(rpc_state); req = rpc_state->http_req; rpc = rpc_state->rpc; if (rpc->reply_complete(rpc_state->reply) == -1) { /* the reply was not completely filled in. error out */ goto error; } if ((rpc_state->rpc_data = evbuffer_new()) == NULL) { /* out of memory */ goto error; } /* serialize the reply */ rpc->reply_marshal(rpc_state->rpc_data, rpc_state->reply); if (TAILQ_FIRST(&rpc->base->output_hooks) != NULL) { int hook_res; evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon); /* do hook based tweaks to the request */ hook_res = evrpc_process_hooks(&rpc->base->output_hooks, rpc_state, req, rpc_state->rpc_data); switch (hook_res) { case EVRPC_TERMINATE: goto error; case EVRPC_PAUSE: if (evrpc_pause_request(rpc->base, rpc_state, evrpc_request_done_closure) == -1) goto error; return; case EVRPC_CONTINUE: break; default: EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE || hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE); } } evrpc_request_done_closure(rpc_state, EVRPC_CONTINUE); return; error: evrpc_reqstate_free_(rpc_state); evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); return; } void * evrpc_get_request(struct evrpc_req_generic *req) { return req->request; } void * evrpc_get_reply(struct evrpc_req_generic *req) { return req->reply; } static void evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res) { struct evrpc_req_generic *rpc_state = arg; struct evhttp_request *req; EVUTIL_ASSERT(rpc_state); req = rpc_state->http_req; if (hook_res == EVRPC_TERMINATE) goto error; /* on success, we are going to transmit marshaled binary data */ if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) { evhttp_add_header(req->output_headers, "Content-Type", "application/octet-stream"); } evhttp_send_reply(req, HTTP_OK, "OK", rpc_state->rpc_data); evrpc_reqstate_free_(rpc_state); return; error: evrpc_reqstate_free_(rpc_state); evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); return; } /* Client implementation of RPC site */ static int evrpc_schedule_request(struct evhttp_connection *connection, struct evrpc_request_wrapper *ctx); struct evrpc_pool * evrpc_pool_new(struct event_base *base) { struct evrpc_pool *pool = mm_calloc(1, sizeof(struct evrpc_pool)); if (pool == NULL) return (NULL); TAILQ_INIT(&pool->connections); TAILQ_INIT(&pool->requests); TAILQ_INIT(&pool->paused_requests); TAILQ_INIT(&pool->input_hooks); TAILQ_INIT(&pool->output_hooks); pool->base = base; pool->timeout = -1; return (pool); } static void evrpc_request_wrapper_free(struct evrpc_request_wrapper *request) { if (request->hook_meta != NULL) evrpc_hook_context_free_(request->hook_meta); mm_free(request->name); mm_free(request); } void evrpc_pool_free(struct evrpc_pool *pool) { struct evhttp_connection *connection; struct evrpc_request_wrapper *request; struct evrpc_hook_ctx *pause; struct evrpc_hook *hook; int r; while ((request = TAILQ_FIRST(&pool->requests)) != NULL) { TAILQ_REMOVE(&pool->requests, request, next); evrpc_request_wrapper_free(request); } while ((pause = TAILQ_FIRST(&pool->paused_requests)) != NULL) { TAILQ_REMOVE(&pool->paused_requests, pause, next); mm_free(pause); } while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) { TAILQ_REMOVE(&pool->connections, connection, next); evhttp_connection_free(connection); } while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) { r = evrpc_remove_hook(pool, EVRPC_INPUT, hook); EVUTIL_ASSERT(r); } while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) { r = evrpc_remove_hook(pool, EVRPC_OUTPUT, hook); EVUTIL_ASSERT(r); } mm_free(pool); } /* * Add a connection to the RPC pool. A request scheduled on the pool * may use any available connection. */ void evrpc_pool_add_connection(struct evrpc_pool *pool, struct evhttp_connection *connection) { EVUTIL_ASSERT(connection->http_server == NULL); TAILQ_INSERT_TAIL(&pool->connections, connection, next); /* * associate an event base with this connection */ if (pool->base != NULL) evhttp_connection_set_base(connection, pool->base); /* * unless a timeout was specifically set for a connection, * the connection inherits the timeout from the pool. */ if (!evutil_timerisset(&connection->timeout)) evhttp_connection_set_timeout(connection, pool->timeout); /* * if we have any requests pending, schedule them with the new * connections. */ if (TAILQ_FIRST(&pool->requests) != NULL) { struct evrpc_request_wrapper *request = TAILQ_FIRST(&pool->requests); TAILQ_REMOVE(&pool->requests, request, next); evrpc_schedule_request(connection, request); } } void evrpc_pool_remove_connection(struct evrpc_pool *pool, struct evhttp_connection *connection) { TAILQ_REMOVE(&pool->connections, connection, next); } void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs) { struct evhttp_connection *evcon; TAILQ_FOREACH(evcon, &pool->connections, next) { evhttp_connection_set_timeout(evcon, timeout_in_secs); } pool->timeout = timeout_in_secs; } static void evrpc_reply_done(struct evhttp_request *, void *); static void evrpc_request_timeout(evutil_socket_t, short, void *); /* * Finds a connection object associated with the pool that is currently * idle and can be used to make a request. */ static struct evhttp_connection * evrpc_pool_find_connection(struct evrpc_pool *pool) { struct evhttp_connection *connection; TAILQ_FOREACH(connection, &pool->connections, next) { if (TAILQ_FIRST(&connection->requests) == NULL) return (connection); } return (NULL); } /* * Prototypes responsible for evrpc scheduling and hooking */ static void evrpc_schedule_request_closure(void *ctx, enum EVRPC_HOOK_RESULT); /* * We assume that the ctx is no longer queued on the pool. */ static int evrpc_schedule_request(struct evhttp_connection *connection, struct evrpc_request_wrapper *ctx) { struct evhttp_request *req = NULL; struct evrpc_pool *pool = ctx->pool; struct evrpc_status status; if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL) goto error; /* serialize the request data into the output buffer */ ctx->request_marshal(req->output_buffer, ctx->request); /* we need to know the connection that we might have to abort */ ctx->evcon = connection; /* if we get paused we also need to know the request */ ctx->req = req; if (TAILQ_FIRST(&pool->output_hooks) != NULL) { int hook_res; evrpc_hook_associate_meta_(&ctx->hook_meta, connection); /* apply hooks to the outgoing request */ hook_res = evrpc_process_hooks(&pool->output_hooks, ctx, req, req->output_buffer); switch (hook_res) { case EVRPC_TERMINATE: goto error; case EVRPC_PAUSE: /* we need to be explicitly resumed */ if (evrpc_pause_request(pool, ctx, evrpc_schedule_request_closure) == -1) goto error; return (0); case EVRPC_CONTINUE: /* we can just continue */ break; default: EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE || hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE); } } evrpc_schedule_request_closure(ctx, EVRPC_CONTINUE); return (0); error: memset(&status, 0, sizeof(status)); status.error = EVRPC_STATUS_ERR_UNSTARTED; (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg); evrpc_request_wrapper_free(ctx); return (-1); } static void evrpc_schedule_request_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res) { struct evrpc_request_wrapper *ctx = arg; struct evhttp_connection *connection = ctx->evcon; struct evhttp_request *req = ctx->req; struct evrpc_pool *pool = ctx->pool; struct evrpc_status status; char *uri = NULL; int res = 0; if (hook_res == EVRPC_TERMINATE) goto error; uri = evrpc_construct_uri(ctx->name); if (uri == NULL) goto error; if (pool->timeout > 0) { /* * a timeout after which the whole rpc is going to be aborted. */ struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = pool->timeout; evtimer_add(&ctx->ev_timeout, &tv); } /* start the request over the connection */ res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri); mm_free(uri); if (res == -1) goto error; return; error: memset(&status, 0, sizeof(status)); status.error = EVRPC_STATUS_ERR_UNSTARTED; (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg); evrpc_request_wrapper_free(ctx); } /* we just queue the paused request on the pool under the req object */ static int evrpc_pause_request(void *vbase, void *ctx, void (*cb)(void *, enum EVRPC_HOOK_RESULT)) { struct evrpc_hooks_ *base = vbase; struct evrpc_hook_ctx *pause = mm_malloc(sizeof(*pause)); if (pause == NULL) return (-1); pause->ctx = ctx; pause->cb = cb; TAILQ_INSERT_TAIL(&base->pause_requests, pause, next); return (0); } int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res) { struct evrpc_hooks_ *base = vbase; struct evrpc_pause_list *head = &base->pause_requests; struct evrpc_hook_ctx *pause; TAILQ_FOREACH(pause, head, next) { if (pause->ctx == ctx) break; } if (pause == NULL) return (-1); (*pause->cb)(pause->ctx, res); TAILQ_REMOVE(head, pause, next); mm_free(pause); return (0); } int evrpc_make_request(struct evrpc_request_wrapper *ctx) { struct evrpc_pool *pool = ctx->pool; /* initialize the event structure for this rpc */ evtimer_assign(&ctx->ev_timeout, pool->base, evrpc_request_timeout, ctx); /* we better have some available connections on the pool */ EVUTIL_ASSERT(TAILQ_FIRST(&pool->connections) != NULL); /* * if no connection is available, we queue the request on the pool, * the next time a connection is empty, the rpc will be send on that. */ TAILQ_INSERT_TAIL(&pool->requests, ctx, next); evrpc_pool_schedule(pool); return (0); } struct evrpc_request_wrapper * evrpc_make_request_ctx( struct evrpc_pool *pool, void *request, void *reply, const char *rpcname, void (*req_marshal)(struct evbuffer*, void *), void (*rpl_clear)(void *), int (*rpl_unmarshal)(void *, struct evbuffer *), void (*cb)(struct evrpc_status *, void *, void *, void *), void *cbarg) { struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *) mm_malloc(sizeof(struct evrpc_request_wrapper)); if (ctx == NULL) return (NULL); ctx->pool = pool; ctx->hook_meta = NULL; ctx->evcon = NULL; ctx->name = mm_strdup(rpcname); if (ctx->name == NULL) { mm_free(ctx); return (NULL); } ctx->cb = cb; ctx->cb_arg = cbarg; ctx->request = request; ctx->reply = reply; ctx->request_marshal = req_marshal; ctx->reply_clear = rpl_clear; ctx->reply_unmarshal = rpl_unmarshal; return (ctx); } static void evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT); static void evrpc_reply_done(struct evhttp_request *req, void *arg) { struct evrpc_request_wrapper *ctx = arg; struct evrpc_pool *pool = ctx->pool; int hook_res = EVRPC_CONTINUE; /* cancel any timeout we might have scheduled */ event_del(&ctx->ev_timeout); ctx->req = req; /* we need to get the reply now */ if (req == NULL) { evrpc_reply_done_closure(ctx, EVRPC_CONTINUE); return; } if (TAILQ_FIRST(&pool->input_hooks) != NULL) { evrpc_hook_associate_meta_(&ctx->hook_meta, ctx->evcon); /* apply hooks to the incoming request */ hook_res = evrpc_process_hooks(&pool->input_hooks, ctx, req, req->input_buffer); switch (hook_res) { case EVRPC_TERMINATE: case EVRPC_CONTINUE: break; case EVRPC_PAUSE: /* * if we get paused we also need to know the * request. unfortunately, the underlying * layer is going to free it. we need to * request ownership explicitly */ evhttp_request_own(req); evrpc_pause_request(pool, ctx, evrpc_reply_done_closure); return; default: EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE || hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE); } } evrpc_reply_done_closure(ctx, hook_res); /* http request is being freed by underlying layer */ } static void evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res) { struct evrpc_request_wrapper *ctx = arg; struct evhttp_request *req = ctx->req; struct evrpc_pool *pool = ctx->pool; struct evrpc_status status; int res = -1; memset(&status, 0, sizeof(status)); status.http_req = req; /* we need to get the reply now */ if (req == NULL) { status.error = EVRPC_STATUS_ERR_TIMEOUT; } else if (hook_res == EVRPC_TERMINATE) { status.error = EVRPC_STATUS_ERR_HOOKABORTED; } else { res = ctx->reply_unmarshal(ctx->reply, req->input_buffer); if (res == -1) status.error = EVRPC_STATUS_ERR_BADPAYLOAD; } if (res == -1) { /* clear everything that we might have written previously */ ctx->reply_clear(ctx->reply); } (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg); evrpc_request_wrapper_free(ctx); /* the http layer owned the original request structure, but if we * got paused, we asked for ownership and need to free it here. */ if (req != NULL && evhttp_request_is_owned(req)) evhttp_request_free(req); /* see if we can schedule another request */ evrpc_pool_schedule(pool); } static void evrpc_pool_schedule(struct evrpc_pool *pool) { struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests); struct evhttp_connection *evcon; /* if no requests are pending, we have no work */ if (ctx == NULL) return; if ((evcon = evrpc_pool_find_connection(pool)) != NULL) { TAILQ_REMOVE(&pool->requests, ctx, next); evrpc_schedule_request(evcon, ctx); } } static void evrpc_request_timeout(evutil_socket_t fd, short what, void *arg) { struct evrpc_request_wrapper *ctx = arg; struct evhttp_connection *evcon = ctx->evcon; EVUTIL_ASSERT(evcon != NULL); evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); } /* * frees potential meta data associated with a request. */ static void evrpc_meta_data_free(struct evrpc_meta_list *meta_data) { struct evrpc_meta *entry; EVUTIL_ASSERT(meta_data != NULL); while ((entry = TAILQ_FIRST(meta_data)) != NULL) { TAILQ_REMOVE(meta_data, entry, next); mm_free(entry->key); mm_free(entry->data); mm_free(entry); } } static struct evrpc_hook_meta * evrpc_hook_meta_new_(void) { struct evrpc_hook_meta *ctx; ctx = mm_malloc(sizeof(struct evrpc_hook_meta)); EVUTIL_ASSERT(ctx != NULL); TAILQ_INIT(&ctx->meta_data); ctx->evcon = NULL; return (ctx); } static void evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx, struct evhttp_connection *evcon) { struct evrpc_hook_meta *ctx = *pctx; if (ctx == NULL) *pctx = ctx = evrpc_hook_meta_new_(); ctx->evcon = evcon; } static void evrpc_hook_context_free_(struct evrpc_hook_meta *ctx) { evrpc_meta_data_free(&ctx->meta_data); mm_free(ctx); } /* Adds meta data */ void evrpc_hook_add_meta(void *ctx, const char *key, const void *data, size_t data_size) { struct evrpc_request_wrapper *req = ctx; struct evrpc_hook_meta *store = NULL; struct evrpc_meta *meta = NULL; if ((store = req->hook_meta) == NULL) store = req->hook_meta = evrpc_hook_meta_new_(); meta = mm_malloc(sizeof(struct evrpc_meta)); EVUTIL_ASSERT(meta != NULL); meta->key = mm_strdup(key); EVUTIL_ASSERT(meta->key != NULL); meta->data_size = data_size; meta->data = mm_malloc(data_size); EVUTIL_ASSERT(meta->data != NULL); memcpy(meta->data, data, data_size); TAILQ_INSERT_TAIL(&store->meta_data, meta, next); } int evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size) { struct evrpc_request_wrapper *req = ctx; struct evrpc_meta *meta = NULL; if (req->hook_meta == NULL) return (-1); TAILQ_FOREACH(meta, &req->hook_meta->meta_data, next) { if (strcmp(meta->key, key) == 0) { *data = meta->data; *data_size = meta->data_size; return (0); } } return (-1); } struct evhttp_connection * evrpc_hook_get_connection(void *ctx) { struct evrpc_request_wrapper *req = ctx; return (req->hook_meta != NULL ? req->hook_meta->evcon : NULL); } int evrpc_send_request_generic(struct evrpc_pool *pool, void *request, void *reply, void (*cb)(struct evrpc_status *, void *, void *, void *), void *cb_arg, const char *rpcname, void (*req_marshal)(struct evbuffer *, void *), void (*rpl_clear)(void *), int (*rpl_unmarshal)(void *, struct evbuffer *)) { struct evrpc_status status; struct evrpc_request_wrapper *ctx; ctx = evrpc_make_request_ctx(pool, request, reply, rpcname, req_marshal, rpl_clear, rpl_unmarshal, cb, cb_arg); if (ctx == NULL) goto error; return (evrpc_make_request(ctx)); error: memset(&status, 0, sizeof(status)); status.error = EVRPC_STATUS_ERR_UNSTARTED; (*(cb))(&status, request, reply, cb_arg); return (-1); } /** Takes a request object and fills it in with the right magic */ static struct evrpc * evrpc_register_object(const char *name, void *(*req_new)(void*), void *req_new_arg, void (*req_free)(void *), int (*req_unmarshal)(void *, struct evbuffer *), void *(*rpl_new)(void*), void *rpl_new_arg, void (*rpl_free)(void *), int (*rpl_complete)(void *), void (*rpl_marshal)(struct evbuffer *, void *)) { struct evrpc* rpc = (struct evrpc *)mm_calloc(1, sizeof(struct evrpc)); if (rpc == NULL) return (NULL); rpc->uri = mm_strdup(name); if (rpc->uri == NULL) { mm_free(rpc); return (NULL); } rpc->request_new = req_new; rpc->request_new_arg = req_new_arg; rpc->request_free = req_free; rpc->request_unmarshal = req_unmarshal; rpc->reply_new = rpl_new; rpc->reply_new_arg = rpl_new_arg; rpc->reply_free = rpl_free; rpc->reply_complete = rpl_complete; rpc->reply_marshal = rpl_marshal; return (rpc); } int evrpc_register_generic(struct evrpc_base *base, const char *name, void (*callback)(struct evrpc_req_generic *, void *), void *cbarg, void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *), int (*req_unmarshal)(void *, struct evbuffer *), void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *), int (*rpl_complete)(void *), void (*rpl_marshal)(struct evbuffer *, void *)) { struct evrpc* rpc = evrpc_register_object(name, req_new, req_new_arg, req_free, req_unmarshal, rpl_new, rpl_new_arg, rpl_free, rpl_complete, rpl_marshal); if (rpc == NULL) return (-1); evrpc_register_rpc(base, rpc, (void (*)(struct evrpc_req_generic*, void *))callback, cbarg); return (0); } /** accessors for obscure and undocumented functionality */ struct evrpc_pool * evrpc_request_get_pool(struct evrpc_request_wrapper *ctx) { return (ctx->pool); } void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx, struct evrpc_pool *pool) { ctx->pool = pool; } void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx, void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg), void *cb_arg) { ctx->cb = cb; ctx->cb_arg = cb_arg; } lldpd-1.0.13/libevent/libevent.pc.in0000644000076400001440000000047514111362570017750 0ustar00bernatusers00000000000000#libevent pkg-config source file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libevent Description: libevent is an asynchronous notification event loop library Version: @VERSION@ Requires: Conflicts: Libs: -L${libdir} -levent Libs.private: @LIBS@ Cflags: -I${includedir} lldpd-1.0.13/libevent/iocp-internal.h0000644000076400001440000001747114111362570020130 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef IOCP_INTERNAL_H_INCLUDED_ #define IOCP_INTERNAL_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif struct event_overlapped; struct event_iocp_port; struct evbuffer; typedef void (*iocp_callback)(struct event_overlapped *, ev_uintptr_t, ev_ssize_t, int success); /* This whole file is actually win32 only. We wrap the structures in a win32 * ifdef so that we can test-compile code that uses these interfaces on * non-win32 platforms. */ #ifdef _WIN32 /** Internal use only. Wraps an OVERLAPPED that we're using for libevent functionality. Whenever an event_iocp_port gets an event for a given OVERLAPPED*, it upcasts the pointer to an event_overlapped, and calls the iocp_callback function with the event_overlapped, the iocp key, and the number of bytes transferred as arguments. */ struct event_overlapped { OVERLAPPED overlapped; iocp_callback cb; }; /* Mingw's headers don't define LPFN_ACCEPTEX. */ typedef BOOL (WINAPI *AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED); typedef BOOL (WINAPI *ConnectExPtr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED); typedef void (WINAPI *GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR *, LPINT, LPSOCKADDR *, LPINT); /** Internal use only. Holds pointers to functions that only some versions of Windows provide. */ struct win32_extension_fns { AcceptExPtr AcceptEx; ConnectExPtr ConnectEx; GetAcceptExSockaddrsPtr GetAcceptExSockaddrs; }; /** Internal use only. Stores a Windows IO Completion port, along with related data. */ struct event_iocp_port { /** The port itself */ HANDLE port; /* A lock to cover internal structures. */ CRITICAL_SECTION lock; /** Number of threads ever open on the port. */ short n_threads; /** True iff we're shutting down all the threads on this port */ short shutdown; /** How often the threads on this port check for shutdown and other * conditions */ long ms; /* The threads that are waiting for events. */ HANDLE *threads; /** Number of threads currently open on this port. */ short n_live_threads; /** A semaphore to signal when we are done shutting down. */ HANDLE *shutdownSemaphore; }; EVENT2_EXPORT_SYMBOL const struct win32_extension_fns *event_get_win32_extension_fns_(void); #else /* Dummy definition so we can test-compile more things on unix. */ struct event_overlapped { iocp_callback cb; }; #endif /** Initialize the fields in an event_overlapped. @param overlapped The struct event_overlapped to initialize @param cb The callback that should be invoked once the IO operation has finished. */ EVENT2_EXPORT_SYMBOL void event_overlapped_init_(struct event_overlapped *, iocp_callback cb); /** Allocate and return a new evbuffer that supports overlapped IO on a given socket. The socket must be associated with an IO completion port using event_iocp_port_associate_. */ EVENT2_EXPORT_SYMBOL struct evbuffer *evbuffer_overlapped_new_(evutil_socket_t fd); /** XXXX Document (nickm) */ evutil_socket_t evbuffer_overlapped_get_fd_(struct evbuffer *buf); void evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd); /** Start reading data onto the end of an overlapped evbuffer. An evbuffer can only have one read pending at a time. While the read is in progress, no other data may be added to the end of the buffer. The buffer must be created with event_overlapped_init_(). evbuffer_commit_read_() must be called in the completion callback. @param buf The buffer to read onto @param n The number of bytes to try to read. @param ol Overlapped object with associated completion callback. @return 0 on success, -1 on error. */ EVENT2_EXPORT_SYMBOL int evbuffer_launch_read_(struct evbuffer *buf, size_t n, struct event_overlapped *ol); /** Start writing data from the start of an evbuffer. An evbuffer can only have one write pending at a time. While the write is in progress, no other data may be removed from the front of the buffer. The buffer must be created with event_overlapped_init_(). evbuffer_commit_write_() must be called in the completion callback. @param buf The buffer to read onto @param n The number of bytes to try to read. @param ol Overlapped object with associated completion callback. @return 0 on success, -1 on error. */ EVENT2_EXPORT_SYMBOL int evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t n, struct event_overlapped *ol); /** XXX document */ EVENT2_EXPORT_SYMBOL void evbuffer_commit_read_(struct evbuffer *, ev_ssize_t); EVENT2_EXPORT_SYMBOL void evbuffer_commit_write_(struct evbuffer *, ev_ssize_t); /** Create an IOCP, and launch its worker threads. Internal use only. This interface is unstable, and will change. */ EVENT2_EXPORT_SYMBOL struct event_iocp_port *event_iocp_port_launch_(int n_cpus); /** Associate a file descriptor with an iocp, such that overlapped IO on the fd will happen on one of the iocp's worker threads. */ EVENT2_EXPORT_SYMBOL int event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd, ev_uintptr_t key); /** Tell all threads serving an iocp to stop. Wait for up to waitMsec for all the threads to finish whatever they're doing. If waitMsec is -1, wait as long as required. If all the threads are done, free the port and return 0. Otherwise, return -1. If you get a -1 return value, it is safe to call this function again. */ EVENT2_EXPORT_SYMBOL int event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec); /* FIXME document. */ EVENT2_EXPORT_SYMBOL int event_iocp_activate_overlapped_(struct event_iocp_port *port, struct event_overlapped *o, ev_uintptr_t key, ev_uint32_t n_bytes); struct event_base; /* FIXME document. */ EVENT2_EXPORT_SYMBOL struct event_iocp_port *event_base_get_iocp_(struct event_base *base); /* FIXME document. */ EVENT2_EXPORT_SYMBOL int event_base_start_iocp_(struct event_base *base, int n_cpus); void event_base_stop_iocp_(struct event_base *base); /* FIXME document. */ EVENT2_EXPORT_SYMBOL struct bufferevent *bufferevent_async_new_(struct event_base *base, evutil_socket_t fd, int options); /* FIXME document. */ void bufferevent_async_set_connected_(struct bufferevent *bev); int bufferevent_async_can_connect_(struct bufferevent *bev); int bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd, const struct sockaddr *sa, int socklen); #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/kqueue-internal.h0000644000076400001440000000370614111362570020471 0ustar00bernatusers00000000000000/* * Copyright (c) 2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef KQUEUE_INTERNAL_H_INCLUDED_ #define KQUEUE_INTERNAL_H_INCLUDED_ /** Notification function, used to tell an event base to wake up from another * thread. Only works when event_kq_add_notify_event_() has previously been * called successfully on that base. */ int event_kq_notify_base_(struct event_base *base); /** Prepare a kqueue-using event base to receive notifications via an internal * EVFILT_USER event. Return 0 on sucess, -1 on failure. */ int event_kq_add_notify_event_(struct event_base *base); #endif lldpd-1.0.13/libevent/include/0000755000076400001440000000000014143730656016635 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/include/evutil.h0000644000076400001440000000336614111362571020316 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT1_EVUTIL_H_INCLUDED_ #define EVENT1_EVUTIL_H_INCLUDED_ /** @file evutil.h Utility and compatibility functions for Libevent. The header is deprecated in Libevent 2.0 and later; please use instead. */ #include #endif /* EVENT1_EVUTIL_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/evrpc.h0000644000076400001440000000373714111362571020127 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT1_EVRPC_H_INCLUDED_ #define EVENT1_EVRPC_H_INCLUDED_ /** @file evrpc.h An RPC system for Libevent. The header is deprecated in Libevent 2.0 and later; please use instead. Depending on what functionality you need, you may also want to include more of the other headers. */ #include #include #include #include #endif /* EVENT1_EVRPC_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/evdns.h0000644000076400001440000000374314111362571020124 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT1_EVDNS_H_INCLUDED_ #define EVENT1_EVDNS_H_INCLUDED_ /** @file evdns.h A dns subsystem for Libevent. The header is deprecated in Libevent 2.0 and later; please use instead. Depending on what functionality you need, you may also want to include more of the other headers. */ #include #include #include #include #endif /* EVENT1_EVDNS_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event.h0000644000076400001440000000527014111362571020123 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT1_EVENT_H_INCLUDED_ #define EVENT1_EVENT_H_INCLUDED_ /** @file event.h A library for writing event-driven network servers. The header is deprecated in Libevent 2.0 and later; please use instead. Depending on what functionality you need, you may also want to include more of the other event2/ headers. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #ifdef EVENT__HAVE_STDINT_H #include #endif #include /* For int types. */ #include #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #undef WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus } #endif #endif /* EVENT1_EVENT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/0000755000076400001440000000000014143730656020040 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/include/event2/buffer_compat.h0000644000076400001440000001120514111362573023016 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFER_COMPAT_H_INCLUDED_ #define EVENT2_BUFFER_COMPAT_H_INCLUDED_ #include /** @file event2/buffer_compat.h Obsolete and deprecated versions of the functions in buffer.h: provided only for backward compatibility. */ /** Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY). @deprecated This function is deprecated because its behavior is not correct for almost any protocol, and also because it's wholly subsumed by evbuffer_readln(). @param buffer the evbuffer to read from @return pointer to a single line, or NULL if an error occurred */ EVENT2_EXPORT_SYMBOL char *evbuffer_readline(struct evbuffer *buffer); /** Type definition for a callback that is invoked whenever data is added or removed from an evbuffer. An evbuffer may have one or more callbacks set at a time. The order in which they are executed is undefined. A callback function may add more callbacks, or remove itself from the list of callbacks, or add or remove data from the buffer. It may not remove another callback from the list. If a callback adds or removes data from the buffer or from another buffer, this can cause a recursive invocation of your callback or other callbacks. If you ask for an infinite loop, you might just get one: watch out! @param buffer the buffer whose size has changed @param old_len the previous length of the buffer @param new_len the current length of the buffer @param arg a pointer to user data */ typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg); /** Replace all callbacks on an evbuffer with a single new callback, or remove them. Subsequent calls to evbuffer_setcb() replace callbacks set by previous calls. Setting the callback to NULL removes any previously set callback. @deprecated This function is deprecated because it clears all previous callbacks set on the evbuffer, which can cause confusing behavior if multiple parts of the code all want to add their own callbacks on a buffer. Instead, use evbuffer_add(), evbuffer_del(), and evbuffer_setflags() to manage your own evbuffer callbacks without interfering with callbacks set by others. @param buffer the evbuffer to be monitored @param cb the callback function to invoke when the evbuffer is modified, or NULL to remove all callbacks. @param cbarg an argument to be provided to the callback function @return 0 if successful, or -1 on error */ EVENT2_EXPORT_SYMBOL int evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg); /** Find a string within an evbuffer. @param buffer the evbuffer to be searched @param what the string to be searched for @param len the length of the search string @return a pointer to the beginning of the search string, or NULL if the search failed. */ EVENT2_EXPORT_SYMBOL unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len); /** deprecated in favor of calling the functions directly */ #define EVBUFFER_LENGTH(x) evbuffer_get_length(x) /** deprecated in favor of calling the functions directly */ #define EVBUFFER_DATA(x) evbuffer_pullup((x), -1) #endif lldpd-1.0.13/libevent/include/event2/listener.h0000644000076400001440000001746714111362573022047 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_LISTENER_H_INCLUDED_ #define EVENT2_LISTENER_H_INCLUDED_ #include #ifdef __cplusplus extern "C" { #endif #include struct sockaddr; struct evconnlistener; /** A callback that we invoke when a listener has a new connection. @param listener The evconnlistener @param fd The new file descriptor @param addr The source address of the connection @param socklen The length of addr @param user_arg the pointer passed to evconnlistener_new() */ typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *); /** A callback that we invoke when a listener encounters a non-retriable error. @param listener The evconnlistener @param user_arg the pointer passed to evconnlistener_new() */ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *); /** Flag: Indicates that we should not make incoming sockets nonblocking * before passing them to the callback. */ #define LEV_OPT_LEAVE_SOCKETS_BLOCKING (1u<<0) /** Flag: Indicates that freeing the listener should close the underlying * socket. */ #define LEV_OPT_CLOSE_ON_FREE (1u<<1) /** Flag: Indicates that we should set the close-on-exec flag, if possible */ #define LEV_OPT_CLOSE_ON_EXEC (1u<<2) /** Flag: Indicates that we should disable the timeout (if any) between when * this socket is closed and when we can listen again on the same port. */ #define LEV_OPT_REUSEABLE (1u<<3) /** Flag: Indicates that the listener should be locked so it's safe to use * from multiple threadcs at once. */ #define LEV_OPT_THREADSAFE (1u<<4) /** Flag: Indicates that the listener should be created in disabled * state. Use evconnlistener_enable() to enable it later. */ #define LEV_OPT_DISABLED (1u<<5) /** Flag: Indicates that the listener should defer accept() until data is * available, if possible. Ignored on platforms that do not support this. * * This option can help performance for protocols where the client transmits * immediately after connecting. Do not use this option if your protocol * _doesn't_ start out with the client transmitting data, since in that case * this option will sometimes cause the kernel to never tell you about the * connection. * * This option is only supported by evconnlistener_new_bind(): it can't * work with evconnlistener_new_fd(), since the listener needs to be told * to use the option before it is actually bound. */ #define LEV_OPT_DEFERRED_ACCEPT (1u<<6) /** Flag: Indicates that we ask to allow multiple servers (processes or * threads) to bind to the same port if they each set the option. * * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however * SO_REUSEPORT does not imply SO_REUSEADDR. * * This is only available on Linux and kernel 3.9+ */ #define LEV_OPT_REUSEABLE_PORT (1u<<7) /** Flag: Indicates that the listener wants to work only in IPv6 socket. * * According to RFC3493 and most Linux distributions, default value is to * work in IPv4-mapped mode. If there is a requirement to bind same port * on same ip addresses but different handlers for both IPv4 and IPv6, * it is required to set IPV6_V6ONLY socket option to be sure that the * code works as expected without affected by bindv6only sysctl setting in * system. * * This socket option also supported by Windows. */ #define LEV_OPT_BIND_IPV6ONLY (1u<<8) /** Allocate a new evconnlistener object to listen for incoming TCP connections on a given file descriptor. @param base The event base to associate the listener with. @param cb A callback to be invoked when a new connection arrives. If the callback is NULL, the listener will be treated as disabled until the callback is set. @param ptr A user-supplied pointer to give to the callback. @param flags Any number of LEV_OPT_* flags @param backlog Passed to the listen() call to determine the length of the acceptable connection backlog. Set to -1 for a reasonable default. Set to 0 if the socket is already listening. @param fd The file descriptor to listen on. It must be a nonblocking file descriptor, and it should already be bound to an appropriate port and address. */ EVENT2_EXPORT_SYMBOL struct evconnlistener *evconnlistener_new(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, evutil_socket_t fd); /** Allocate a new evconnlistener object to listen for incoming TCP connections on a given address. @param base The event base to associate the listener with. @param cb A callback to be invoked when a new connection arrives. If the callback is NULL, the listener will be treated as disabled until the callback is set. @param ptr A user-supplied pointer to give to the callback. @param flags Any number of LEV_OPT_* flags @param backlog Passed to the listen() call to determine the length of the acceptable connection backlog. Set to -1 for a reasonable default. @param addr The address to listen for connections on. @param socklen The length of the address. */ EVENT2_EXPORT_SYMBOL struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen); /** Disable and deallocate an evconnlistener. */ EVENT2_EXPORT_SYMBOL void evconnlistener_free(struct evconnlistener *lev); /** Re-enable an evconnlistener that has been disabled. */ EVENT2_EXPORT_SYMBOL int evconnlistener_enable(struct evconnlistener *lev); /** Stop listening for connections on an evconnlistener. */ EVENT2_EXPORT_SYMBOL int evconnlistener_disable(struct evconnlistener *lev); /** Return an evconnlistener's associated event_base. */ EVENT2_EXPORT_SYMBOL struct event_base *evconnlistener_get_base(struct evconnlistener *lev); /** Return the socket that an evconnlistner is listening on. */ EVENT2_EXPORT_SYMBOL evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev); /** Change the callback on the listener to cb and its user_data to arg. */ EVENT2_EXPORT_SYMBOL void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb, void *arg); /** Set an evconnlistener's error callback. */ EVENT2_EXPORT_SYMBOL void evconnlistener_set_error_cb(struct evconnlistener *lev, evconnlistener_errorcb errorcb); #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/include/event2/bufferevent_struct.h0000644000076400001440000001004714111362573024124 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ #define EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ /** @file event2/bufferevent_struct.h Data structures for bufferevents. Using these structures may hurt forward compatibility with later versions of Libevent: be careful! @deprecated Use of bufferevent_struct.h is completely deprecated; these structures are only exposed for backward compatibility with programs written before Libevent 2.0 that used them. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /* For struct event */ #include struct event_watermark { size_t low; size_t high; }; /** Shared implementation of a bufferevent. This type is exposed only because it was exposed in previous versions, and some people's code may rely on manipulating it. Otherwise, you should really not rely on the layout, size, or contents of this structure: it is fairly volatile, and WILL change in future versions of the code. **/ struct bufferevent { /** Event base for which this bufferevent was created. */ struct event_base *ev_base; /** Pointer to a table of function pointers to set up how this bufferevent behaves. */ const struct bufferevent_ops *be_ops; /** A read event that triggers when a timeout has happened or a socket is ready to read data. Only used by some subtypes of bufferevent. */ struct event ev_read; /** A write event that triggers when a timeout has happened or a socket is ready to write data. Only used by some subtypes of bufferevent. */ struct event ev_write; /** An input buffer. Only the bufferevent is allowed to add data to this buffer, though the user is allowed to drain it. */ struct evbuffer *input; /** An input buffer. Only the bufferevent is allowed to drain data from this buffer, though the user is allowed to add it. */ struct evbuffer *output; struct event_watermark wm_read; struct event_watermark wm_write; bufferevent_data_cb readcb; bufferevent_data_cb writecb; /* This should be called 'eventcb', but renaming it would break * backward compatibility */ bufferevent_event_cb errorcb; void *cbarg; struct timeval timeout_read; struct timeval timeout_write; /** Events that are currently enabled: currently EV_READ and EV_WRITE are supported. */ short enabled; }; #ifdef __cplusplus } #endif #endif /* EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/visibility.h0000644000076400001440000000546714111362573022406 0ustar00bernatusers00000000000000/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_VISIBILITY_H_INCLUDED_ #define EVENT2_VISIBILITY_H_INCLUDED_ #include #if defined(event_shared_EXPORTS) || \ defined(event_extra_shared_EXPORTS) || \ defined(event_core_shared_EXPORTS) || \ defined(event_pthreads_shared_EXPORTS) || \ defined(event_openssl_shared_EXPORTS) # if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550) # define EVENT2_EXPORT_SYMBOL __global # elif defined __GNUC__ # define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default"))) # elif defined(_MSC_VER) # define EVENT2_EXPORT_SYMBOL __declspec(dllexport) # else # define EVENT2_EXPORT_SYMBOL /* unknown compiler */ # endif #else /* event_*_EXPORTS */ # define EVENT2_EXPORT_SYMBOL #endif /* event_*_EXPORTS */ /** We need to dllimport event_debug_logging_mask_ into event_extra */ #if defined(_MSC_VER) # if defined(event_core_shared_EXPORTS) /** from core export */ # define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllexport) # elif defined(event_extra_shared_EXPORTS) || /** from extra import */ \ defined(EVENT_VISIBILITY_WANT_DLLIMPORT) # define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllimport) # endif #endif /* _MSC_VER */ #if !defined(EVENT2_CORE_EXPORT_SYMBOL) # define EVENT2_CORE_EXPORT_SYMBOL EVENT2_EXPORT_SYMBOL #endif #endif /* EVENT2_VISIBILITY_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/keyvalq_struct.h0000644000076400001440000000505314111362573023266 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ #define EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif /* Fix so that people don't have to run with */ /* XXXX This code is duplicated with event_struct.h */ #ifndef TAILQ_ENTRY #define EVENT_DEFINED_TQENTRY_ #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } #endif /* !TAILQ_ENTRY */ #ifndef TAILQ_HEAD #define EVENT_DEFINED_TQHEAD_ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; \ struct type **tqh_last; \ } #endif /* * Key-Value pairs. Can be used for HTTP headers but also for * query argument parsing. */ struct evkeyval { TAILQ_ENTRY(evkeyval) next; char *key; char *value; }; TAILQ_HEAD (evkeyvalq, evkeyval); /* XXXX This code is duplicated with event_struct.h */ #ifdef EVENT_DEFINED_TQENTRY_ #undef TAILQ_ENTRY #endif #ifdef EVENT_DEFINED_TQHEAD_ #undef TAILQ_HEAD #endif #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/include/event2/event_compat.h0000644000076400001440000001672714111362573022704 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_EVENT_COMPAT_H_INCLUDED_ #define EVENT2_EVENT_COMPAT_H_INCLUDED_ /** @file event2/event_compat.h Potentially non-threadsafe versions of the functions in event.h: provided only for backwards compatibility. In the oldest versions of Libevent, event_base was not a first-class structure. Instead, there was a single event base that every function manipulated. Later, when separate event bases were added, the old functions that didn't take an event_base argument needed to work by manipulating the "current" event base. This could lead to thread-safety issues, and obscure, hard-to-diagnose bugs. @deprecated All functions in this file are by definition deprecated. */ #include #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /** Initialize the event API. The event API needs to be initialized with event_init() before it can be used. Sets the global current base that gets used for events that have no base associated with them. @deprecated This function is deprecated because it replaces the "current" event_base, and is totally unsafe for multithreaded use. The replacement is event_base_new(). @see event_base_set(), event_base_new() */ EVENT2_EXPORT_SYMBOL struct event_base *event_init(void); /** Loop to process events. Like event_base_dispatch(), but uses the "current" base. @deprecated This function is deprecated because it is easily confused by multiple calls to event_init(), and because it is not safe for multithreaded use. The replacement is event_base_dispatch(). @see event_base_dispatch(), event_init() */ EVENT2_EXPORT_SYMBOL int event_dispatch(void); /** Handle events. This function behaves like event_base_loop(), but uses the "current" base @deprecated This function is deprecated because it uses the event base from the last call to event_init, and is therefore not safe for multithreaded use. The replacement is event_base_loop(). @see event_base_loop(), event_init() */ EVENT2_EXPORT_SYMBOL int event_loop(int); /** Exit the event loop after the specified time. This function behaves like event_base_loopexit(), except that it uses the "current" base. @deprecated This function is deprecated because it uses the event base from the last call to event_init, and is therefore not safe for multithreaded use. The replacement is event_base_loopexit(). @see event_init, event_base_loopexit() */ EVENT2_EXPORT_SYMBOL int event_loopexit(const struct timeval *); /** Abort the active event_loop() immediately. This function behaves like event_base_loopbreakt(), except that it uses the "current" base. @deprecated This function is deprecated because it uses the event base from the last call to event_init, and is therefore not safe for multithreaded use. The replacement is event_base_loopbreak(). @see event_base_loopbreak(), event_init() */ EVENT2_EXPORT_SYMBOL int event_loopbreak(void); /** Schedule a one-time event to occur. @deprecated This function is obsolete, and has been replaced by event_base_once(). Its use is deprecated because it relies on the "current" base configured by event_init(). @see event_base_once() */ EVENT2_EXPORT_SYMBOL int event_once(evutil_socket_t , short, void (*)(evutil_socket_t, short, void *), void *, const struct timeval *); /** Get the kernel event notification mechanism used by Libevent. @deprecated This function is obsolete, and has been replaced by event_base_get_method(). Its use is deprecated because it relies on the "current" base configured by event_init(). @see event_base_get_method() */ EVENT2_EXPORT_SYMBOL const char *event_get_method(void); /** Set the number of different event priorities. @deprecated This function is deprecated because it is easily confused by multiple calls to event_init(), and because it is not safe for multithreaded use. The replacement is event_base_priority_init(). @see event_base_priority_init() */ EVENT2_EXPORT_SYMBOL int event_priority_init(int); /** Prepare an event structure to be added. @deprecated event_set() is not recommended for new code, because it requires a subsequent call to event_base_set() to be safe under most circumstances. Use event_assign() or event_new() instead. */ EVENT2_EXPORT_SYMBOL void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *); #define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) #define evsignal_set(ev, x, cb, arg) \ event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) /** @name timeout_* macros @deprecated These macros are deprecated because their naming is inconsistent with the rest of Libevent. Use the evtimer_* macros instead. @{ */ #define timeout_add(ev, tv) event_add((ev), (tv)) #define timeout_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) #define timeout_del(ev) event_del(ev) #define timeout_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) #define timeout_initialized(ev) event_initialized(ev) /**@}*/ /** @name signal_* macros @deprecated These macros are deprecated because their naming is inconsistent with the rest of Libevent. Use the evsignal_* macros instead. @{ */ #define signal_add(ev, tv) event_add((ev), (tv)) #define signal_set(ev, x, cb, arg) \ event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) #define signal_del(ev) event_del(ev) #define signal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) #define signal_initialized(ev) event_initialized(ev) /**@}*/ #ifndef EVENT_FD /* These macros are obsolete; use event_get_fd and event_get_signal instead. */ #define EVENT_FD(ev) ((int)event_get_fd(ev)) #define EVENT_SIGNAL(ev) event_get_signal(ev) #endif #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/tag_compat.h0000644000076400001440000000413514111362573022324 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_TAG_COMPAT_H_INCLUDED_ #define EVENT2_TAG_COMPAT_H_INCLUDED_ /** @file event2/tag_compat.h Obsolete/deprecated functions from tag.h; provided only for backwards compatibility. */ /** @name Misnamed functions @deprecated These macros are deprecated because their names don't follow Libevent's naming conventions. Use evtag_encode_int and evtag_encode_int64 instead. @{ */ #define encode_int(evbuf, number) evtag_encode_int((evbuf), (number)) #define encode_int64(evbuf, number) evtag_encode_int64((evbuf), (number)) /**@}*/ #endif /* EVENT2_TAG_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/bufferevent_compat.h0000644000076400001440000001067214111362573024067 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson * Copyright (c) 2000-2007 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ #define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ #include #define evbuffercb bufferevent_data_cb #define everrorcb bufferevent_event_cb /** Create a new bufferevent for an fd. This function is deprecated. Use bufferevent_socket_new and bufferevent_set_callbacks instead. Libevent provides an abstraction on top of the regular event callbacks. This abstraction is called a buffered event. A buffered event provides input and output buffers that get filled and drained automatically. The user of a buffered event no longer deals directly with the I/O, but instead is reading from input and writing to output buffers. Once initialized, the bufferevent structure can be used repeatedly with bufferevent_enable() and bufferevent_disable(). When read enabled the bufferevent will try to read from the file descriptor and call the read callback. The write callback is executed whenever the output buffer is drained below the write low watermark, which is 0 by default. If multiple bases are in use, bufferevent_base_set() must be called before enabling the bufferevent for the first time. @deprecated This function is deprecated because it uses the current event base, and as such can be error prone for multithreaded programs. Use bufferevent_socket_new() instead. @param fd the file descriptor from which data is read and written to. This file descriptor is not allowed to be a pipe(2). @param readcb callback to invoke when there is data to be read, or NULL if no callback is desired @param writecb callback to invoke when the file descriptor is ready for writing, or NULL if no callback is desired @param errorcb callback to invoke when there is an error on the file descriptor @param cbarg an argument that will be supplied to each of the callbacks (readcb, writecb, and errorcb) @return a pointer to a newly allocated bufferevent struct, or NULL if an error occurred @see bufferevent_base_set(), bufferevent_free() */ EVENT2_EXPORT_SYMBOL struct bufferevent *bufferevent_new(evutil_socket_t fd, evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); /** Set the read and write timeout for a buffered event. @param bufev the bufferevent to be modified @param timeout_read the read timeout @param timeout_write the write timeout */ EVENT2_EXPORT_SYMBOL void bufferevent_settimeout(struct bufferevent *bufev, int timeout_read, int timeout_write); #define EVBUFFER_READ BEV_EVENT_READING #define EVBUFFER_WRITE BEV_EVENT_WRITING #define EVBUFFER_EOF BEV_EVENT_EOF #define EVBUFFER_ERROR BEV_EVENT_ERROR #define EVBUFFER_TIMEOUT BEV_EVENT_TIMEOUT /** macro for getting access to the input buffer of a bufferevent */ #define EVBUFFER_INPUT(x) bufferevent_get_input(x) /** macro for getting access to the output buffer of a bufferevent */ #define EVBUFFER_OUTPUT(x) bufferevent_get_output(x) #endif lldpd-1.0.13/libevent/include/event2/buffer.h0000644000076400001440000011442514111362573021463 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFER_H_INCLUDED_ #define EVENT2_BUFFER_H_INCLUDED_ /** @file event2/buffer.h Functions for buffering data for network sending or receiving. An evbuffer can be used for preparing data before sending it to the network or conversely for reading data from the network. Evbuffers try to avoid memory copies as much as possible. As a result, evbuffers can be used to pass data around without actually incurring the overhead of copying the data. A new evbuffer can be allocated with evbuffer_new(), and can be freed with evbuffer_free(). Most users will be using evbuffers via the bufferevent interface. To access a bufferevent's evbuffers, use bufferevent_get_input() and bufferevent_get_output(). There are several guidelines for using evbuffers. - if you already know how much data you are going to add as a result of calling evbuffer_add() multiple times, it makes sense to use evbuffer_expand() first to make sure that enough memory is allocated before hand. - evbuffer_add_buffer() adds the contents of one buffer to the other without incurring any unnecessary memory copies. - evbuffer_add() and evbuffer_add_buffer() do not mix very well: if you use them, you will wind up with fragmented memory in your buffer. - For high-performance code, you may want to avoid copying data into and out of buffers. You can skip the copy step by using evbuffer_reserve_space()/evbuffer_commit_space() when writing into a buffer, and evbuffer_peek() when reading. In Libevent 2.0 and later, evbuffers are represented using a linked list of memory chunks, with pointers to the first and last chunk in the chain. As the contents of an evbuffer can be stored in multiple different memory blocks, it cannot be accessed directly. Instead, evbuffer_pullup() can be used to force a specified number of bytes to be contiguous. This will cause memory reallocation and memory copies if the data is split across multiple blocks. It is more efficient, however, to use evbuffer_peek() if you don't require that the memory to be contiguous. */ #include #ifdef __cplusplus extern "C" { #endif #include #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_UIO_H #include #endif #include /** An evbuffer is an opaque data type for efficiently buffering data to be sent or received on the network. @see event2/event.h for more information */ struct evbuffer #ifdef EVENT_IN_DOXYGEN_ {} #endif ; /** Pointer to a position within an evbuffer. Used when repeatedly searching through a buffer. Calling any function that modifies or re-packs the buffer contents may invalidate all evbuffer_ptrs for that buffer. Do not modify or contruct these values except with evbuffer_ptr_set. An evbuffer_ptr can represent any position from the start of a buffer up to a position immediately after the end of a buffer. @see evbuffer_ptr_set() */ struct evbuffer_ptr { ev_ssize_t pos; /* Do not alter or rely on the values of fields: they are for internal * use */ struct { void *chain; size_t pos_in_chain; } internal_; }; /** Describes a single extent of memory inside an evbuffer. Used for direct-access functions. @see evbuffer_reserve_space, evbuffer_commit_space, evbuffer_peek */ #ifdef EVENT__HAVE_SYS_UIO_H #define evbuffer_iovec iovec /* Internal use -- defined only if we are using the native struct iovec */ #define EVBUFFER_IOVEC_IS_NATIVE_ #else struct evbuffer_iovec { /** The start of the extent of memory. */ void *iov_base; /** The length of the extent of memory. */ size_t iov_len; }; #endif /** Allocate storage for a new evbuffer. @return a pointer to a newly allocated evbuffer struct, or NULL if an error occurred */ EVENT2_EXPORT_SYMBOL struct evbuffer *evbuffer_new(void); /** Deallocate storage for an evbuffer. @param buf pointer to the evbuffer to be freed */ EVENT2_EXPORT_SYMBOL void evbuffer_free(struct evbuffer *buf); /** Enable locking on an evbuffer so that it can safely be used by multiple threads at the same time. NOTE: when locking is enabled, the lock will be held when callbacks are invoked. This could result in deadlock if you aren't careful. Plan accordingly! @param buf An evbuffer to make lockable. @param lock A lock object, or NULL if we should allocate our own. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_enable_locking(struct evbuffer *buf, void *lock); /** Acquire the lock on an evbuffer. Has no effect if locking was not enabled with evbuffer_enable_locking. */ EVENT2_EXPORT_SYMBOL void evbuffer_lock(struct evbuffer *buf); /** Release the lock on an evbuffer. Has no effect if locking was not enabled with evbuffer_enable_locking. */ EVENT2_EXPORT_SYMBOL void evbuffer_unlock(struct evbuffer *buf); /** If this flag is set, then we will not use evbuffer_peek(), * evbuffer_remove(), evbuffer_remove_buffer(), and so on to read bytes * from this buffer: we'll only take bytes out of this buffer by * writing them to the network (as with evbuffer_write_atmost), by * removing them without observing them (as with evbuffer_drain), * or by copying them all out at once (as with evbuffer_add_buffer). * * Using this option allows the implementation to use sendfile-based * operations for evbuffer_add_file(); see that function for more * information. * * This flag is on by default for bufferevents that can take advantage * of it; you should never actually need to set it on a bufferevent's * output buffer. */ #define EVBUFFER_FLAG_DRAINS_TO_FD 1 /** Change the flags that are set for an evbuffer by adding more. * * @param buffer the evbuffer that the callback is watching. * @param cb the callback whose status we want to change. * @param flags One or more EVBUFFER_FLAG_* options * @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags); /** Change the flags that are set for an evbuffer by removing some. * * @param buffer the evbuffer that the callback is watching. * @param cb the callback whose status we want to change. * @param flags One or more EVBUFFER_FLAG_* options * @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags); /** Returns the total number of bytes stored in the evbuffer @param buf pointer to the evbuffer @return the number of bytes stored in the evbuffer */ EVENT2_EXPORT_SYMBOL size_t evbuffer_get_length(const struct evbuffer *buf); /** Returns the number of contiguous available bytes in the first buffer chain. This is useful when processing data that might be split into multiple chains, or that might all be in the first chain. Calls to evbuffer_pullup() that cause reallocation and copying of data can thus be avoided. @param buf pointer to the evbuffer @return 0 if no data is available, otherwise the number of available bytes in the first buffer chain. */ EVENT2_EXPORT_SYMBOL size_t evbuffer_get_contiguous_space(const struct evbuffer *buf); /** Expands the available space in an evbuffer. Expands the available space in the evbuffer to at least datlen, so that appending datlen additional bytes will not require any new allocations. @param buf the evbuffer to be expanded @param datlen the new minimum length requirement @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evbuffer_expand(struct evbuffer *buf, size_t datlen); /** Reserves space in the last chain or chains of an evbuffer. Makes space available in the last chain or chains of an evbuffer that can be arbitrarily written to by a user. The space does not become available for reading until it has been committed with evbuffer_commit_space(). The space is made available as one or more extents, represented by an initial pointer and a length. You can force the memory to be available as only one extent. Allowing more extents, however, makes the function more efficient. Multiple subsequent calls to this function will make the same space available until evbuffer_commit_space() has been called. It is an error to do anything that moves around the buffer's internal memory structures before committing the space. NOTE: The code currently does not ever use more than two extents. This may change in future versions. @param buf the evbuffer in which to reserve space. @param size how much space to make available, at minimum. The total length of the extents may be greater than the requested length. @param vec an array of one or more evbuffer_iovec structures to hold pointers to the reserved extents of memory. @param n_vec The length of the vec array. Must be at least 1; 2 is more efficient. @return the number of provided extents, or -1 on error. @see evbuffer_commit_space() */ EVENT2_EXPORT_SYMBOL int evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size, struct evbuffer_iovec *vec, int n_vec); /** Commits previously reserved space. Commits some of the space previously reserved with evbuffer_reserve_space(). It then becomes available for reading. This function may return an error if the pointer in the extents do not match those returned from evbuffer_reserve_space, or if data has been added to the buffer since the space was reserved. If you want to commit less data than you got reserved space for, modify the iov_len pointer of the appropriate extent to a smaller value. Note that you may have received more space than you requested if it was available! @param buf the evbuffer in which to reserve space. @param vec one or two extents returned by evbuffer_reserve_space. @param n_vecs the number of extents. @return 0 on success, -1 on error @see evbuffer_reserve_space() */ EVENT2_EXPORT_SYMBOL int evbuffer_commit_space(struct evbuffer *buf, struct evbuffer_iovec *vec, int n_vecs); /** Append data to the end of an evbuffer. @param buf the evbuffer to be appended to @param data pointer to the beginning of the data buffer @param datlen the number of bytes to be copied from the data buffer @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen); /** Read data from an evbuffer and drain the bytes read. If more bytes are requested than are available in the evbuffer, we only extract as many bytes as were available. @param buf the evbuffer to be read from @param data the destination buffer to store the result @param datlen the maximum size of the destination buffer @return the number of bytes read, or -1 if we can't drain the buffer. */ EVENT2_EXPORT_SYMBOL int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen); /** Read data from an evbuffer, and leave the buffer unchanged. If more bytes are requested than are available in the evbuffer, we only extract as many bytes as were available. @param buf the evbuffer to be read from @param data_out the destination buffer to store the result @param datlen the maximum size of the destination buffer @return the number of bytes read, or -1 if we can't drain the buffer. */ EVENT2_EXPORT_SYMBOL ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen); /** Read data from the middle of an evbuffer, and leave the buffer unchanged. If more bytes are requested than are available in the evbuffer, we only extract as many bytes as were available. @param buf the evbuffer to be read from @param pos the position to start reading from @param data_out the destination buffer to store the result @param datlen the maximum size of the destination buffer @return the number of bytes read, or -1 if we can't drain the buffer. */ EVENT2_EXPORT_SYMBOL ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos, void *data_out, size_t datlen); /** Read data from an evbuffer into another evbuffer, draining the bytes from the source buffer. This function avoids copy operations to the extent possible. If more bytes are requested than are available in src, the src buffer is drained completely. @param src the evbuffer to be read from @param dst the destination evbuffer to store the result into @param datlen the maximum numbers of bytes to transfer @return the number of bytes read */ EVENT2_EXPORT_SYMBOL int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst, size_t datlen); /** Used to tell evbuffer_readln what kind of line-ending to look for. */ enum evbuffer_eol_style { /** Any sequence of CR and LF characters is acceptable as an * EOL. * * Note that this style can produce ambiguous results: the * sequence "CRLF" will be treated as a single EOL if it is * all in the buffer at once, but if you first read a CR from * the network and later read an LF from the network, it will * be treated as two EOLs. */ EVBUFFER_EOL_ANY, /** An EOL is an LF, optionally preceded by a CR. This style is * most useful for implementing text-based internet protocols. */ EVBUFFER_EOL_CRLF, /** An EOL is a CR followed by an LF. */ EVBUFFER_EOL_CRLF_STRICT, /** An EOL is a LF. */ EVBUFFER_EOL_LF, /** An EOL is a NUL character (that is, a single byte with value 0) */ EVBUFFER_EOL_NUL }; /** * Read a single line from an evbuffer. * * Reads a line terminated by an EOL as determined by the evbuffer_eol_style * argument. Returns a newly allocated nul-terminated string; the caller must * free the returned value. The EOL is not included in the returned string. * * @param buffer the evbuffer to read from * @param n_read_out if non-NULL, points to a size_t that is set to the * number of characters in the returned string. This is useful for * strings that can contain NUL characters. * @param eol_style the style of line-ending to use. * @return pointer to a single line, or NULL if an error occurred */ EVENT2_EXPORT_SYMBOL char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out, enum evbuffer_eol_style eol_style); /** Move all data from one evbuffer into another evbuffer. This is a destructive add. The data from one buffer moves into the other buffer. However, no unnecessary memory copies occur. @param outbuf the output buffer @param inbuf the input buffer @return 0 if successful, or -1 if an error occurred @see evbuffer_remove_buffer() */ EVENT2_EXPORT_SYMBOL int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf); /** Copy data from one evbuffer into another evbuffer. This is a non-destructive add. The data from one buffer is copied into the other buffer. However, no unnecessary memory copies occur. Note that buffers already containing buffer references can't be added to other buffers. @param outbuf the output buffer @param inbuf the input buffer @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf); /** A cleanup function for a piece of memory added to an evbuffer by reference. @see evbuffer_add_reference() */ typedef void (*evbuffer_ref_cleanup_cb)(const void *data, size_t datalen, void *extra); /** Reference memory into an evbuffer without copying. The memory needs to remain valid until all the added data has been read. This function keeps just a reference to the memory without actually incurring the overhead of a copy. @param outbuf the output buffer @param data the memory to reference @param datlen how memory to reference @param cleanupfn callback to be invoked when the memory is no longer referenced by this evbuffer. @param cleanupfn_arg optional argument to the cleanup callback @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evbuffer_add_reference(struct evbuffer *outbuf, const void *data, size_t datlen, evbuffer_ref_cleanup_cb cleanupfn, void *cleanupfn_arg); /** Copy data from a file into the evbuffer for writing to a socket. This function avoids unnecessary data copies between userland and kernel. If sendfile is available and the EVBUFFER_FLAG_DRAINS_TO_FD flag is set, it uses those functions. Otherwise, it tries to use mmap (or CreateFileMapping on Windows). The function owns the resulting file descriptor and will close it when finished transferring data. The results of using evbuffer_remove() or evbuffer_pullup() on evbuffers whose data was added using this function are undefined. For more fine-grained control, use evbuffer_add_file_segment. @param outbuf the output buffer @param fd the file descriptor @param offset the offset from which to read data @param length how much data to read, or -1 to read as much as possible. (-1 requires that 'fd' support fstat.) @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset, ev_off_t length); /** An evbuffer_file_segment holds a reference to a range of a file -- possibly the whole file! -- for use in writing from an evbuffer to a socket. It could be implemented with mmap, sendfile, splice, or (if all else fails) by just pulling all the data into RAM. A single evbuffer_file_segment can be added more than once, and to more than one evbuffer. */ struct evbuffer_file_segment; /** Flag for creating evbuffer_file_segment: If this flag is set, then when the evbuffer_file_segment is freed and no longer in use by any evbuffer, the underlying fd is closed. */ #define EVBUF_FS_CLOSE_ON_FREE 0x01 /** Flag for creating evbuffer_file_segment: Disable memory-map based implementations. */ #define EVBUF_FS_DISABLE_MMAP 0x02 /** Flag for creating evbuffer_file_segment: Disable direct fd-to-fd implementations (including sendfile and splice). You might want to use this option if data needs to be taken from the evbuffer by any means other than writing it to the network: the sendfile backend is fast, but it only works for sending files directly to the network. */ #define EVBUF_FS_DISABLE_SENDFILE 0x04 /** Flag for creating evbuffer_file_segment: Do not allocate a lock for this segment. If this option is set, then neither the segment nor any evbuffer it is added to may ever be accessed from more than one thread at a time. */ #define EVBUF_FS_DISABLE_LOCKING 0x08 /** A cleanup function for a evbuffer_file_segment added to an evbuffer for reference. */ typedef void (*evbuffer_file_segment_cleanup_cb)( struct evbuffer_file_segment const* seg, int flags, void* arg); /** Create and return a new evbuffer_file_segment for reading data from a file and sending it out via an evbuffer. This function avoids unnecessary data copies between userland and kernel. Where available, it uses sendfile or splice. The file descriptor must not be closed so long as any evbuffer is using this segment. The results of using evbuffer_remove() or evbuffer_pullup() or any other function that reads bytes from an evbuffer on any evbuffer containing the newly returned segment are undefined, unless you pass the EVBUF_FS_DISABLE_SENDFILE flag to this function. @param fd an open file to read from. @param offset an index within the file at which to start reading @param length how much data to read, or -1 to read as much as possible. (-1 requires that 'fd' support fstat.) @param flags any number of the EVBUF_FS_* flags @return a new evbuffer_file_segment, or NULL on failure. **/ EVENT2_EXPORT_SYMBOL struct evbuffer_file_segment *evbuffer_file_segment_new( int fd, ev_off_t offset, ev_off_t length, unsigned flags); /** Free an evbuffer_file_segment It is safe to call this function even if the segment has been added to one or more evbuffers. The evbuffer_file_segment will not be freed until no more references to it exist. */ EVENT2_EXPORT_SYMBOL void evbuffer_file_segment_free(struct evbuffer_file_segment *seg); /** Add cleanup callback and argument for the callback to an evbuffer_file_segment. The cleanup callback will be invoked when no more references to the evbuffer_file_segment exist. **/ EVENT2_EXPORT_SYMBOL void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg, evbuffer_file_segment_cleanup_cb cb, void* arg); /** Insert some or all of an evbuffer_file_segment at the end of an evbuffer Note that the offset and length parameters of this function have a different meaning from those provided to evbuffer_file_segment_new: When you create the segment, the offset is the offset _within the file_, and the length is the length _of the segment_, whereas when you add a segment to an evbuffer, the offset is _within the segment_ and the length is the length of the _part of the segment you want to use. In other words, if you have a 10 KiB file, and you create an evbuffer_file_segment for it with offset 20 and length 1000, it will refer to bytes 20..1019 inclusive. If you then pass this segment to evbuffer_add_file_segment and specify an offset of 20 and a length of 50, you will be adding bytes 40..99 inclusive. @param buf the evbuffer to append to @param seg the segment to add @param offset the offset within the segment to start from @param length the amount of data to add, or -1 to add it all. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_add_file_segment(struct evbuffer *buf, struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length); /** Append a formatted string to the end of an evbuffer. The string is formated as printf. @param buf the evbuffer that will be appended to @param fmt a format string @param ... arguments that will be passed to printf(3) @return The number of bytes added if successful, or -1 if an error occurred. @see evutil_printf(), evbuffer_add_vprintf() */ EVENT2_EXPORT_SYMBOL int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 2, 3))) #endif ; /** Append a va_list formatted string to the end of an evbuffer. @param buf the evbuffer that will be appended to @param fmt a format string @param ap a varargs va_list argument array that will be passed to vprintf(3) @return The number of bytes added if successful, or -1 if an error occurred. */ EVENT2_EXPORT_SYMBOL int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) #ifdef __GNUC__ __attribute__((format(printf, 2, 0))) #endif ; /** Remove a specified number of bytes data from the beginning of an evbuffer. @param buf the evbuffer to be drained @param len the number of bytes to drain from the beginning of the buffer @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_drain(struct evbuffer *buf, size_t len); /** Write the contents of an evbuffer to a file descriptor. The evbuffer will be drained after the bytes have been successfully written. @param buffer the evbuffer to be written and drained @param fd the file descriptor to be written to @return the number of bytes written, or -1 if an error occurred @see evbuffer_read() */ EVENT2_EXPORT_SYMBOL int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd); /** Write some of the contents of an evbuffer to a file descriptor. The evbuffer will be drained after the bytes have been successfully written. @param buffer the evbuffer to be written and drained @param fd the file descriptor to be written to @param howmuch the largest allowable number of bytes to write, or -1 to write as many bytes as we can. @return the number of bytes written, or -1 if an error occurred @see evbuffer_read() */ EVENT2_EXPORT_SYMBOL int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd, ev_ssize_t howmuch); /** Read from a file descriptor and store the result in an evbuffer. @param buffer the evbuffer to store the result @param fd the file descriptor to read from @param howmuch the number of bytes to be read. If the given number is negative or out of maximum bytes per one read, as many bytes as we can will be read. @return the number of bytes read, or -1 if an error occurred @see evbuffer_write() */ EVENT2_EXPORT_SYMBOL int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch); /** Search for a string within an evbuffer. @param buffer the evbuffer to be searched @param what the string to be searched for @param len the length of the search string @param start NULL or a pointer to a valid struct evbuffer_ptr. @return a struct evbuffer_ptr whose 'pos' field has the offset of the first occurrence of the string in the buffer after 'start'. The 'pos' field of the result is -1 if the string was not found. */ EVENT2_EXPORT_SYMBOL struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start); /** Search for a string within part of an evbuffer. @param buffer the evbuffer to be searched @param what the string to be searched for @param len the length of the search string @param start NULL or a pointer to a valid struct evbuffer_ptr that indicates where we should start searching. @param end NULL or a pointer to a valid struct evbuffer_ptr that indicates where we should stop searching. @return a struct evbuffer_ptr whose 'pos' field has the offset of the first occurrence of the string in the buffer after 'start'. The 'pos' field of the result is -1 if the string was not found. */ EVENT2_EXPORT_SYMBOL struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end); /** Defines how to adjust an evbuffer_ptr by evbuffer_ptr_set() @see evbuffer_ptr_set() */ enum evbuffer_ptr_how { /** Sets the pointer to the position; can be called on with an uninitialized evbuffer_ptr. */ EVBUFFER_PTR_SET, /** Advances the pointer by adding to the current position. */ EVBUFFER_PTR_ADD }; /** Sets the search pointer in the buffer to position. There are two ways to use this function: you can call evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET) to move 'pos' to a position 'N' bytes after the start of the buffer, or evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_ADD) to move 'pos' forward by 'N' bytes. If evbuffer_ptr is not initialized, this function can only be called with EVBUFFER_PTR_SET. An evbuffer_ptr can represent any position from the start of the buffer to a position immediately after the end of the buffer. @param buffer the evbuffer to be search @param ptr a pointer to a struct evbuffer_ptr @param position the position at which to start the next search @param how determines how the pointer should be manipulated. @returns 0 on success or -1 otherwise */ EVENT2_EXPORT_SYMBOL int evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr, size_t position, enum evbuffer_ptr_how how); /** Search for an end-of-line string within an evbuffer. @param buffer the evbuffer to be searched @param start NULL or a pointer to a valid struct evbuffer_ptr to start searching at. @param eol_len_out If non-NULL, the pointed-to value will be set to the length of the end-of-line string. @param eol_style The kind of EOL to look for; see evbuffer_readln() for more information @return a struct evbuffer_ptr whose 'pos' field has the offset of the first occurrence EOL in the buffer after 'start'. The 'pos' field of the result is -1 if the string was not found. */ EVENT2_EXPORT_SYMBOL struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer, struct evbuffer_ptr *start, size_t *eol_len_out, enum evbuffer_eol_style eol_style); /** Function to peek at data inside an evbuffer without removing it or copying it out. Pointers to the data are returned by filling the 'vec_out' array with pointers to one or more extents of data inside the buffer. The total data in the extents that you get back may be more than you requested (if there is more data last extent than you asked for), or less (if you do not provide enough evbuffer_iovecs, or if the buffer does not have as much data as you asked to see). @param buffer the evbuffer to peek into, @param len the number of bytes to try to peek. If len is negative, we will try to fill as much of vec_out as we can. If len is negative and vec_out is not provided, we return the number of evbuffer_iovecs that would be needed to get all the data in the buffer. @param start_at an evbuffer_ptr indicating the point at which we should start looking for data. NULL means, "At the start of the buffer." @param vec_out an array of evbuffer_iovec @param n_vec the length of vec_out. If 0, we only count how many extents would be necessary to point to the requested amount of data. @return The number of extents needed. This may be less than n_vec if we didn't need all the evbuffer_iovecs we were given, or more than n_vec if we would need more to return all the data that was requested. */ EVENT2_EXPORT_SYMBOL int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len, struct evbuffer_ptr *start_at, struct evbuffer_iovec *vec_out, int n_vec); /** Structure passed to an evbuffer_cb_func evbuffer callback @see evbuffer_cb_func, evbuffer_add_cb() */ struct evbuffer_cb_info { /** The number of bytes in this evbuffer when callbacks were last * invoked. */ size_t orig_size; /** The number of bytes added since callbacks were last invoked. */ size_t n_added; /** The number of bytes removed since callbacks were last invoked. */ size_t n_deleted; }; /** Type definition for a callback that is invoked whenever data is added or removed from an evbuffer. An evbuffer may have one or more callbacks set at a time. The order in which they are executed is undefined. A callback function may add more callbacks, or remove itself from the list of callbacks, or add or remove data from the buffer. It may not remove another callback from the list. If a callback adds or removes data from the buffer or from another buffer, this can cause a recursive invocation of your callback or other callbacks. If you ask for an infinite loop, you might just get one: watch out! @param buffer the buffer whose size has changed @param info a structure describing how the buffer changed. @param arg a pointer to user data */ typedef void (*evbuffer_cb_func)(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg); struct evbuffer_cb_entry; /** Add a new callback to an evbuffer. Subsequent calls to evbuffer_add_cb() add new callbacks. To remove this callback, call evbuffer_remove_cb or evbuffer_remove_cb_entry. @param buffer the evbuffer to be monitored @param cb the callback function to invoke when the evbuffer is modified, or NULL to remove all callbacks. @param cbarg an argument to be provided to the callback function @return a handle to the callback on success, or NULL on failure. */ EVENT2_EXPORT_SYMBOL struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); /** Remove a callback from an evbuffer, given a handle returned from evbuffer_add_cb. Calling this function invalidates the handle. @return 0 if a callback was removed, or -1 if no matching callback was found. */ EVENT2_EXPORT_SYMBOL int evbuffer_remove_cb_entry(struct evbuffer *buffer, struct evbuffer_cb_entry *ent); /** Remove a callback from an evbuffer, given the function and argument used to add it. @return 0 if a callback was removed, or -1 if no matching callback was found. */ EVENT2_EXPORT_SYMBOL int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); /** If this flag is not set, then a callback is temporarily disabled, and * should not be invoked. * * @see evbuffer_cb_set_flags(), evbuffer_cb_clear_flags() */ #define EVBUFFER_CB_ENABLED 1 /** Change the flags that are set for a callback on a buffer by adding more. @param buffer the evbuffer that the callback is watching. @param cb the callback whose status we want to change. @param flags EVBUFFER_CB_ENABLED to re-enable the callback. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_cb_set_flags(struct evbuffer *buffer, struct evbuffer_cb_entry *cb, ev_uint32_t flags); /** Change the flags that are set for a callback on a buffer by removing some @param buffer the evbuffer that the callback is watching. @param cb the callback whose status we want to change. @param flags EVBUFFER_CB_ENABLED to disable the callback. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_cb_clear_flags(struct evbuffer *buffer, struct evbuffer_cb_entry *cb, ev_uint32_t flags); #if 0 /** Postpone calling a given callback until unsuspend is called later. This is different from disabling the callback, since the callback will get invoked later if the buffer size changes between now and when we unsuspend it. @param the buffer that the callback is watching. @param cb the callback we want to suspend. */ EVENT2_EXPORT_SYMBOL void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); /** Stop postponing a callback that we postponed with evbuffer_cb_suspend. If data was added to or removed from the buffer while the callback was suspended, the callback will get called once now. @param the buffer that the callback is watching. @param cb the callback we want to stop suspending. */ EVENT2_EXPORT_SYMBOL void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); #endif /** Makes the data at the beginning of an evbuffer contiguous. @param buf the evbuffer to make contiguous @param size the number of bytes to make contiguous, or -1 to make the entire buffer contiguous. @return a pointer to the contiguous memory array, or NULL if param size requested more data than is present in the buffer. */ EVENT2_EXPORT_SYMBOL unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size); /** Prepends data to the beginning of the evbuffer @param buf the evbuffer to which to prepend data @param data a pointer to the memory to prepend @param size the number of bytes to prepend @return 0 if successful, or -1 otherwise */ EVENT2_EXPORT_SYMBOL int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size); /** Prepends all data from the src evbuffer to the beginning of the dst evbuffer. @param dst the evbuffer to which to prepend data @param src the evbuffer to prepend; it will be emptied as a result @return 0 if successful, or -1 otherwise */ EVENT2_EXPORT_SYMBOL int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src); /** Prevent calls that modify an evbuffer from succeeding. A buffer may frozen at the front, at the back, or at both the front and the back. If the front of a buffer is frozen, operations that drain data from the front of the buffer, or that prepend data to the buffer, will fail until it is unfrozen. If the back a buffer is frozen, operations that append data from the buffer will fail until it is unfrozen. @param buf The buffer to freeze @param at_front If true, we freeze the front of the buffer. If false, we freeze the back. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_freeze(struct evbuffer *buf, int at_front); /** Re-enable calls that modify an evbuffer. @param buf The buffer to un-freeze @param at_front If true, we unfreeze the front of the buffer. If false, we unfreeze the back. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evbuffer_unfreeze(struct evbuffer *buf, int at_front); struct event_base; /** Force all the callbacks on an evbuffer to be run, not immediately after the evbuffer is altered, but instead from inside the event loop. This can be used to serialize all the callbacks to a single thread of execution. */ EVENT2_EXPORT_SYMBOL int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base); /** Append data from 1 or more iovec's to an evbuffer Calculates the number of bytes needed for an iovec structure and guarantees all data will fit into a single chain. Can be used in lieu of functionality which calls evbuffer_add() constantly before being used to increase performance. @param buffer the destination buffer @param vec the source iovec @param n_vec the number of iovec structures. @return the number of bytes successfully written to the output buffer. */ EVENT2_EXPORT_SYMBOL size_t evbuffer_add_iovec(struct evbuffer * buffer, struct evbuffer_iovec * vec, int n_vec); #ifdef __cplusplus } #endif #endif /* EVENT2_BUFFER_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/dns_struct.h0000644000076400001440000000504414111362573022376 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_DNS_STRUCT_H_INCLUDED_ #define EVENT2_DNS_STRUCT_H_INCLUDED_ /** @file event2/dns_struct.h Data structures for dns. Using these structures may hurt forward compatibility with later versions of Libevent: be careful! */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /* * Structures used to implement a DNS server. */ struct evdns_server_request { int flags; int nquestions; struct evdns_server_question **questions; }; struct evdns_server_question { int type; #ifdef __cplusplus int dns_question_class; #else /* You should refer to this field as "dns_question_class". The * name "class" works in C for backward compatibility, and will be * removed in a future version. (1.5 or later). */ int class; #define dns_question_class class #endif char name[1]; }; #ifdef __cplusplus } #endif #endif /* EVENT2_DNS_STRUCT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/bufferevent_ssl.h0000644000076400001440000001136014111362573023400 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ #define EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ /** @file event2/bufferevent_ssl.h OpenSSL support for bufferevents. */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* This is what openssl's SSL objects are underneath. */ struct ssl_st; /** The state of an SSL object to be used when creating a new SSL bufferevent. */ enum bufferevent_ssl_state { BUFFEREVENT_SSL_OPEN = 0, BUFFEREVENT_SSL_CONNECTING = 1, BUFFEREVENT_SSL_ACCEPTING = 2 }; #if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_) /** Create a new SSL bufferevent to send its data over another bufferevent. @param base An event_base to use to detect reading and writing. It must also be the base for the underlying bufferevent. @param underlying A socket to use for this SSL @param ssl A SSL* object from openssl. @param state The current state of the SSL connection @param options One or more bufferevent_options @return A new bufferevent on success, or NULL on failure */ EVENT2_EXPORT_SYMBOL struct bufferevent * bufferevent_openssl_filter_new(struct event_base *base, struct bufferevent *underlying, struct ssl_st *ssl, enum bufferevent_ssl_state state, int options); /** Create a new SSL bufferevent to send its data over an SSL * on a socket. @param base An event_base to use to detect reading and writing @param fd A socket to use for this SSL @param ssl A SSL* object from openssl. @param state The current state of the SSL connection @param options One or more bufferevent_options @return A new bufferevent on success, or NULL on failure. */ EVENT2_EXPORT_SYMBOL struct bufferevent * bufferevent_openssl_socket_new(struct event_base *base, evutil_socket_t fd, struct ssl_st *ssl, enum bufferevent_ssl_state state, int options); /** Control how to report dirty SSL shutdowns. If the peer (or the network, or an attacker) closes the TCP connection before closing the SSL channel, and the protocol is SSL >= v3, this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default), this is reported as BEV_EVENT_ERROR. If instead allow_dirty_shutdown=1, a dirty shutdown is reported as BEV_EVENT_EOF. (Note that if the protocol is < SSLv3, you will always receive BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure connection close from a dirty one. This is one reason (among many) not to use SSL 2.) */ EVENT2_EXPORT_SYMBOL int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev); EVENT2_EXPORT_SYMBOL void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev, int allow_dirty_shutdown); /** Return the underlying openssl SSL * object for an SSL bufferevent. */ EVENT2_EXPORT_SYMBOL struct ssl_st * bufferevent_openssl_get_ssl(struct bufferevent *bufev); /** Tells a bufferevent to begin SSL renegotiation. */ EVENT2_EXPORT_SYMBOL int bufferevent_ssl_renegotiate(struct bufferevent *bev); /** Return the most recent OpenSSL error reported on an SSL bufferevent. */ EVENT2_EXPORT_SYMBOL unsigned long bufferevent_get_openssl_error(struct bufferevent *bev); #endif #ifdef __cplusplus } #endif #endif /* EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/util.h0000644000076400001440000007135414111362573021172 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_UTIL_H_INCLUDED_ #define EVENT2_UTIL_H_INCLUDED_ /** @file event2/util.h Common convenience functions for cross-platform portability and related socket manipulations. */ #include #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #ifdef EVENT__HAVE_STDINT_H #include #elif defined(EVENT__HAVE_INTTYPES_H) #include #endif #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_STDDEF_H #include #endif #ifdef _MSC_VER #include #endif #include #ifdef EVENT__HAVE_NETDB_H #include #endif #ifdef _WIN32 #include #ifdef EVENT__HAVE_GETADDRINFO /* for EAI_* definitions. */ #include #endif #else #ifdef EVENT__HAVE_ERRNO_H #include #endif #include #endif #include /* Some openbsd autoconf versions get the name of this macro wrong. */ #if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P) #define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__ #endif /** * @name Standard integer types. * * Integer type definitions for types that are supposed to be defined in the * C99-specified stdint.h. Shamefully, some platforms do not include * stdint.h, so we need to replace it. (If you are on a platform like this, * your C headers are now over 10 years out of date. You should bug them to * do something about this.) * * We define: * *
*
ev_uint64_t, ev_uint32_t, ev_uint16_t, ev_uint8_t
*
unsigned integer types of exactly 64, 32, 16, and 8 bits * respectively.
*
ev_int64_t, ev_int32_t, ev_int16_t, ev_int8_t
*
signed integer types of exactly 64, 32, 16, and 8 bits * respectively.
*
ev_uintptr_t, ev_intptr_t
*
unsigned/signed integers large enough * to hold a pointer without loss of bits.
*
ev_ssize_t
*
A signed type of the same size as size_t
*
ev_off_t
*
A signed type typically used to represent offsets within a * (potentially large) file
* * @{ */ #ifdef EVENT__HAVE_UINT64_T #define ev_uint64_t uint64_t #define ev_int64_t int64_t #elif defined(_WIN32) #define ev_uint64_t unsigned __int64 #define ev_int64_t signed __int64 #elif EVENT__SIZEOF_LONG_LONG == 8 #define ev_uint64_t unsigned long long #define ev_int64_t long long #elif EVENT__SIZEOF_LONG == 8 #define ev_uint64_t unsigned long #define ev_int64_t long #elif defined(EVENT_IN_DOXYGEN_) #define ev_uint64_t ... #define ev_int64_t ... #else #error "No way to define ev_uint64_t" #endif #ifdef EVENT__HAVE_UINT32_T #define ev_uint32_t uint32_t #define ev_int32_t int32_t #elif defined(_WIN32) #define ev_uint32_t unsigned int #define ev_int32_t signed int #elif EVENT__SIZEOF_LONG == 4 #define ev_uint32_t unsigned long #define ev_int32_t signed long #elif EVENT__SIZEOF_INT == 4 #define ev_uint32_t unsigned int #define ev_int32_t signed int #elif defined(EVENT_IN_DOXYGEN_) #define ev_uint32_t ... #define ev_int32_t ... #else #error "No way to define ev_uint32_t" #endif #ifdef EVENT__HAVE_UINT16_T #define ev_uint16_t uint16_t #define ev_int16_t int16_t #elif defined(_WIN32) #define ev_uint16_t unsigned short #define ev_int16_t signed short #elif EVENT__SIZEOF_INT == 2 #define ev_uint16_t unsigned int #define ev_int16_t signed int #elif EVENT__SIZEOF_SHORT == 2 #define ev_uint16_t unsigned short #define ev_int16_t signed short #elif defined(EVENT_IN_DOXYGEN_) #define ev_uint16_t ... #define ev_int16_t ... #else #error "No way to define ev_uint16_t" #endif #ifdef EVENT__HAVE_UINT8_T #define ev_uint8_t uint8_t #define ev_int8_t int8_t #elif defined(EVENT_IN_DOXYGEN_) #define ev_uint8_t ... #define ev_int8_t ... #else #define ev_uint8_t unsigned char #define ev_int8_t signed char #endif #ifdef EVENT__HAVE_UINTPTR_T #define ev_uintptr_t uintptr_t #define ev_intptr_t intptr_t #elif EVENT__SIZEOF_VOID_P <= 4 #define ev_uintptr_t ev_uint32_t #define ev_intptr_t ev_int32_t #elif EVENT__SIZEOF_VOID_P <= 8 #define ev_uintptr_t ev_uint64_t #define ev_intptr_t ev_int64_t #elif defined(EVENT_IN_DOXYGEN_) #define ev_uintptr_t ... #define ev_intptr_t ... #else #error "No way to define ev_uintptr_t" #endif #ifdef EVENT__ssize_t #define ev_ssize_t EVENT__ssize_t #else #define ev_ssize_t ssize_t #endif /* Note that we define ev_off_t based on the compile-time size of off_t that * we used to build Libevent, and not based on the current size of off_t. * (For example, we don't define ev_off_t to off_t.). We do this because * some systems let you build your software with different off_t sizes * at runtime, and so putting in any dependency on off_t would risk API * mismatch. */ #ifdef _WIN32 #define ev_off_t ev_int64_t #elif EVENT__SIZEOF_OFF_T == 8 #define ev_off_t ev_int64_t #elif EVENT__SIZEOF_OFF_T == 4 #define ev_off_t ev_int32_t #elif defined(EVENT_IN_DOXYGEN_) #define ev_off_t ... #else #define ev_off_t off_t #endif /**@}*/ /* Limits for integer types. We're making two assumptions here: - The compiler does constant folding properly. - The platform does signed arithmetic in two's complement. */ /** @name Limits for integer types These macros hold the largest or smallest values possible for the ev_[u]int*_t types. @{ */ #ifndef EVENT__HAVE_STDINT_H #define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL) #define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL) #define EV_INT64_MIN ((-EV_INT64_MAX) - 1) #define EV_UINT32_MAX ((ev_uint32_t)0xffffffffUL) #define EV_INT32_MAX ((ev_int32_t) 0x7fffffffL) #define EV_INT32_MIN ((-EV_INT32_MAX) - 1) #define EV_UINT16_MAX ((ev_uint16_t)0xffffUL) #define EV_INT16_MAX ((ev_int16_t) 0x7fffL) #define EV_INT16_MIN ((-EV_INT16_MAX) - 1) #define EV_UINT8_MAX 255 #define EV_INT8_MAX 127 #define EV_INT8_MIN ((-EV_INT8_MAX) - 1) #else #define EV_UINT64_MAX UINT64_MAX #define EV_INT64_MAX INT64_MAX #define EV_INT64_MIN INT64_MIN #define EV_UINT32_MAX UINT32_MAX #define EV_INT32_MAX INT32_MAX #define EV_INT32_MIN INT32_MIN #define EV_UINT16_MAX UINT16_MAX #define EV_INT16_MIN INT16_MIN #define EV_INT16_MAX INT16_MAX #define EV_UINT8_MAX UINT8_MAX #define EV_INT8_MAX INT8_MAX #define EV_INT8_MIN INT8_MIN /** @} */ #endif /** @name Limits for SIZE_T and SSIZE_T @{ */ #if EVENT__SIZEOF_SIZE_T == 8 #define EV_SIZE_MAX EV_UINT64_MAX #define EV_SSIZE_MAX EV_INT64_MAX #elif EVENT__SIZEOF_SIZE_T == 4 #define EV_SIZE_MAX EV_UINT32_MAX #define EV_SSIZE_MAX EV_INT32_MAX #elif defined(EVENT_IN_DOXYGEN_) #define EV_SIZE_MAX ... #define EV_SSIZE_MAX ... #else #error "No way to define SIZE_MAX" #endif #define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1) /**@}*/ #ifdef _WIN32 #define ev_socklen_t int #elif defined(EVENT__socklen_t) #define ev_socklen_t EVENT__socklen_t #else #define ev_socklen_t socklen_t #endif #ifdef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY #if !defined(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \ && !defined(ss_family) #define ss_family __ss_family #endif #endif /** * A type wide enough to hold the output of "socket()" or "accept()". On * Windows, this is an intptr_t; elsewhere, it is an int. */ #ifdef _WIN32 #define evutil_socket_t intptr_t #else #define evutil_socket_t int #endif /** * Structure to hold information about a monotonic timer * * Use this with evutil_configure_monotonic_time() and * evutil_gettime_monotonic(). * * This is an opaque structure; you can allocate one using * evutil_monotonic_timer_new(). * * @see evutil_monotonic_timer_new(), evutil_monotonic_timer_free(), * evutil_configure_monotonic_time(), evutil_gettime_monotonic() */ struct evutil_monotonic_timer #ifdef EVENT_IN_DOXYGEN_ {/*Empty body so that doxygen will generate documentation here.*/} #endif ; #define EV_MONOT_PRECISE 1 #define EV_MONOT_FALLBACK 2 /** Format a date string using RFC 1123 format (used in HTTP). * If `tm` is NULL, current system's time will be used. * The number of characters written will be returned. * One should check if the return value is smaller than `datelen` to check if * the result is truncated or not. */ EVENT2_EXPORT_SYMBOL int evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm); /** Allocate a new struct evutil_monotonic_timer for use with the * evutil_configure_monotonic_time() and evutil_gettime_monotonic() * functions. You must configure the timer with * evutil_configure_monotonic_time() before using it. */ EVENT2_EXPORT_SYMBOL struct evutil_monotonic_timer * evutil_monotonic_timer_new(void); /** Free a struct evutil_monotonic_timer that was allocated using * evutil_monotonic_timer_new(). */ EVENT2_EXPORT_SYMBOL void evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer); /** Set up a struct evutil_monotonic_timer; flags can include * EV_MONOT_PRECISE and EV_MONOT_FALLBACK. */ EVENT2_EXPORT_SYMBOL int evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer, int flags); /** Query the current monotonic time from a struct evutil_monotonic_timer * previously configured with evutil_configure_monotonic_time(). Monotonic * time is guaranteed never to run in reverse, but is not necessarily epoch- * based, or relative to any other definite point. Use it to make reliable * measurements of elapsed time between events even when the system time * may be changed. * * It is not safe to use this funtion on the same timer from multiple * threads. */ EVENT2_EXPORT_SYMBOL int evutil_gettime_monotonic(struct evutil_monotonic_timer *timer, struct timeval *tp); /** Create two new sockets that are connected to each other. On Unix, this simply calls socketpair(). On Windows, it uses the loopback network interface on 127.0.0.1, and only AF_INET,SOCK_STREAM are supported. (This may fail on some Windows hosts where firewall software has cleverly decided to keep 127.0.0.1 from talking to itself.) Parameters and return values are as for socketpair() */ EVENT2_EXPORT_SYMBOL int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]); /** Do platform-specific operations as needed to make a socket nonblocking. @param sock The socket to make nonblocking @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_socket_nonblocking(evutil_socket_t sock); /** Do platform-specific operations to make a listener socket reusable. Specifically, we want to make sure that another program will be able to bind this address right after we've closed the listener. This differs from Windows's interpretation of "reusable", which allows multiple listeners to bind the same address at the same time. @param sock The socket to make reusable @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_listen_socket_reuseable(evutil_socket_t sock); /** Do platform-specific operations to make a listener port reusable. Specifically, we want to make sure that multiple programs which also set the same socket option will be able to bind, listen at the same time. This is a feature available only to Linux 3.9+ @param sock The socket to make reusable @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock); /** Set ipv6 only bind socket option to make listener work only in ipv6 sockets. According to RFC3493 and most Linux distributions, default value for the sockets is to work in IPv4-mapped mode. In IPv4-mapped mode, it is not possible to bind same port from different IPv4 and IPv6 handlers. @param sock The socket to make in ipv6only working mode @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_listen_socket_ipv6only(evutil_socket_t sock); /** Do platform-specific operations as needed to close a socket upon a successful execution of one of the exec*() functions. @param sock The socket to be closed @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_socket_closeonexec(evutil_socket_t sock); /** Do the platform-specific call needed to close a socket returned from socket() or accept(). @param sock The socket to be closed @return 0 on success (whether the operation is supported or not), -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_closesocket(evutil_socket_t sock); #define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s) /** Do platform-specific operations, if possible, to make a tcp listener * socket defer accept()s until there is data to read. * * Not all platforms support this. You don't want to do this for every * listener socket: only the ones that implement a protocol where the * client transmits before the server needs to respond. * * @param sock The listening socket to to make deferred * @return 0 on success (whether the operation is supported or not), * -1 on failure */ EVENT2_EXPORT_SYMBOL int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock); #ifdef _WIN32 /** Return the most recent socket error. Not idempotent on all platforms. */ #define EVUTIL_SOCKET_ERROR() WSAGetLastError() /** Replace the most recent socket error with errcode */ #define EVUTIL_SET_SOCKET_ERROR(errcode) \ do { WSASetLastError(errcode); } while (0) /** Return the most recent socket error to occur on sock. */ EVENT2_EXPORT_SYMBOL int evutil_socket_geterror(evutil_socket_t sock); /** Convert a socket error to a string. */ EVENT2_EXPORT_SYMBOL const char *evutil_socket_error_to_string(int errcode); #define EVUTIL_INVALID_SOCKET INVALID_SOCKET #elif defined(EVENT_IN_DOXYGEN_) /** @name Socket error functions These functions are needed for making programs compatible between Windows and Unix-like platforms. You see, Winsock handles socket errors differently from the rest of the world. Elsewhere, a socket error is like any other error and is stored in errno. But winsock functions require you to retrieve the error with a special function, and don't let you use strerror for the error codes. And handling EWOULDBLOCK is ... different. @{ */ /** Return the most recent socket error. Not idempotent on all platforms. */ #define EVUTIL_SOCKET_ERROR() ... /** Replace the most recent socket error with errcode */ #define EVUTIL_SET_SOCKET_ERROR(errcode) ... /** Return the most recent socket error to occur on sock. */ #define evutil_socket_geterror(sock) ... /** Convert a socket error to a string. */ #define evutil_socket_error_to_string(errcode) ... #define EVUTIL_INVALID_SOCKET -1 /**@}*/ #else /** !EVENT_IN_DOXYGEN_ && !_WIN32 */ #define EVUTIL_SOCKET_ERROR() (errno) #define EVUTIL_SET_SOCKET_ERROR(errcode) \ do { errno = (errcode); } while (0) #define evutil_socket_geterror(sock) (errno) #define evutil_socket_error_to_string(errcode) (strerror(errcode)) #define EVUTIL_INVALID_SOCKET -1 #endif /** !_WIN32 */ /** * @name Manipulation macros for struct timeval. * * We define replacements * for timeradd, timersub, timerclear, timercmp, and timerisset. * * @{ */ #ifdef EVENT__HAVE_TIMERADD #define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) #define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) #else #define evutil_timeradd(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ if ((vvp)->tv_usec >= 1000000) { \ (vvp)->tv_sec++; \ (vvp)->tv_usec -= 1000000; \ } \ } while (0) #define evutil_timersub(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ if ((vvp)->tv_usec < 0) { \ (vvp)->tv_sec--; \ (vvp)->tv_usec += 1000000; \ } \ } while (0) #endif /* !EVENT__HAVE_TIMERADD */ #ifdef EVENT__HAVE_TIMERCLEAR #define evutil_timerclear(tvp) timerclear(tvp) #else #define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 #endif /**@}*/ /** Return true iff the tvp is related to uvp according to the relational * operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */ #define evutil_timercmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) #ifdef EVENT__HAVE_TIMERISSET #define evutil_timerisset(tvp) timerisset(tvp) #else #define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #endif /** Replacement for offsetof on platforms that don't define it. */ #ifdef offsetof #define evutil_offsetof(type, field) offsetof(type, field) #else #define evutil_offsetof(type, field) ((off_t)(&((type *)0)->field)) #endif /* big-int related functions */ /** Parse a 64-bit value from a string. Arguments are as for strtol. */ EVENT2_EXPORT_SYMBOL ev_int64_t evutil_strtoll(const char *s, char **endptr, int base); /** Replacement for gettimeofday on platforms that lack it. */ #ifdef EVENT__HAVE_GETTIMEOFDAY #define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz)) #else struct timezone; EVENT2_EXPORT_SYMBOL int evutil_gettimeofday(struct timeval *tv, struct timezone *tz); #endif /** Replacement for snprintf to get consistent behavior on platforms for which the return value of snprintf does not conform to C99. */ EVENT2_EXPORT_SYMBOL int evutil_snprintf(char *buf, size_t buflen, const char *format, ...) #ifdef __GNUC__ __attribute__((format(printf, 3, 4))) #endif ; /** Replacement for vsnprintf to get consistent behavior on platforms for which the return value of snprintf does not conform to C99. */ EVENT2_EXPORT_SYMBOL int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap) #ifdef __GNUC__ __attribute__((format(printf, 3, 0))) #endif ; /** Replacement for inet_ntop for platforms which lack it. */ EVENT2_EXPORT_SYMBOL const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len); /** Variation of inet_pton that also parses IPv6 scopes. Public for unit tests. No reason to call this directly. */ EVENT2_EXPORT_SYMBOL int evutil_inet_pton_scope(int af, const char *src, void *dst, unsigned *indexp); /** Replacement for inet_pton for platforms which lack it. */ EVENT2_EXPORT_SYMBOL int evutil_inet_pton(int af, const char *src, void *dst); struct sockaddr; /** Parse an IPv4 or IPv6 address, with optional port, from a string. Recognized formats are: - [IPv6Address]:port - [IPv6Address] - IPv6Address - IPv4Address:port - IPv4Address If no port is specified, the port in the output is set to 0. @param str The string to parse. @param out A struct sockaddr to hold the result. This should probably be a struct sockaddr_storage. @param outlen A pointer to the number of bytes that that 'out' can safely hold. Set to the number of bytes used in 'out' on success. @return -1 if the address is not well-formed, if the port is out of range, or if out is not large enough to hold the result. Otherwise returns 0 on success. */ EVENT2_EXPORT_SYMBOL int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen); /** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1 * preceeds sa2, or greater than 0 if sa1 follows sa2. If include_port is * true, consider the port as well as the address. Only implemented for * AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain * the same between Libevent versions. */ EVENT2_EXPORT_SYMBOL int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2, int include_port); /** As strcasecmp, but always compares the characters in locale-independent ASCII. That's useful if you're handling data in ASCII-based protocols. */ EVENT2_EXPORT_SYMBOL int evutil_ascii_strcasecmp(const char *str1, const char *str2); /** As strncasecmp, but always compares the characters in locale-independent ASCII. That's useful if you're handling data in ASCII-based protocols. */ EVENT2_EXPORT_SYMBOL int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n); /* Here we define evutil_addrinfo to the native addrinfo type, or redefine it * if this system has no getaddrinfo(). */ #ifdef EVENT__HAVE_STRUCT_ADDRINFO #define evutil_addrinfo addrinfo #else /** A definition of struct addrinfo for systems that lack it. (This is just an alias for struct addrinfo if the system defines struct addrinfo.) */ struct evutil_addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for nodename */ struct sockaddr *ai_addr; /* binary address */ struct evutil_addrinfo *ai_next; /* next structure in linked list */ }; #endif /** @name evutil_getaddrinfo() error codes These values are possible error codes for evutil_getaddrinfo() and related functions. @{ */ #if defined(EAI_ADDRFAMILY) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY #else #define EVUTIL_EAI_ADDRFAMILY -901 #endif #if defined(EAI_AGAIN) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_AGAIN EAI_AGAIN #else #define EVUTIL_EAI_AGAIN -902 #endif #if defined(EAI_BADFLAGS) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS #else #define EVUTIL_EAI_BADFLAGS -903 #endif #if defined(EAI_FAIL) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_FAIL EAI_FAIL #else #define EVUTIL_EAI_FAIL -904 #endif #if defined(EAI_FAMILY) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_FAMILY EAI_FAMILY #else #define EVUTIL_EAI_FAMILY -905 #endif #if defined(EAI_MEMORY) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_MEMORY EAI_MEMORY #else #define EVUTIL_EAI_MEMORY -906 #endif /* This test is a bit complicated, since some MS SDKs decide to * remove NODATA or redefine it to be the same as NONAME, in a * fun interpretation of RFC 2553 and RFC 3493. */ #if defined(EAI_NODATA) && defined(EVENT__HAVE_GETADDRINFO) && (!defined(EAI_NONAME) || EAI_NODATA != EAI_NONAME) #define EVUTIL_EAI_NODATA EAI_NODATA #else #define EVUTIL_EAI_NODATA -907 #endif #if defined(EAI_NONAME) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_NONAME EAI_NONAME #else #define EVUTIL_EAI_NONAME -908 #endif #if defined(EAI_SERVICE) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_SERVICE EAI_SERVICE #else #define EVUTIL_EAI_SERVICE -909 #endif #if defined(EAI_SOCKTYPE) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE #else #define EVUTIL_EAI_SOCKTYPE -910 #endif #if defined(EAI_SYSTEM) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_EAI_SYSTEM EAI_SYSTEM #else #define EVUTIL_EAI_SYSTEM -911 #endif #define EVUTIL_EAI_CANCEL -90001 #if defined(AI_PASSIVE) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_PASSIVE AI_PASSIVE #else #define EVUTIL_AI_PASSIVE 0x1000 #endif #if defined(AI_CANONNAME) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_CANONNAME AI_CANONNAME #else #define EVUTIL_AI_CANONNAME 0x2000 #endif #if defined(AI_NUMERICHOST) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST #else #define EVUTIL_AI_NUMERICHOST 0x4000 #endif #if defined(AI_NUMERICSERV) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV #else #define EVUTIL_AI_NUMERICSERV 0x8000 #endif #if defined(AI_V4MAPPED) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_V4MAPPED AI_V4MAPPED #else #define EVUTIL_AI_V4MAPPED 0x10000 #endif #if defined(AI_ALL) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_ALL AI_ALL #else #define EVUTIL_AI_ALL 0x20000 #endif #if defined(AI_ADDRCONFIG) && defined(EVENT__HAVE_GETADDRINFO) #define EVUTIL_AI_ADDRCONFIG AI_ADDRCONFIG #else #define EVUTIL_AI_ADDRCONFIG 0x40000 #endif /**@}*/ struct evutil_addrinfo; /** * This function clones getaddrinfo for systems that don't have it. For full * details, see RFC 3493, section 6.1. * * Limitations: * - When the system has no getaddrinfo, we fall back to gethostbyname_r or * gethostbyname, with their attendant issues. * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. * * For a nonblocking variant, see evdns_getaddrinfo. */ EVENT2_EXPORT_SYMBOL int evutil_getaddrinfo(const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res); /** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */ EVENT2_EXPORT_SYMBOL void evutil_freeaddrinfo(struct evutil_addrinfo *ai); EVENT2_EXPORT_SYMBOL const char *evutil_gai_strerror(int err); /** Generate n bytes of secure pseudorandom data, and store them in buf. * * Current versions of Libevent use an ARC4-based random number generator, * seeded using the platform's entropy source (/dev/urandom on Unix-like * systems; CryptGenRandom on Windows). This is not actually as secure as it * should be: ARC4 is a pretty lousy cipher, and the current implementation * provides only rudimentary prediction- and backtracking-resistance. Don't * use this for serious cryptographic applications. */ EVENT2_EXPORT_SYMBOL void evutil_secure_rng_get_bytes(void *buf, size_t n); /** * Seed the secure random number generator if needed, and return 0 on * success or -1 on failure. * * It is okay to call this function more than once; it will still return * 0 if the RNG has been successfully seeded and -1 if it can't be * seeded. * * Ordinarily you don't need to call this function from your own code; * Libevent will seed the RNG itself the first time it needs good random * numbers. You only need to call it if (a) you want to double-check * that one of the seeding methods did succeed, or (b) you plan to drop * the capability to seed (by chrooting, or dropping capabilities, or * whatever), and you want to make sure that seeding happens before your * program loses the ability to do it. */ EVENT2_EXPORT_SYMBOL int evutil_secure_rng_init(void); /** * Set a filename to use in place of /dev/urandom for seeding the secure * PRNG. Return 0 on success, -1 on failure. * * Call this function BEFORE calling any other initialization or RNG * functions. * * (This string will _NOT_ be copied internally. Do not free it while any * user of the secure RNG might be running. Don't pass anything other than a * real /dev/...random device file here, or you might lose security.) * * This API is unstable, and might change in a future libevent version. */ EVENT2_EXPORT_SYMBOL int evutil_secure_rng_set_urandom_device_file(char *fname); #if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM) /** Seed the random number generator with extra random bytes. You should almost never need to call this function; it should be sufficient to invoke evutil_secure_rng_init(), or let Libevent take care of calling evutil_secure_rng_init() on its own. If you call this function as a _replacement_ for the regular entropy sources, then you need to be sure that your input contains a fairly large amount of strong entropy. Doing so is notoriously hard: most people who try get it wrong. Watch out! @param dat a buffer full of a strong source of random numbers @param datlen the number of bytes to read from datlen */ EVENT2_EXPORT_SYMBOL void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); #endif #ifdef __cplusplus } #endif #endif /* EVENT1_EVUTIL_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/event.h0000644000076400001440000017160114111362573021332 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_EVENT_H_INCLUDED_ #define EVENT2_EVENT_H_INCLUDED_ /** @mainpage @section intro Introduction Libevent is an event notification library for developing scalable network servers. The Libevent API provides a mechanism to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached. Furthermore, Libevent also support callbacks due to signals or regular timeouts. Libevent is meant to replace the event loop found in event driven network servers. An application just needs to call event_base_dispatch() and then add or remove events dynamically without having to change the event loop. Currently, Libevent supports /dev/poll, kqueue(2), select(2), poll(2), epoll(4), and evports. The internal event mechanism is completely independent of the exposed event API, and a simple update of Libevent can provide new functionality without having to redesign the applications. As a result, Libevent allows for portable application development and provides the most scalable event notification mechanism available on an operating system. Libevent can also be used for multithreaded programs. Libevent should compile on Linux, *BSD, Mac OS X, Solaris and, Windows. @section usage Standard usage Every program that uses Libevent must include the header, and pass the -levent flag to the linker. (You can instead link -levent_core if you only want the main event and buffered IO-based code, and don't want to link any protocol code.) @section setup Library setup Before you call any other Libevent functions, you need to set up the library. If you're going to use Libevent from multiple threads in a multithreaded application, you need to initialize thread support -- typically by using evthread_use_pthreads() or evthread_use_windows_threads(). See for more information. This is also the point where you can replace Libevent's memory management functions with event_set_mem_functions, and enable debug mode with event_enable_debug_mode(). @section base Creating an event base Next, you need to create an event_base structure, using event_base_new() or event_base_new_with_config(). The event_base is responsible for keeping track of which events are "pending" (that is to say, being watched to see if they become active) and which events are "active". Every event is associated with a single event_base. @section event Event notification For each file descriptor that you wish to monitor, you must create an event structure with event_new(). (You may also declare an event structure and call event_assign() to initialize the members of the structure.) To enable notification, you add the structure to the list of monitored events by calling event_add(). The event structure must remain allocated as long as it is active, so it should generally be allocated on the heap. @section loop Dispatching events. Finally, you call event_base_dispatch() to loop and dispatch events. You can also use event_base_loop() for more fine-grained control. Currently, only one thread can be dispatching a given event_base at a time. If you want to run events in multiple threads at once, you can either have a single event_base whose events add work to a work queue, or you can create multiple event_base objects. @section bufferevent I/O Buffers Libevent provides a buffered I/O abstraction on top of the regular event callbacks. This abstraction is called a bufferevent. A bufferevent provides input and output buffers that get filled and drained automatically. The user of a buffered event no longer deals directly with the I/O, but instead is reading from input and writing to output buffers. Once initialized via bufferevent_socket_new(), the bufferevent structure can be used repeatedly with bufferevent_enable() and bufferevent_disable(). Instead of reading and writing directly to a socket, you would call bufferevent_read() and bufferevent_write(). When read enabled the bufferevent will try to read from the file descriptor and call the read callback. The write callback is executed whenever the output buffer is drained below the write low watermark, which is 0 by default. See for more information. @section timers Timers Libevent can also be used to create timers that invoke a callback after a certain amount of time has expired. The evtimer_new() macro returns an event struct to use as a timer. To activate the timer, call evtimer_add(). Timers can be deactivated by calling evtimer_del(). (These macros are thin wrappers around event_new(), event_add(), and event_del(); you can also use those instead.) @section evdns Asynchronous DNS resolution Libevent provides an asynchronous DNS resolver that should be used instead of the standard DNS resolver functions. See the functions for more detail. @section evhttp Event-driven HTTP servers Libevent provides a very simple event-driven HTTP server that can be embedded in your program and used to service HTTP requests. To use this capability, you need to include the header in your program. See that header for more information. @section evrpc A framework for RPC servers and clients Libevent provides a framework for creating RPC servers and clients. It takes care of marshaling and unmarshaling all data structures. @section api API Reference To browse the complete documentation of the libevent API, click on any of the following links. event2/event.h The primary libevent header event2/thread.h Functions for use by multithreaded programs event2/buffer.h and event2/bufferevent.h Buffer management for network reading and writing event2/util.h Utility functions for portable nonblocking network code event2/dns.h Asynchronous DNS resolution event2/http.h An embedded libevent-based HTTP server event2/rpc.h A framework for creating RPC servers and clients */ /** @file event2/event.h Core functions for waiting for and receiving events, and using event bases. */ #include #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include /* For int types. */ #include /** * Structure to hold information and state for a Libevent dispatch loop. * * The event_base lies at the center of Libevent; every application will * have one. It keeps track of all pending and active events, and * notifies your application of the active ones. * * This is an opaque structure; you can allocate one using * event_base_new() or event_base_new_with_config(). * * @see event_base_new(), event_base_free(), event_base_loop(), * event_base_new_with_config() */ struct event_base #ifdef EVENT_IN_DOXYGEN_ {/*Empty body so that doxygen will generate documentation here.*/} #endif ; /** * @struct event * * Structure to represent a single event. * * An event can have some underlying condition it represents: a socket * becoming readable or writeable (or both), or a signal becoming raised. * (An event that represents no underlying condition is still useful: you * can use one to implement a timer, or to communicate between threads.) * * Generally, you can create events with event_new(), then make them * pending with event_add(). As your event_base runs, it will run the * callbacks of an events whose conditions are triggered. When you no * longer want the event, free it with event_free(). * * In more depth: * * An event may be "pending" (one whose condition we are watching), * "active" (one whose condition has triggered and whose callback is about * to run), neither, or both. Events come into existence via * event_assign() or event_new(), and are then neither active nor pending. * * To make an event pending, pass it to event_add(). When doing so, you * can also set a timeout for the event. * * Events become active during an event_base_loop() call when either their * condition has triggered, or when their timeout has elapsed. You can * also activate an event manually using event_active(). The even_base * loop will run the callbacks of active events; after it has done so, it * marks them as no longer active. * * You can make an event non-pending by passing it to event_del(). This * also makes the event non-active. * * Events can be "persistent" or "non-persistent". A non-persistent event * becomes non-pending as soon as it is triggered: thus, it only runs at * most once per call to event_add(). A persistent event remains pending * even when it becomes active: you'll need to event_del() it manually in * order to make it non-pending. When a persistent event with a timeout * becomes active, its timeout is reset: this means you can use persistent * events to implement periodic timeouts. * * This should be treated as an opaque structure; you should never read or * write any of its fields directly. For backward compatibility with old * code, it is defined in the event2/event_struct.h header; including this * header may make your code incompatible with other versions of Libevent. * * @see event_new(), event_free(), event_assign(), event_get_assignment(), * event_add(), event_del(), event_active(), event_pending(), * event_get_fd(), event_get_base(), event_get_events(), * event_get_callback(), event_get_callback_arg(), * event_priority_set() */ struct event #ifdef EVENT_IN_DOXYGEN_ {/*Empty body so that doxygen will generate documentation here.*/} #endif ; /** * Configuration for an event_base. * * There are many options that can be used to alter the behavior and * implementation of an event_base. To avoid having to pass them all in a * complex many-argument constructor, we provide an abstract data type * where you set up configuration information before passing it to * event_base_new_with_config(). * * @see event_config_new(), event_config_free(), event_base_new_with_config(), * event_config_avoid_method(), event_config_require_features(), * event_config_set_flag(), event_config_set_num_cpus_hint() */ struct event_config #ifdef EVENT_IN_DOXYGEN_ {/*Empty body so that doxygen will generate documentation here.*/} #endif ; /** * Enable some relatively expensive debugging checks in Libevent that * would normally be turned off. Generally, these checks cause code that * would otherwise crash mysteriously to fail earlier with an assertion * failure. Note that this method MUST be called before any events or * event_bases have been created. * * Debug mode can currently catch the following errors: * An event is re-assigned while it is added * Any function is called on a non-assigned event * * Note that debugging mode uses memory to track every event that has been * initialized (via event_assign, event_set, or event_new) but not yet * released (via event_free or event_debug_unassign). If you want to use * debug mode, and you find yourself running out of memory, you will need * to use event_debug_unassign to explicitly stop tracking events that * are no longer considered set-up. * * @see event_debug_unassign() */ EVENT2_EXPORT_SYMBOL void event_enable_debug_mode(void); /** * When debugging mode is enabled, informs Libevent that an event should no * longer be considered as assigned. When debugging mode is not enabled, does * nothing. * * This function must only be called on a non-added event. * * @see event_enable_debug_mode() */ EVENT2_EXPORT_SYMBOL void event_debug_unassign(struct event *); /** * Create and return a new event_base to use with the rest of Libevent. * * @return a new event_base on success, or NULL on failure. * * @see event_base_free(), event_base_new_with_config() */ EVENT2_EXPORT_SYMBOL struct event_base *event_base_new(void); /** Reinitialize the event base after a fork Some event mechanisms do not survive across fork. The event base needs to be reinitialized with the event_reinit() function. @param base the event base that needs to be re-initialized @return 0 if successful, or -1 if some events could not be re-added. @see event_base_new() */ EVENT2_EXPORT_SYMBOL int event_reinit(struct event_base *base); /** Event dispatching loop This loop will run the event base until either there are no more pending or active, or until something calls event_base_loopbreak() or event_base_loopexit(). @param base the event_base structure returned by event_base_new() or event_base_new_with_config() @return 0 if successful, -1 if an error occurred, or 1 if we exited because no events were pending or active. @see event_base_loop() */ EVENT2_EXPORT_SYMBOL int event_base_dispatch(struct event_base *); /** Get the kernel event notification mechanism used by Libevent. @param eb the event_base structure returned by event_base_new() @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) */ EVENT2_EXPORT_SYMBOL const char *event_base_get_method(const struct event_base *); /** Gets all event notification mechanisms supported by Libevent. This functions returns the event mechanism in order preferred by Libevent. Note that this list will include all backends that Libevent has compiled-in support for, and will not necessarily check your OS to see whether it has the required resources. @return an array with pointers to the names of support methods. The end of the array is indicated by a NULL pointer. If an error is encountered NULL is returned. */ EVENT2_EXPORT_SYMBOL const char **event_get_supported_methods(void); /** Query the current monotonic time from a the timer for a struct * event_base. */ EVENT2_EXPORT_SYMBOL int event_gettime_monotonic(struct event_base *base, struct timeval *tp); /** @name event type flag Flags to pass to event_base_get_num_events() to specify the kinds of events we want to aggregate counts for */ /**@{*/ /** count the number of active events, which have been triggered.*/ #define EVENT_BASE_COUNT_ACTIVE 1U /** count the number of virtual events, which is used to represent an internal * condition, other than a pending event, that keeps the loop from exiting. */ #define EVENT_BASE_COUNT_VIRTUAL 2U /** count the number of events which have been added to event base, including * internal events. */ #define EVENT_BASE_COUNT_ADDED 4U /**@}*/ /** Gets the number of events in event_base, as specified in the flags. Since event base has some internal events added to make some of its functionalities work, EVENT_BASE_COUNT_ADDED may return more than the number of events you added using event_add(). If you pass EVENT_BASE_COUNT_ACTIVE and EVENT_BASE_COUNT_ADDED together, an active event will be counted twice. However, this might not be the case in future libevent versions. The return value is an indication of the work load, but the user shouldn't rely on the exact value as this may change in the future. @param eb the event_base structure returned by event_base_new() @param flags a bitwise combination of the kinds of events to aggregate counts for @return the number of events specified in the flags */ EVENT2_EXPORT_SYMBOL int event_base_get_num_events(struct event_base *, unsigned int); /** Get the maximum number of events in a given event_base as specified in the flags. @param eb the event_base structure returned by event_base_new() @param flags a bitwise combination of the kinds of events to aggregate counts for @param clear option used to reset the maximum count. @return the number of events specified in the flags */ EVENT2_EXPORT_SYMBOL int event_base_get_max_events(struct event_base *, unsigned int, int); /** Allocates a new event configuration object. The event configuration object can be used to change the behavior of an event base. @return an event_config object that can be used to store configuration, or NULL if an error is encountered. @see event_base_new_with_config(), event_config_free(), event_config */ EVENT2_EXPORT_SYMBOL struct event_config *event_config_new(void); /** Deallocates all memory associated with an event configuration object @param cfg the event configuration object to be freed. */ EVENT2_EXPORT_SYMBOL void event_config_free(struct event_config *cfg); /** Enters an event method that should be avoided into the configuration. This can be used to avoid event mechanisms that do not support certain file descriptor types, or for debugging to avoid certain event mechanisms. An application can make use of multiple event bases to accommodate incompatible file descriptor types. @param cfg the event configuration object @param method the name of the event method to avoid @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int event_config_avoid_method(struct event_config *cfg, const char *method); /** A flag used to describe which features an event_base (must) provide. Because of OS limitations, not every Libevent backend supports every possible feature. You can use this type with event_config_require_features() to tell Libevent to only proceed if your event_base implements a given feature, and you can receive this type from event_base_get_features() to see which features are available. */ enum event_method_feature { /** Require an event method that allows edge-triggered events with EV_ET. */ EV_FEATURE_ET = 0x01, /** Require an event method where having one event triggered among * many is [approximately] an O(1) operation. This excludes (for * example) select and poll, which are approximately O(N) for N * equal to the total number of possible events. */ EV_FEATURE_O1 = 0x02, /** Require an event method that allows file descriptors as well as * sockets. */ EV_FEATURE_FDS = 0x04, /** Require an event method that allows you to use EV_CLOSED to detect * connection close without the necessity of reading all the pending data. * * Methods that do support EV_CLOSED may not be able to provide support on * all kernel versions. **/ EV_FEATURE_EARLY_CLOSE = 0x08 }; /** A flag passed to event_config_set_flag(). These flags change the behavior of an allocated event_base. @see event_config_set_flag(), event_base_new_with_config(), event_method_feature */ enum event_base_config_flag { /** Do not allocate a lock for the event base, even if we have locking set up. Setting this option will make it unsafe and nonfunctional to call functions on the base concurrently from multiple threads. */ EVENT_BASE_FLAG_NOLOCK = 0x01, /** Do not check the EVENT_* environment variables when configuring an event_base */ EVENT_BASE_FLAG_IGNORE_ENV = 0x02, /** Windows only: enable the IOCP dispatcher at startup If this flag is set then bufferevent_socket_new() and evconn_listener_new() will use IOCP-backed implementations instead of the usual select-based one on Windows. */ EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, /** Instead of checking the current time every time the event loop is ready to run timeout callbacks, check after each timeout callback. */ EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, /** If we are using the epoll backend, this flag says that it is safe to use Libevent's internal change-list code to batch up adds and deletes in order to try to do as few syscalls as possible. Setting this flag can make your code run faster, but it may trigger a Linux bug: it is not safe to use this flag if you have any fds cloned by dup() or its variants. Doing so will produce strange and hard-to-diagnose bugs. This flag can also be activated by setting the EVENT_EPOLL_USE_CHANGELIST environment variable. This flag has no effect if you wind up using a backend other than epoll. */ EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10, /** Ordinarily, Libevent implements its time and timeout code using the fastest monotonic timer that we have. If this flag is set, however, we use less efficient more precise timer, assuming one is present. */ EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 }; /** Return a bitmask of the features implemented by an event base. This will be a bitwise OR of one or more of the values of event_method_feature @see event_method_feature */ EVENT2_EXPORT_SYMBOL int event_base_get_features(const struct event_base *base); /** Enters a required event method feature that the application demands. Note that not every feature or combination of features is supported on every platform. Code that requests features should be prepared to handle the case where event_base_new_with_config() returns NULL, as in:
     event_config_require_features(cfg, EV_FEATURE_ET);
     base = event_base_new_with_config(cfg);
     if (base == NULL) {
       // We can't get edge-triggered behavior here.
       event_config_require_features(cfg, 0);
       base = event_base_new_with_config(cfg);
     }
   
@param cfg the event configuration object @param feature a bitfield of one or more event_method_feature values. Replaces values from previous calls to this function. @return 0 on success, -1 on failure. @see event_method_feature, event_base_new_with_config() */ EVENT2_EXPORT_SYMBOL int event_config_require_features(struct event_config *cfg, int feature); /** * Sets one or more flags to configure what parts of the eventual event_base * will be initialized, and how they'll work. * * @see event_base_config_flags, event_base_new_with_config() **/ EVENT2_EXPORT_SYMBOL int event_config_set_flag(struct event_config *cfg, int flag); /** * Records a hint for the number of CPUs in the system. This is used for * tuning thread pools, etc, for optimal performance. In Libevent 2.0, * it is only on Windows, and only when IOCP is in use. * * @param cfg the event configuration object * @param cpus the number of cpus * @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus); /** * Record an interval and/or a number of callbacks after which the event base * should check for new events. By default, the event base will run as many * events are as activated at the highest activated priority before checking * for new events. If you configure it by setting max_interval, it will check * the time after each callback, and not allow more than max_interval to * elapse before checking for new events. If you configure it by setting * max_callbacks to a value >= 0, it will run no more than max_callbacks * callbacks before checking for new events. * * This option can decrease the latency of high-priority events, and * avoid priority inversions where multiple low-priority events keep us from * polling for high-priority events, but at the expense of slightly decreasing * the throughput. Use it with caution! * * @param cfg The event_base configuration object. * @param max_interval An interval after which Libevent should stop running * callbacks and check for more events, or NULL if there should be * no such interval. * @param max_callbacks A number of callbacks after which Libevent should * stop running callbacks and check for more events, or -1 if there * should be no such limit. * @param min_priority A priority below which max_interval and max_callbacks * should not be enforced. If this is set to 0, they are enforced * for events of every priority; if it's set to 1, they're enforced * for events of priority 1 and above, and so on. * @return 0 on success, -1 on failure. **/ EVENT2_EXPORT_SYMBOL int event_config_set_max_dispatch_interval(struct event_config *cfg, const struct timeval *max_interval, int max_callbacks, int min_priority); /** Initialize the event API. Use event_base_new_with_config() to initialize a new event base, taking the specified configuration under consideration. The configuration object can currently be used to avoid certain event notification mechanisms. @param cfg the event configuration object @return an initialized event_base that can be used to registering events, or NULL if no event base can be created with the requested event_config. @see event_base_new(), event_base_free(), event_init(), event_assign() */ EVENT2_EXPORT_SYMBOL struct event_base *event_base_new_with_config(const struct event_config *); /** Deallocate all memory associated with an event_base, and free the base. Note that this function will not close any fds or free any memory passed to event_new as the argument to callback. If there are any pending finalizer callbacks, this function will invoke them. @param eb an event_base to be freed */ EVENT2_EXPORT_SYMBOL void event_base_free(struct event_base *); /** As event_base_free, but do not run finalizers. */ EVENT2_EXPORT_SYMBOL void event_base_free_nofinalize(struct event_base *); /** @name Log severities */ /**@{*/ #define EVENT_LOG_DEBUG 0 #define EVENT_LOG_MSG 1 #define EVENT_LOG_WARN 2 #define EVENT_LOG_ERR 3 /**@}*/ /* Obsolete names: these are deprecated, but older programs might use them. * They violate the reserved-identifier namespace. */ #define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG #define _EVENT_LOG_MSG EVENT_LOG_MSG #define _EVENT_LOG_WARN EVENT_LOG_WARN #define _EVENT_LOG_ERR EVENT_LOG_ERR /** A callback function used to intercept Libevent's log messages. @see event_set_log_callback */ typedef void (*event_log_cb)(int severity, const char *msg); /** Redirect Libevent's log messages. @param cb a function taking two arguments: an integer severity between EVENT_LOG_DEBUG and EVENT_LOG_ERR, and a string. If cb is NULL, then the default log is used. NOTE: The function you provide *must not* call any other libevent functionality. Doing so can produce undefined behavior. */ EVENT2_EXPORT_SYMBOL void event_set_log_callback(event_log_cb cb); /** A function to be called if Libevent encounters a fatal internal error. @see event_set_fatal_callback */ typedef void (*event_fatal_cb)(int err); /** Override Libevent's behavior in the event of a fatal internal error. By default, Libevent will call exit(1) if a programming error makes it impossible to continue correct operation. This function allows you to supply another callback instead. Note that if the function is ever invoked, something is wrong with your program, or with Libevent: any subsequent calls to Libevent may result in undefined behavior. Libevent will (almost) always log an EVENT_LOG_ERR message before calling this function; look at the last log message to see why Libevent has died. */ EVENT2_EXPORT_SYMBOL void event_set_fatal_callback(event_fatal_cb cb); #define EVENT_DBG_ALL 0xffffffffu #define EVENT_DBG_NONE 0 /** Turn on debugging logs and have them sent to the default log handler. This is a global setting; if you are going to call it, you must call this before any calls that create an event-base. You must call it before any multithreaded use of Libevent. Debug logs are verbose. @param which Controls which debug messages are turned on. This option is unused for now; for forward compatibility, you must pass in the constant "EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn debugging logs off. */ EVENT2_EXPORT_SYMBOL void event_enable_debug_logging(ev_uint32_t which); /** Associate a different event base with an event. The event to be associated must not be currently active or pending. @param eb the event base @param ev the event @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int event_base_set(struct event_base *, struct event *); /** @name Loop flags These flags control the behavior of event_base_loop(). */ /**@{*/ /** Block until we have an active event, then exit once all active events * have had their callbacks run. */ #define EVLOOP_ONCE 0x01 /** Do not block: see which events are ready now, run the callbacks * of the highest-priority ones, then exit. */ #define EVLOOP_NONBLOCK 0x02 /** Do not exit the loop because we have no pending events. Instead, keep * running until event_base_loopexit() or event_base_loopbreak() makes us * stop. */ #define EVLOOP_NO_EXIT_ON_EMPTY 0x04 /**@}*/ /** Wait for events to become active, and run their callbacks. This is a more flexible version of event_base_dispatch(). By default, this loop will run the event base until either there are no more pending or active events, or until something calls event_base_loopbreak() or event_base_loopexit(). You can override this behavior with the 'flags' argument. @param eb the event_base structure returned by event_base_new() or event_base_new_with_config() @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK @return 0 if successful, -1 if an error occurred, or 1 if we exited because no events were pending or active. @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE, EVLOOP_NONBLOCK */ EVENT2_EXPORT_SYMBOL int event_base_loop(struct event_base *, int); /** Exit the event loop after the specified time The next event_base_loop() iteration after the given timer expires will complete normally (handling all queued events) then exit without blocking for events again. Subsequent invocations of event_base_loop() will proceed normally. @param eb the event_base structure returned by event_init() @param tv the amount of time after which the loop should terminate, or NULL to exit after running all currently active events. @return 0 if successful, or -1 if an error occurred @see event_base_loopbreak() */ EVENT2_EXPORT_SYMBOL int event_base_loopexit(struct event_base *, const struct timeval *); /** Abort the active event_base_loop() immediately. event_base_loop() will abort the loop after the next event is completed; event_base_loopbreak() is typically invoked from this event's callback. This behavior is analogous to the "break;" statement. Subsequent invocations of event_base_loop() will proceed normally. @param eb the event_base structure returned by event_init() @return 0 if successful, or -1 if an error occurred @see event_base_loopexit() */ EVENT2_EXPORT_SYMBOL int event_base_loopbreak(struct event_base *); /** Tell the active event_base_loop() to scan for new events immediately. Calling this function makes the currently active event_base_loop() start the loop over again (scanning for new events) after the current event callback finishes. If the event loop is not running, this function has no effect. event_base_loopbreak() is typically invoked from this event's callback. This behavior is analogous to the "continue;" statement. Subsequent invocations of event loop will proceed normally. @param eb the event_base structure returned by event_init() @return 0 if successful, or -1 if an error occurred @see event_base_loopbreak() */ EVENT2_EXPORT_SYMBOL int event_base_loopcontinue(struct event_base *); /** Checks if the event loop was told to exit by event_base_loopexit(). This function will return true for an event_base at every point after event_loopexit() is called, until the event loop is next entered. @param eb the event_base structure returned by event_init() @return true if event_base_loopexit() was called on this event base, or 0 otherwise @see event_base_loopexit() @see event_base_got_break() */ EVENT2_EXPORT_SYMBOL int event_base_got_exit(struct event_base *); /** Checks if the event loop was told to abort immediately by event_base_loopbreak(). This function will return true for an event_base at every point after event_base_loopbreak() is called, until the event loop is next entered. @param eb the event_base structure returned by event_init() @return true if event_base_loopbreak() was called on this event base, or 0 otherwise @see event_base_loopbreak() @see event_base_got_exit() */ EVENT2_EXPORT_SYMBOL int event_base_got_break(struct event_base *); /** * @name event flags * * Flags to pass to event_new(), event_assign(), event_pending(), and * anything else with an argument of the form "short events" */ /**@{*/ /** Indicates that a timeout has occurred. It's not necessary to pass * this flag to event_for new()/event_assign() to get a timeout. */ #define EV_TIMEOUT 0x01 /** Wait for a socket or FD to become readable */ #define EV_READ 0x02 /** Wait for a socket or FD to become writeable */ #define EV_WRITE 0x04 /** Wait for a POSIX signal to be raised*/ #define EV_SIGNAL 0x08 /** * Persistent event: won't get removed automatically when activated. * * When a persistent event with a timeout becomes activated, its timeout * is reset to 0. */ #define EV_PERSIST 0x10 /** Select edge-triggered behavior, if supported by the backend. */ #define EV_ET 0x20 /** * If this option is provided, then event_del() will not block in one thread * while waiting for the event callback to complete in another thread. * * To use this option safely, you may need to use event_finalize() or * event_free_finalize() in order to safely tear down an event in a * multithreaded application. See those functions for more information. **/ #define EV_FINALIZE 0x40 /** * Detects connection close events. You can use this to detect when a * connection has been closed, without having to read all the pending data * from a connection. * * Not all backends support EV_CLOSED. To detect or require it, use the * feature flag EV_FEATURE_EARLY_CLOSE. **/ #define EV_CLOSED 0x80 /**@}*/ /** @name evtimer_* macros Aliases for working with one-shot timer events If you need EV_PERSIST timer use event_*() functions. */ /**@{*/ #define evtimer_assign(ev, b, cb, arg) \ event_assign((ev), (b), -1, 0, (cb), (arg)) #define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) #define evtimer_add(ev, tv) event_add((ev), (tv)) #define evtimer_del(ev) event_del(ev) #define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) #define evtimer_initialized(ev) event_initialized(ev) /**@}*/ /** @name evsignal_* macros Aliases for working with signal events */ /**@{*/ #define evsignal_add(ev, tv) event_add((ev), (tv)) #define evsignal_assign(ev, b, x, cb, arg) \ event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg)) #define evsignal_new(b, x, cb, arg) \ event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) #define evsignal_del(ev) event_del(ev) #define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) #define evsignal_initialized(ev) event_initialized(ev) /**@}*/ /** @name evuser_* macros Aliases for working with user-triggered events If you need EV_PERSIST event use event_*() functions. */ /**@{*/ #define evuser_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) #define evuser_del(ev) event_del(ev) #define evuser_pending(ev, tv) event_pending((ev), 0, (tv)) #define evuser_initialized(ev) event_initialized(ev) #define evuser_trigger(ev) event_active((ev), 0, 0) /**@}*/ /** A callback function for an event. It receives three arguments: @param fd An fd or signal @param events One or more EV_* flags @param arg A user-supplied argument. @see event_new() */ typedef void (*event_callback_fn)(evutil_socket_t, short, void *); /** Return a value used to specify that the event itself must be used as the callback argument. The function event_new() takes a callback argument which is passed to the event's callback function. To specify that the argument to be passed to the callback function is the event that event_new() returns, pass in the return value of event_self_cbarg() as the callback argument for event_new(). For example:
      struct event *ev = event_new(base, sock, events, callback, %event_self_cbarg());
  
For consistency with event_new(), it is possible to pass the return value of this function as the callback argument for event_assign() – this achieves the same result as passing the event in directly. @return a value to be passed as the callback argument to event_new() or event_assign(). @see event_new(), event_assign() */ EVENT2_EXPORT_SYMBOL void *event_self_cbarg(void); /** Allocate and assign a new event structure, ready to be added. The function event_new() returns a new event that can be used in future calls to event_add() and event_del(). The fd and events arguments determine which conditions will trigger the event; the callback and callback_arg arguments tell Libevent what to do when the event becomes active. If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then fd is a file descriptor or socket that should get monitored for readiness to read, readiness to write, or readiness for either operation (respectively). If events contains EV_SIGNAL, then fd is a signal number to wait for. If events contains none of those flags, then the event can be triggered only by a timeout or by manual activation with event_active(): In this case, fd must be -1. The EV_PERSIST flag can also be passed in the events argument: it makes event_add() persistent until event_del() is called. The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported only by certain backends. It tells Libevent to use edge-triggered events. The EV_TIMEOUT flag has no effect here. It is okay to have multiple events all listening on the same fds; but they must either all be edge-triggered, or all not be edge triggered. When the event becomes active, the event loop will run the provided callback function, with three arguments. The first will be the provided fd value. The second will be a bitfield of the events that triggered: EV_READ, EV_WRITE, or EV_SIGNAL. Here the EV_TIMEOUT flag indicates that a timeout occurred, and EV_ET indicates that an edge-triggered event occurred. The third event will be the callback_arg pointer that you provide. @param base the event base to which the event should be attached. @param fd the file descriptor or signal to be monitored, or -1. @param events desired events to monitor: bitfield of EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST, EV_ET. @param callback callback function to be invoked when the event occurs @param callback_arg an argument to be passed to the callback function @return a newly allocated struct event that must later be freed with event_free() or NULL if an error occurred. @see event_free(), event_add(), event_del(), event_assign() */ EVENT2_EXPORT_SYMBOL struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *); /** Prepare a new, already-allocated event structure to be added. The function event_assign() prepares the event structure ev to be used in future calls to event_add() and event_del(). Unlike event_new(), it doesn't allocate memory itself: it requires that you have already allocated a struct event, probably on the heap. Doing this will typically make your code depend on the size of the event structure, and thereby create incompatibility with future versions of Libevent. The easiest way to avoid this problem is just to use event_new() and event_free() instead. A slightly harder way to future-proof your code is to use event_get_struct_event_size() to determine the required size of an event at runtime. Note that it is NOT safe to call this function on an event that is active or pending. Doing so WILL corrupt internal data structures in Libevent, and lead to strange, hard-to-diagnose bugs. You _can_ use event_assign to change an existing event, but only if it is not active or pending! The arguments for this function, and the behavior of the events that it makes, are as for event_new(). @param ev an event struct to be modified @param base the event base to which ev should be attached. @param fd the file descriptor to be monitored @param events desired events to monitor; can be EV_READ and/or EV_WRITE @param callback callback function to be invoked when the event occurs @param callback_arg an argument to be passed to the callback function @return 0 if success, or -1 on invalid arguments. @see event_new(), event_add(), event_del(), event_base_once(), event_get_struct_event_size() */ EVENT2_EXPORT_SYMBOL int event_assign(struct event *, struct event_base *, evutil_socket_t, short, event_callback_fn, void *); /** Deallocate a struct event * returned by event_new(). If the event is pending or active, this function makes it non-pending and non-active first. */ EVENT2_EXPORT_SYMBOL void event_free(struct event *); /** * Callback type for event_finalize and event_free_finalize(). **/ typedef void (*event_finalize_callback_fn)(struct event *, void *); /** @name Finalization functions These functions are used to safely tear down an event in a multithreaded application. If you construct your events with EV_FINALIZE to avoid deadlocks, you will need a way to remove an event in the certainty that it will definitely not be running its callback when you deallocate it and its callback argument. To do this, call one of event_finalize() or event_free_finalize with 0 for its first argument, the event to tear down as its second argument, and a callback function as its third argument. The callback will be invoked as part of the event loop, with the event's priority. After you call a finalizer function, event_add() and event_active() will no longer work on the event, and event_del() will produce a no-op. You must not try to change the event's fields with event_assign() or event_set() while the finalize callback is in progress. Once the callback has been invoked, you should treat the event structure as containing uninitialized memory. The event_free_finalize() function frees the event after it's finalized; event_finalize() does not. A finalizer callback must not make events pending or active. It must not add events, activate events, or attempt to "resuscitate" the event being finalized in any way. @return 0 on success, -1 on failure. */ /**@{*/ EVENT2_EXPORT_SYMBOL int event_finalize(unsigned, struct event *, event_finalize_callback_fn); EVENT2_EXPORT_SYMBOL int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn); /**@}*/ /** Schedule a one-time event The function event_base_once() is similar to event_new(). However, it schedules a callback to be called exactly once, and does not require the caller to prepare an event structure. Note that in Libevent 2.0 and earlier, if the event is never triggered, the internal memory used to hold it will never be freed. In Libevent 2.1, the internal memory will get freed by event_base_free() if the event is never triggered. The 'arg' value, however, will not get freed in either case--you'll need to free that on your own if you want it to go away. @param base an event_base @param fd a file descriptor to monitor, or -1 for no fd. @param events event(s) to monitor; can be any of EV_READ | EV_WRITE, or EV_TIMEOUT @param callback callback function to be invoked when the event occurs @param arg an argument to be passed to the callback function @param timeout the maximum amount of time to wait for the event. NULL makes an EV_READ/EV_WRITE event make forever; NULL makes an EV_TIMEOUT event success immediately. @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *); /** Add an event to the set of pending events. The function event_add() schedules the execution of the event 'ev' when the condition specified by event_assign() or event_new() occurs, or when the time specified in timeout has elapsed. If a timeout is NULL, no timeout occurs and the function will only be called if a matching event occurs. The event in the ev argument must be already initialized by event_assign() or event_new() and may not be used in calls to event_assign() until it is no longer pending. If the event in the ev argument already has a scheduled timeout, calling event_add() replaces the old timeout with the new one if tv is non-NULL. @param ev an event struct initialized via event_assign() or event_new() @param timeout the maximum amount of time to wait for the event, or NULL to wait forever @return 0 if successful, or -1 if an error occurred @see event_del(), event_assign(), event_new() */ EVENT2_EXPORT_SYMBOL int event_add(struct event *ev, const struct timeval *timeout); /** Remove a timer from a pending event without removing the event itself. If the event has a scheduled timeout, this function unschedules it but leaves the event otherwise pending. @param ev an event struct initialized via event_assign() or event_new() @return 0 on success, or -1 if an error occurred. */ EVENT2_EXPORT_SYMBOL int event_remove_timer(struct event *ev); /** Remove an event from the set of monitored events. The function event_del() will cancel the event in the argument ev. If the event has already executed or has never been added the call will have no effect. @param ev an event struct to be removed from the working set @return 0 if successful, or -1 if an error occurred @see event_add() */ EVENT2_EXPORT_SYMBOL int event_del(struct event *); /** As event_del(), but never blocks while the event's callback is running in another thread, even if the event was constructed without the EV_FINALIZE flag. */ EVENT2_EXPORT_SYMBOL int event_del_noblock(struct event *ev); /** As event_del(), but always blocks while the event's callback is running in another thread, even if the event was constructed with the EV_FINALIZE flag. */ EVENT2_EXPORT_SYMBOL int event_del_block(struct event *ev); /** Make an event active. You can use this function on a pending or a non-pending event to make it active, so that its callback will be run by event_base_dispatch() or event_base_loop(). One common use in multithreaded programs is to wake the thread running event_base_loop() from another thread. @param ev an event to make active. @param res a set of flags to pass to the event's callback. @param ncalls an obsolete argument: this is ignored. **/ EVENT2_EXPORT_SYMBOL void event_active(struct event *ev, int res, short ncalls); /** Checks if a specific event is pending or scheduled. @param ev an event struct previously passed to event_add() @param events the requested event type; any of EV_TIMEOUT|EV_READ| EV_WRITE|EV_SIGNAL @param tv if this field is not NULL, and the event has a timeout, this field is set to hold the time at which the timeout will expire. @return true if the event is pending on any of the events in 'what', (that is to say, it has been added), or 0 if the event is not added. */ EVENT2_EXPORT_SYMBOL int event_pending(const struct event *ev, short events, struct timeval *tv); /** If called from within the callback for an event, returns that event. The behavior of this function is not defined when called from outside the callback function for an event. */ EVENT2_EXPORT_SYMBOL struct event *event_base_get_running_event(struct event_base *base); /** Test if an event structure might be initialized. The event_initialized() function can be used to check if an event has been initialized. Warning: This function is only useful for distinguishing a zeroed-out piece of memory from an initialized event, it can easily be confused by uninitialized memory. Thus, it should ONLY be used to distinguish an initialized event from zero. @param ev an event structure to be tested @return 1 if the structure might be initialized, or 0 if it has not been initialized */ EVENT2_EXPORT_SYMBOL int event_initialized(const struct event *ev); /** Get the signal number assigned to a signal event */ #define event_get_signal(ev) ((int)event_get_fd(ev)) /** Get the socket or signal assigned to an event, or -1 if the event has no socket. */ EVENT2_EXPORT_SYMBOL evutil_socket_t event_get_fd(const struct event *ev); /** Get the event_base associated with an event. */ EVENT2_EXPORT_SYMBOL struct event_base *event_get_base(const struct event *ev); /** Return the events (EV_READ, EV_WRITE, etc) assigned to an event. */ EVENT2_EXPORT_SYMBOL short event_get_events(const struct event *ev); /** Return the callback assigned to an event. */ EVENT2_EXPORT_SYMBOL event_callback_fn event_get_callback(const struct event *ev); /** Return the callback argument assigned to an event. */ EVENT2_EXPORT_SYMBOL void *event_get_callback_arg(const struct event *ev); /** Return the priority of an event. @see event_priority_init(), event_get_priority() */ EVENT2_EXPORT_SYMBOL int event_get_priority(const struct event *ev); /** Extract _all_ of arguments given to construct a given event. The event_base is copied into *base_out, the fd is copied into *fd_out, and so on. If any of the "_out" arguments is NULL, it will be ignored. */ EVENT2_EXPORT_SYMBOL void event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out); /** Return the size of struct event that the Libevent library was compiled with. This will be NO GREATER than sizeof(struct event) if you're running with the same version of Libevent that your application was built with, but otherwise might not. Note that it might be SMALLER than sizeof(struct event) if some future version of Libevent adds extra padding to the end of struct event. We might do this to help ensure ABI-compatibility between different versions of Libevent. */ EVENT2_EXPORT_SYMBOL size_t event_get_struct_event_size(void); /** Get the Libevent version. Note that this will give you the version of the library that you're currently linked against, not the version of the headers that you've compiled against. @return a string containing the version number of Libevent */ EVENT2_EXPORT_SYMBOL const char *event_get_version(void); /** Return a numeric representation of Libevent's version. Note that this will give you the version of the library that you're currently linked against, not the version of the headers you've used to compile. The format uses one byte each for the major, minor, and patchlevel parts of the version number. The low-order byte is unused. For example, version 2.0.1-alpha has a numeric representation of 0x02000100 */ EVENT2_EXPORT_SYMBOL ev_uint32_t event_get_version_number(void); /** As event_get_version, but gives the version of Libevent's headers. */ #define LIBEVENT_VERSION EVENT__VERSION /** As event_get_version_number, but gives the version number of Libevent's * headers. */ #define LIBEVENT_VERSION_NUMBER EVENT__NUMERIC_VERSION /** Largest number of priorities that Libevent can support. */ #define EVENT_MAX_PRIORITIES 256 /** Set the number of different event priorities By default Libevent schedules all active events with the same priority. However, some time it is desirable to process some events with a higher priority than others. For that reason, Libevent supports strict priority queues. Active events with a lower priority are always processed before events with a higher priority. The number of different priorities can be set initially with the event_base_priority_init() function. This function should be called before the first call to event_base_dispatch(). The event_priority_set() function can be used to assign a priority to an event. By default, Libevent assigns the middle priority to all events unless their priority is explicitly set. Note that urgent-priority events can starve less-urgent events: after running all urgent-priority callbacks, Libevent checks for more urgent events again, before running less-urgent events. Less-urgent events will not have their callbacks run until there are no events more urgent than them that want to be active. @param eb the event_base structure returned by event_base_new() @param npriorities the maximum number of priorities @return 0 if successful, or -1 if an error occurred @see event_priority_set() */ EVENT2_EXPORT_SYMBOL int event_base_priority_init(struct event_base *, int); /** Get the number of different event priorities. @param eb the event_base structure returned by event_base_new() @return Number of different event priorities @see event_base_priority_init() */ EVENT2_EXPORT_SYMBOL int event_base_get_npriorities(struct event_base *eb); /** Assign a priority to an event. @param ev an event struct @param priority the new priority to be assigned @return 0 if successful, or -1 if an error occurred @see event_priority_init(), event_get_priority() */ EVENT2_EXPORT_SYMBOL int event_priority_set(struct event *, int); /** Prepare an event_base to use a large number of timeouts with the same duration. Libevent's default scheduling algorithm is optimized for having a large number of timeouts with their durations more or less randomly distributed. But if you have a large number of timeouts that all have the same duration (for example, if you have a large number of connections that all have a 10-second timeout), then you can improve Libevent's performance by telling Libevent about it. To do this, call this function with the common duration. It will return a pointer to a different, opaque timeout value. (Don't depend on its actual contents!) When you use this timeout value in event_add(), Libevent will schedule the event more efficiently. (This optimization probably will not be worthwhile until you have thousands or tens of thousands of events with the same timeout.) */ EVENT2_EXPORT_SYMBOL const struct timeval *event_base_init_common_timeout(struct event_base *base, const struct timeval *duration); #if !defined(EVENT__DISABLE_MM_REPLACEMENT) || defined(EVENT_IN_DOXYGEN_) /** Override the functions that Libevent uses for memory management. Usually, Libevent uses the standard libc functions malloc, realloc, and free to allocate memory. Passing replacements for those functions to event_set_mem_functions() overrides this behavior. Note that all memory returned from Libevent will be allocated by the replacement functions rather than by malloc() and realloc(). Thus, if you have replaced those functions, it will not be appropriate to free() memory that you get from Libevent. Instead, you must use the free_fn replacement that you provided. Note also that if you are going to call this function, you should do so before any call to any Libevent function that does allocation. Otherwise, those functions will allocate their memory using malloc(), but then later free it using your provided free_fn. @param malloc_fn A replacement for malloc. @param realloc_fn A replacement for realloc @param free_fn A replacement for free. **/ EVENT2_EXPORT_SYMBOL void event_set_mem_functions( void *(*malloc_fn)(size_t sz), void *(*realloc_fn)(void *ptr, size_t sz), void (*free_fn)(void *ptr)); /** This definition is present if Libevent was built with support for event_set_mem_functions() */ #define EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED #endif /** Writes a human-readable description of all inserted and/or active events to a provided stdio stream. This is intended for debugging; its format is not guaranteed to be the same between libevent versions. @param base An event_base on which to scan the events. @param output A stdio file to write on. */ EVENT2_EXPORT_SYMBOL void event_base_dump_events(struct event_base *, FILE *); /** Activates all pending events for the given fd and event mask. This function activates pending events only. Events which have not been added will not become active. @param base the event_base on which to activate the events. @param fd An fd to active events on. @param events One or more of EV_{READ,WRITE,TIMEOUT}. */ EVENT2_EXPORT_SYMBOL void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events); /** Activates all pending signals with a given signal number This function activates pending events only. Events which have not been added will not become active. @param base the event_base on which to activate the events. @param fd The signal to active events on. */ EVENT2_EXPORT_SYMBOL void event_base_active_by_signal(struct event_base *base, int sig); /** * Callback for iterating events in an event base via event_base_foreach_event */ typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *); /** Iterate over all added or active events events in an event loop, and invoke a given callback on each one. The callback must not call any function that modifies the event base, that modifies any event in the event base, or that adds or removes any event to the event base. Doing so is unsupported and will lead to undefined behavior -- likely, to crashes. event_base_foreach_event() holds a lock on the event_base() for the whole time it's running: slow callbacks are not advisable. Note that Libevent adds some events of its own to make pieces of its functionality work. You must not assume that the only events you'll encounter will be the ones you added yourself. The callback function must return 0 to continue iteration, or some other integer to stop iterating. @param base An event_base on which to scan the events. @param fn A callback function to receive the events. @param arg An argument passed to the callback function. @return 0 if we iterated over every event, or the value returned by the callback function if the loop exited early. */ EVENT2_EXPORT_SYMBOL int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg); /** Sets 'tv' to the current time (as returned by gettimeofday()), looking at the cached value in 'base' if possible, and calling gettimeofday() or clock_gettime() as appropriate if there is no cached time. Generally, this value will only be cached while actually processing event callbacks, and may be very inaccurate if your callbacks take a long time to execute. Returns 0 on success, negative on failure. */ EVENT2_EXPORT_SYMBOL int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv); /** Update cached_tv in the 'base' to the current time * * You can use this function is useful for selectively increasing * the accuracy of the cached time value in 'base' during callbacks * that take a long time to execute. * * This function has no effect if the base is currently not in its * event loop, or if timeval caching is disabled via * EVENT_BASE_FLAG_NO_CACHE_TIME. * * @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int event_base_update_cache_time(struct event_base *base); /** Release up all globally-allocated resources allocated by Libevent. This function does not free developer-controlled resources like event_bases, events, bufferevents, listeners, and so on. It only releases resources like global locks that there is no other way to free. It is not actually necessary to call this function before exit: every resource that it frees would be released anyway on exit. It mainly exists so that resource-leak debugging tools don't see Libevent as holding resources at exit. You should only call this function when no other Libevent functions will be invoked -- e.g., when cleanly exiting a program. */ EVENT2_EXPORT_SYMBOL void libevent_global_shutdown(void); #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/http.h0000644000076400001440000012347114111362573021172 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_HTTP_H_INCLUDED_ #define EVENT2_HTTP_H_INCLUDED_ /* For int types. */ #include #include #ifdef __cplusplus extern "C" { #endif /* In case we haven't included the right headers yet. */ struct evbuffer; struct event_base; struct bufferevent; struct evhttp_connection; /** @file event2/http.h * * Basic support for HTTP serving. * * As Libevent is a library for dealing with event notification and most * interesting applications are networked today, I have often found the * need to write HTTP code. The following prototypes and definitions provide * an application with a minimal interface for making HTTP requests and for * creating a very simple HTTP server. */ /* Response codes */ #define HTTP_OK 200 /**< request completed ok */ #define HTTP_NOCONTENT 204 /**< request does not have content */ #define HTTP_MOVEPERM 301 /**< the uri moved permanently */ #define HTTP_MOVETEMP 302 /**< the uri moved temporarily */ #define HTTP_NOTMODIFIED 304 /**< page was not modified from last */ #define HTTP_BADREQUEST 400 /**< invalid http request was made */ #define HTTP_NOTFOUND 404 /**< could not find content for uri */ #define HTTP_BADMETHOD 405 /**< method not allowed for this uri */ #define HTTP_ENTITYTOOLARGE 413 /**< */ #define HTTP_EXPECTATIONFAILED 417 /**< we can't handle this expectation */ #define HTTP_INTERNAL 500 /**< internal error */ #define HTTP_NOTIMPLEMENTED 501 /**< not implemented */ #define HTTP_SERVUNAVAIL 503 /**< the server is not available */ struct evhttp; struct evhttp_request; struct evkeyvalq; struct evhttp_bound_socket; struct evconnlistener; struct evdns_base; /** * Create a new HTTP server. * * @param base (optional) the event base to receive the HTTP events * @return a pointer to a newly initialized evhttp server structure or NULL * on error * @see evhttp_free() */ EVENT2_EXPORT_SYMBOL struct evhttp *evhttp_new(struct event_base *base); /** * Binds an HTTP server on the specified address and port. * * Can be called multiple times to bind the same http server * to multiple different ports. * * @param http a pointer to an evhttp object * @param address a string containing the IP address to listen(2) on * @param port the port number to listen on * @return 0 on success, -1 on failure. * @see evhttp_accept_socket() */ EVENT2_EXPORT_SYMBOL int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port); /** * Like evhttp_bind_socket(), but returns a handle for referencing the socket. * * The returned pointer is not valid after \a http is freed. * * @param http a pointer to an evhttp object * @param address a string containing the IP address to listen(2) on * @param port the port number to listen on * @return Handle for the socket on success, NULL on failure. * @see evhttp_bind_socket(), evhttp_del_accept_socket() */ EVENT2_EXPORT_SYMBOL struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port); /** * Makes an HTTP server accept connections on the specified socket. * * This may be useful to create a socket and then fork multiple instances * of an http server, or when a socket has been communicated via file * descriptor passing in situations where an http servers does not have * permissions to bind to a low-numbered port. * * Can be called multiple times to have the http server listen to * multiple different sockets. * * @param http a pointer to an evhttp object * @param fd a socket fd that is ready for accepting connections * @return 0 on success, -1 on failure. * @see evhttp_bind_socket() */ EVENT2_EXPORT_SYMBOL int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd); /** * Like evhttp_accept_socket(), but returns a handle for referencing the socket. * * The returned pointer is not valid after \a http is freed. * * @param http a pointer to an evhttp object * @param fd a socket fd that is ready for accepting connections * @return Handle for the socket on success, NULL on failure. * @see evhttp_accept_socket(), evhttp_del_accept_socket() */ EVENT2_EXPORT_SYMBOL struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd); /** * The most low-level evhttp_bind/accept method: takes an evconnlistener, and * returns an evhttp_bound_socket. The listener will be freed when the bound * socket is freed. */ EVENT2_EXPORT_SYMBOL struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener); /** * Return the listener used to implement a bound socket. */ EVENT2_EXPORT_SYMBOL struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound); typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *); /** * Applies the function specified in the first argument to all * evhttp_bound_sockets associated with "http". The user must not * attempt to free or remove any connections, sockets or listeners * in the callback "function". * * @param http pointer to an evhttp object * @param function function to apply to every bound socket * @param argument pointer value passed to function for every socket iterated */ EVENT2_EXPORT_SYMBOL void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument); /** * Makes an HTTP server stop accepting connections on the specified socket * * This may be useful when a socket has been sent via file descriptor passing * and is no longer needed by the current process. * * If you created this bound socket with evhttp_bind_socket_with_handle or * evhttp_accept_socket_with_handle, this function closes the fd you provided. * If you created this bound socket with evhttp_bind_listener, this function * frees the listener you provided. * * \a bound_socket is an invalid pointer after this call returns. * * @param http a pointer to an evhttp object * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() */ EVENT2_EXPORT_SYMBOL void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound_socket); /** * Get the raw file descriptor referenced by an evhttp_bound_socket. * * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle * @return the file descriptor used by the bound socket * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() */ EVENT2_EXPORT_SYMBOL evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_socket); /** * Free the previously created HTTP server. * * Works only if no requests are currently being served. * * @param http the evhttp server object to be freed * @see evhttp_start() */ EVENT2_EXPORT_SYMBOL void evhttp_free(struct evhttp* http); /** XXX Document. */ EVENT2_EXPORT_SYMBOL void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size); /** XXX Document. */ EVENT2_EXPORT_SYMBOL void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size); /** Set the value to use for the Content-Type header when none was provided. If the content type string is NULL, the Content-Type header will not be automatically added. @param http the http server on which to set the default content type @param content_type the value for the Content-Type header */ EVENT2_EXPORT_SYMBOL void evhttp_set_default_content_type(struct evhttp *http, const char *content_type); /** Sets the what HTTP methods are supported in requests accepted by this server, and passed to user callbacks. If not supported they will generate a "405 Method not allowed" response. By default this includes the following methods: GET, POST, HEAD, PUT, DELETE @param http the http server on which to set the methods @param methods bit mask constructed from evhttp_cmd_type values */ EVENT2_EXPORT_SYMBOL void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods); /** Set a callback for a specified URI @param http the http sever on which to set the callback @param path the path for which to invoke the callback @param cb the callback function that gets invoked on requesting path @param cb_arg an additional context argument for the callback @return 0 on success, -1 if the callback existed already, -2 on failure */ EVENT2_EXPORT_SYMBOL int evhttp_set_cb(struct evhttp *http, const char *path, void (*cb)(struct evhttp_request *, void *), void *cb_arg); /** Removes the callback for a specified URI */ EVENT2_EXPORT_SYMBOL int evhttp_del_cb(struct evhttp *, const char *); /** Set a callback for all requests that are not caught by specific callbacks Invokes the specified callback for all requests that do not match any of the previously specified request paths. This is catchall for requests not specifically configured with evhttp_set_cb(). @param http the evhttp server object for which to set the callback @param cb the callback to invoke for any unmatched requests @param arg an context argument for the callback */ EVENT2_EXPORT_SYMBOL void evhttp_set_gencb(struct evhttp *http, void (*cb)(struct evhttp_request *, void *), void *arg); /** Set a callback used to create new bufferevents for connections to a given evhttp object. You can use this to override the default bufferevent type -- for example, to make this evhttp object use SSL bufferevents rather than unencrypted ones. New bufferevents must be allocated with no fd set on them. @param http the evhttp server object for which to set the callback @param cb the callback to invoke for incoming connections @param arg an context argument for the callback */ EVENT2_EXPORT_SYMBOL void evhttp_set_bevcb(struct evhttp *http, struct bufferevent *(*cb)(struct event_base *, void *), void *arg); /** Adds a virtual host to the http server. A virtual host is a newly initialized evhttp object that has request callbacks set on it via evhttp_set_cb() or evhttp_set_gencb(). It most not have any listing sockets associated with it. If the virtual host has not been removed by the time that evhttp_free() is called on the main http server, it will be automatically freed, too. It is possible to have hierarchical vhosts. For example: A vhost with the pattern *.example.com may have other vhosts with patterns foo.example.com and bar.example.com associated with it. @param http the evhttp object to which to add a virtual host @param pattern the glob pattern against which the hostname is matched. The match is case insensitive and follows otherwise regular shell matching. @param vhost the virtual host to add the regular http server. @return 0 on success, -1 on failure @see evhttp_remove_virtual_host() */ EVENT2_EXPORT_SYMBOL int evhttp_add_virtual_host(struct evhttp* http, const char *pattern, struct evhttp* vhost); /** Removes a virtual host from the http server. @param http the evhttp object from which to remove the virtual host @param vhost the virtual host to remove from the regular http server. @return 0 on success, -1 on failure @see evhttp_add_virtual_host() */ EVENT2_EXPORT_SYMBOL int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost); /** Add a server alias to an http object. The http object can be a virtual host or the main server. @param http the evhttp object @param alias the alias to add @see evhttp_add_remove_alias() */ EVENT2_EXPORT_SYMBOL int evhttp_add_server_alias(struct evhttp *http, const char *alias); /** Remove a server alias from an http object. @param http the evhttp object @param alias the alias to remove @see evhttp_add_server_alias() */ EVENT2_EXPORT_SYMBOL int evhttp_remove_server_alias(struct evhttp *http, const char *alias); /** * Set the timeout for an HTTP request. * * @param http an evhttp object * @param timeout_in_secs the timeout, in seconds */ EVENT2_EXPORT_SYMBOL void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs); /** * Set the timeout for an HTTP request. * * @param http an evhttp object * @param tv the timeout, or NULL */ EVENT2_EXPORT_SYMBOL void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv); /* Read all the clients body, and only after this respond with an error if the * clients body exceed max_body_size */ #define EVHTTP_SERVER_LINGERING_CLOSE 0x0001 /** * Set connection flags for HTTP server. * * @see EVHTTP_SERVER_* * @return 0 on success, otherwise non zero (for example if flag doesn't * supported). */ EVENT2_EXPORT_SYMBOL int evhttp_set_flags(struct evhttp *http, int flags); /* Request/Response functionality */ /** * Send an HTML error message to the client. * * @param req a request object * @param error the HTTP error code * @param reason a brief explanation of the error. If this is NULL, we'll * just use the standard meaning of the error code. */ EVENT2_EXPORT_SYMBOL void evhttp_send_error(struct evhttp_request *req, int error, const char *reason); /** * Send an HTML reply to the client. * * The body of the reply consists of the data in databuf. After calling * evhttp_send_reply() databuf will be empty, but the buffer is still * owned by the caller and needs to be deallocated by the caller if * necessary. * * @param req a request object * @param code the HTTP response code to send * @param reason a brief message to send with the response code * @param databuf the body of the response */ EVENT2_EXPORT_SYMBOL void evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *databuf); /* Low-level response interface, for streaming/chunked replies */ /** Initiate a reply that uses Transfer-Encoding chunked. This allows the caller to stream the reply back to the client and is useful when either not all of the reply data is immediately available or when sending very large replies. The caller needs to supply data chunks with evhttp_send_reply_chunk() and complete the reply by calling evhttp_send_reply_end(). @param req a request object @param code the HTTP response code to send @param reason a brief message to send with the response code */ EVENT2_EXPORT_SYMBOL void evhttp_send_reply_start(struct evhttp_request *req, int code, const char *reason); /** Send another data chunk as part of an ongoing chunked reply. The reply chunk consists of the data in databuf. After calling evhttp_send_reply_chunk() databuf will be empty, but the buffer is still owned by the caller and needs to be deallocated by the caller if necessary. @param req a request object @param databuf the data chunk to send as part of the reply. */ EVENT2_EXPORT_SYMBOL void evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf); /** Send another data chunk as part of an ongoing chunked reply. The reply chunk consists of the data in databuf. After calling evhttp_send_reply_chunk() databuf will be empty, but the buffer is still owned by the caller and needs to be deallocated by the caller if necessary. @param req a request object @param databuf the data chunk to send as part of the reply. @param cb callback funcion @param call back's argument. */ EVENT2_EXPORT_SYMBOL void evhttp_send_reply_chunk_with_cb(struct evhttp_request *, struct evbuffer *, void (*cb)(struct evhttp_connection *, void *), void *arg); /** Complete a chunked reply, freeing the request as appropriate. @param req a request object */ EVENT2_EXPORT_SYMBOL void evhttp_send_reply_end(struct evhttp_request *req); /* * Interfaces for making requests */ /** The different request types supported by evhttp. These are as specified * in RFC2616, except for PATCH which is specified by RFC5789. * * By default, only some of these methods are accepted and passed to user * callbacks; use evhttp_set_allowed_methods() to change which methods * are allowed. */ enum evhttp_cmd_type { EVHTTP_REQ_GET = 1 << 0, EVHTTP_REQ_POST = 1 << 1, EVHTTP_REQ_HEAD = 1 << 2, EVHTTP_REQ_PUT = 1 << 3, EVHTTP_REQ_DELETE = 1 << 4, EVHTTP_REQ_OPTIONS = 1 << 5, EVHTTP_REQ_TRACE = 1 << 6, EVHTTP_REQ_CONNECT = 1 << 7, EVHTTP_REQ_PATCH = 1 << 8 }; /** a request object can represent either a request or a reply */ enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; /** * Create and return a connection object that can be used to for making HTTP * requests. The connection object tries to resolve address and establish the * connection when it is given an http request object. * * @param base the event_base to use for handling the connection * @param dnsbase the dns_base to use for resolving host names; if not * specified host name resolution will block. * @param bev a bufferevent to use for connecting to the server; if NULL, a * socket-based bufferevent will be created. This buffrevent will be freed * when the connection closes. It must have no fd set on it. * @param address the address to which to connect * @param port the port to connect to * @return an evhttp_connection object that can be used for making requests or * NULL on error */ EVENT2_EXPORT_SYMBOL struct evhttp_connection *evhttp_connection_base_bufferevent_new( struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port); /** * Return the bufferevent that an evhttp_connection is using. */ EVENT2_EXPORT_SYMBOL struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon); /** * Return the HTTP server associated with this connection, or NULL. */ EVENT2_EXPORT_SYMBOL struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon); /** * Creates a new request object that needs to be filled in with the request * parameters. The callback is executed when the request completed or an * error occurred. */ EVENT2_EXPORT_SYMBOL struct evhttp_request *evhttp_request_new( void (*cb)(struct evhttp_request *, void *), void *arg); /** * Enable delivery of chunks to requestor. * @param cb will be called after every read of data with the same argument * as the completion callback. Will never be called on an empty * response. May drain the input buffer; it will be drained * automatically on return. */ EVENT2_EXPORT_SYMBOL void evhttp_request_set_chunked_cb(struct evhttp_request *, void (*cb)(struct evhttp_request *, void *)); /** * Register callback for additional parsing of request headers. * @param cb will be called after receiving and parsing the full header. * It allows analyzing the header and possibly closing the connection * by returning a value < 0. */ EVENT2_EXPORT_SYMBOL void evhttp_request_set_header_cb(struct evhttp_request *, int (*cb)(struct evhttp_request *, void *)); /** * The different error types supported by evhttp * * @see evhttp_request_set_error_cb() */ enum evhttp_request_error { /** * Timeout reached, also @see evhttp_connection_set_timeout() */ EVREQ_HTTP_TIMEOUT, /** * EOF reached */ EVREQ_HTTP_EOF, /** * Error while reading header, or invalid header */ EVREQ_HTTP_INVALID_HEADER, /** * Error encountered while reading or writing */ EVREQ_HTTP_BUFFER_ERROR, /** * The evhttp_cancel_request() called on this request. */ EVREQ_HTTP_REQUEST_CANCEL, /** * Body is greater then evhttp_connection_set_max_body_size() */ EVREQ_HTTP_DATA_TOO_LONG }; /** * Set a callback for errors * @see evhttp_request_error for error types. * * On error, both the error callback and the regular callback will be called, * error callback is called before the regular callback. **/ EVENT2_EXPORT_SYMBOL void evhttp_request_set_error_cb(struct evhttp_request *, void (*)(enum evhttp_request_error, void *)); /** * Set a callback to be called on request completion of evhttp_send_* function. * * The callback function will be called on the completion of the request after * the output data has been written and before the evhttp_request object * is destroyed. This can be useful for tracking resources associated with a * request (ex: timing metrics). * * @param req a request object * @param cb callback function that will be called on request completion * @param cb_arg an additional context argument for the callback */ EVENT2_EXPORT_SYMBOL void evhttp_request_set_on_complete_cb(struct evhttp_request *req, void (*cb)(struct evhttp_request *, void *), void *cb_arg); /** Frees the request object and removes associated events. */ EVENT2_EXPORT_SYMBOL void evhttp_request_free(struct evhttp_request *req); /** * Create and return a connection object that can be used to for making HTTP * requests. The connection object tries to resolve address and establish the * connection when it is given an http request object. * * @param base the event_base to use for handling the connection * @param dnsbase the dns_base to use for resolving host names; if not * specified host name resolution will block. * @param address the address to which to connect * @param port the port to connect to * @return an evhttp_connection object that can be used for making requests or * NULL on error */ EVENT2_EXPORT_SYMBOL struct evhttp_connection *evhttp_connection_base_new( struct event_base *base, struct evdns_base *dnsbase, const char *address, ev_uint16_t port); /** * Set family hint for DNS requests. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_family(struct evhttp_connection *evcon, int family); /* reuse connection address on retry */ #define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 /* Try to read error, since server may already send and close * connection, but if at that time we have some data to send then we * can send get EPIPE and fail, while we can read that HTTP error. */ #define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010 /* @see EVHTTP_SERVER_LINGERING_CLOSE */ #define EVHTTP_CON_LINGERING_CLOSE 0x0020 /* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ #define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 /** * Set connection flags. * * @see EVHTTP_CON_* * @return 0 on success, otherwise non zero (for example if flag doesn't * supported). */ EVENT2_EXPORT_SYMBOL int evhttp_connection_set_flags(struct evhttp_connection *evcon, int flags); /** Takes ownership of the request object * * Can be used in a request callback to keep onto the request until * evhttp_request_free() is explicitly called by the user. */ EVENT2_EXPORT_SYMBOL void evhttp_request_own(struct evhttp_request *req); /** Returns 1 if the request is owned by the user */ EVENT2_EXPORT_SYMBOL int evhttp_request_is_owned(struct evhttp_request *req); /** * Returns the connection object associated with the request or NULL * * The user needs to either free the request explicitly or call * evhttp_send_reply_end(). */ EVENT2_EXPORT_SYMBOL struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req); /** * Returns the underlying event_base for this connection */ EVENT2_EXPORT_SYMBOL struct event_base *evhttp_connection_get_base(struct evhttp_connection *req); EVENT2_EXPORT_SYMBOL void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, ev_ssize_t new_max_headers_size); EVENT2_EXPORT_SYMBOL void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, ev_ssize_t new_max_body_size); /** Frees an http connection */ EVENT2_EXPORT_SYMBOL void evhttp_connection_free(struct evhttp_connection *evcon); /** Disowns a given connection object * * Can be used to tell libevent to free the connection object after * the last request has completed or failed. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_free_on_completion(struct evhttp_connection *evcon); /** sets the ip address from which http connections are made */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_local_address(struct evhttp_connection *evcon, const char *address); /** sets the local port from which http connections are made */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_local_port(struct evhttp_connection *evcon, ev_uint16_t port); /** Sets the timeout in seconds for events related to this connection */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_timeout(struct evhttp_connection *evcon, int timeout_in_secs); /** Sets the timeout for events related to this connection. Takes a struct * timeval. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, const struct timeval *tv); /** Sets the delay before retrying requests on this connection. This is only * used if evhttp_connection_set_retries is used to make the number of retries * at least one. Each retry after the first is twice as long as the one before * it. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, const struct timeval *tv); /** Sets the retry limit for this connection - -1 repeats indefinitely */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_retries(struct evhttp_connection *evcon, int retry_max); /** Set a callback for connection close. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_closecb(struct evhttp_connection *evcon, void (*)(struct evhttp_connection *, void *), void *); /** Get the remote address and port associated with this connection. */ EVENT2_EXPORT_SYMBOL void evhttp_connection_get_peer(struct evhttp_connection *evcon, char **address, ev_uint16_t *port); /** Get the remote address associated with this connection. * extracted from getpeername() OR from nameserver. * * @return NULL if getpeername() return non success, * or connection is not connected, * otherwise it return pointer to struct sockaddr_storage */ EVENT2_EXPORT_SYMBOL const struct sockaddr* evhttp_connection_get_addr(struct evhttp_connection *evcon); /** Make an HTTP request over the specified connection. The connection gets ownership of the request. On failure, the request object is no longer valid as it has been freed. @param evcon the evhttp_connection object over which to send the request @param req the previously created and configured request object @param type the request type EVHTTP_REQ_GET, EVHTTP_REQ_POST, etc. @param uri the URI associated with the request @return 0 on success, -1 on failure @see evhttp_cancel_request() */ EVENT2_EXPORT_SYMBOL int evhttp_make_request(struct evhttp_connection *evcon, struct evhttp_request *req, enum evhttp_cmd_type type, const char *uri); /** Cancels a pending HTTP request. Cancels an ongoing HTTP request. The callback associated with this request is not executed and the request object is freed. If the request is currently being processed, e.g. it is ongoing, the corresponding evhttp_connection object is going to get reset. A request cannot be canceled if its callback has executed already. A request may be canceled reentrantly from its chunked callback. @param req the evhttp_request to cancel; req becomes invalid after this call. */ EVENT2_EXPORT_SYMBOL void evhttp_cancel_request(struct evhttp_request *req); /** * A structure to hold a parsed URI or Relative-Ref conforming to RFC3986. */ struct evhttp_uri; /** Returns the request URI */ EVENT2_EXPORT_SYMBOL const char *evhttp_request_get_uri(const struct evhttp_request *req); /** Returns the request URI (parsed) */ EVENT2_EXPORT_SYMBOL const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req); /** Returns the request command */ EVENT2_EXPORT_SYMBOL enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req); EVENT2_EXPORT_SYMBOL int evhttp_request_get_response_code(const struct evhttp_request *req); EVENT2_EXPORT_SYMBOL const char * evhttp_request_get_response_code_line(const struct evhttp_request *req); /** Returns the input headers */ EVENT2_EXPORT_SYMBOL struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req); /** Returns the output headers */ EVENT2_EXPORT_SYMBOL struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req); /** Returns the input buffer */ EVENT2_EXPORT_SYMBOL struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req); /** Returns the output buffer */ EVENT2_EXPORT_SYMBOL struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req); /** Returns the host associated with the request. If a client sends an absolute URI, the host part of that is preferred. Otherwise, the input headers are searched for a Host: header. NULL is returned if no absolute URI or Host: header is provided. */ EVENT2_EXPORT_SYMBOL const char *evhttp_request_get_host(struct evhttp_request *req); /* Interfaces for dealing with HTTP headers */ /** Finds the value belonging to a header. @param headers the evkeyvalq object in which to find the header @param key the name of the header to find @returns a pointer to the value for the header or NULL if the header could not be found. @see evhttp_add_header(), evhttp_remove_header() */ EVENT2_EXPORT_SYMBOL const char *evhttp_find_header(const struct evkeyvalq *headers, const char *key); /** Removes a header from a list of existing headers. @param headers the evkeyvalq object from which to remove a header @param key the name of the header to remove @returns 0 if the header was removed, -1 otherwise. @see evhttp_find_header(), evhttp_add_header() */ EVENT2_EXPORT_SYMBOL int evhttp_remove_header(struct evkeyvalq *headers, const char *key); /** Adds a header to a list of existing headers. @param headers the evkeyvalq object to which to add a header @param key the name of the header @param value the value belonging to the header @returns 0 on success, -1 otherwise. @see evhttp_find_header(), evhttp_clear_headers() */ EVENT2_EXPORT_SYMBOL int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value); /** Removes all headers from the header list. @param headers the evkeyvalq object from which to remove all headers */ EVENT2_EXPORT_SYMBOL void evhttp_clear_headers(struct evkeyvalq *headers); /* Miscellaneous utility functions */ /** Helper function to encode a string for inclusion in a URI. All characters are replaced by their hex-escaped (%22) equivalents, except for characters explicitly unreserved by RFC3986 -- that is, ASCII alphanumeric characters, hyphen, dot, underscore, and tilde. The returned string must be freed by the caller. @param str an unencoded string @return a newly allocated URI-encoded string or NULL on failure */ EVENT2_EXPORT_SYMBOL char *evhttp_encode_uri(const char *str); /** As evhttp_encode_uri, but if 'size' is nonnegative, treat the string as being 'size' bytes long. This allows you to encode strings that may contain 0-valued bytes. The returned string must be freed by the caller. @param str an unencoded string @param size the length of the string to encode, or -1 if the string is NUL-terminated @param space_to_plus if true, space characters in 'str' are encoded as +, not %20. @return a newly allocate URI-encoded string, or NULL on failure. */ EVENT2_EXPORT_SYMBOL char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus); /** Helper function to sort of decode a URI-encoded string. Unlike evhttp_uridecode, it decodes all plus characters that appear _after_ the first question mark character, but no plusses that occur before. This is not a good way to decode URIs in whole or in part. The returned string must be freed by the caller @deprecated This function is deprecated; you probably want to use evhttp_uridecode instead. @param uri an encoded URI @return a newly allocated unencoded URI or NULL on failure */ EVENT2_EXPORT_SYMBOL char *evhttp_decode_uri(const char *uri); /** Helper function to decode a URI-escaped string or HTTP parameter. If 'decode_plus' is 1, then we decode the string as an HTTP parameter value, and convert all plus ('+') characters to spaces. If 'decode_plus' is 0, we leave all plus characters unchanged. The returned string must be freed by the caller. @param uri a URI-encode encoded URI @param decode_plus determines whether we convert '+' to space. @param size_out if size_out is not NULL, *size_out is set to the size of the returned string @return a newly allocated unencoded URI or NULL on failure */ EVENT2_EXPORT_SYMBOL char *evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out); /** Helper function to parse out arguments in a query. Parsing a URI like http://foo.com/?q=test&s=some+thing will result in two entries in the key value queue. The first entry is: key="q", value="test" The second entry is: key="s", value="some thing" @deprecated This function is deprecated as of Libevent 2.0.9. Use evhttp_uri_parse and evhttp_parse_query_str instead. @param uri the request URI @param headers the head of the evkeyval queue @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evhttp_parse_query(const char *uri, struct evkeyvalq *headers); /** Helper function to parse out arguments from the query portion of an HTTP URI. Parsing a query string like q=test&s=some+thing will result in two entries in the key value queue. The first entry is: key="q", value="test" The second entry is: key="s", value="some thing" @param query_parse the query portion of the URI @param headers the head of the evkeyval queue @return 0 on success, -1 on failure */ EVENT2_EXPORT_SYMBOL int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers); /** * Escape HTML character entities in a string. * * Replaces <, >, ", ' and & with <, >, ", * ' and & correspondingly. * * The returned string needs to be freed by the caller. * * @param html an unescaped HTML string * @return an escaped HTML string or NULL on error */ EVENT2_EXPORT_SYMBOL char *evhttp_htmlescape(const char *html); /** * Return a new empty evhttp_uri with no fields set. */ EVENT2_EXPORT_SYMBOL struct evhttp_uri *evhttp_uri_new(void); /** * Changes the flags set on a given URI. See EVHTTP_URI_* for * a list of flags. **/ EVENT2_EXPORT_SYMBOL void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags); /** Return the scheme of an evhttp_uri, or NULL if there is no scheme has * been set and the evhttp_uri contains a Relative-Ref. */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri); /** * Return the userinfo part of an evhttp_uri, or NULL if it has no userinfo * set. */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri); /** * Return the host part of an evhttp_uri, or NULL if it has no host set. * The host may either be a regular hostname (conforming to the RFC 3986 * "regname" production), or an IPv4 address, or the empty string, or a * bracketed IPv6 address, or a bracketed 'IP-Future' address. * * Note that having a NULL host means that the URI has no authority * section, but having an empty-string host means that the URI has an * authority section with no host part. For example, * "mailto:user@example.com" has a host of NULL, but "file:///etc/motd" * has a host of "". */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_host(const struct evhttp_uri *uri); /** Return the port part of an evhttp_uri, or -1 if there is no port set. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_get_port(const struct evhttp_uri *uri); /** Return the path part of an evhttp_uri, or NULL if it has no path set */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_path(const struct evhttp_uri *uri); /** Return the query part of an evhttp_uri (excluding the leading "?"), or * NULL if it has no query set */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_query(const struct evhttp_uri *uri); /** Return the fragment part of an evhttp_uri (excluding the leading "#"), * or NULL if it has no fragment set */ EVENT2_EXPORT_SYMBOL const char *evhttp_uri_get_fragment(const struct evhttp_uri *uri); /** Set the scheme of an evhttp_uri, or clear the scheme if scheme==NULL. * Returns 0 on success, -1 if scheme is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme); /** Set the userinfo of an evhttp_uri, or clear the userinfo if userinfo==NULL. * Returns 0 on success, -1 if userinfo is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo); /** Set the host of an evhttp_uri, or clear the host if host==NULL. * Returns 0 on success, -1 if host is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host); /** Set the port of an evhttp_uri, or clear the port if port==-1. * Returns 0 on success, -1 if port is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_port(struct evhttp_uri *uri, int port); /** Set the path of an evhttp_uri, or clear the path if path==NULL. * Returns 0 on success, -1 if path is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path); /** Set the query of an evhttp_uri, or clear the query if query==NULL. * The query should not include a leading "?". * Returns 0 on success, -1 if query is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query); /** Set the fragment of an evhttp_uri, or clear the fragment if fragment==NULL. * The fragment should not include a leading "#". * Returns 0 on success, -1 if fragment is not well-formed. */ EVENT2_EXPORT_SYMBOL int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment); /** * Helper function to parse a URI-Reference as specified by RFC3986. * * This function matches the URI-Reference production from RFC3986, * which includes both URIs like * * scheme://[[userinfo]@]foo.com[:port]]/[path][?query][#fragment] * * and relative-refs like * * [path][?query][#fragment] * * Any optional elements portions not present in the original URI are * left set to NULL in the resulting evhttp_uri. If no port is * specified, the port is set to -1. * * Note that no decoding is performed on percent-escaped characters in * the string; if you want to parse them, use evhttp_uridecode or * evhttp_parse_query_str as appropriate. * * Note also that most URI schemes will have additional constraints that * this function does not know about, and cannot check. For example, * mailto://www.example.com/cgi-bin/fortune.pl is not a reasonable * mailto url, http://www.example.com:99999/ is not a reasonable HTTP * URL, and ftp:username@example.com is not a reasonable FTP URL. * Nevertheless, all of these URLs conform to RFC3986, and this function * accepts all of them as valid. * * @param source_uri the request URI * @param flags Zero or more EVHTTP_URI_* flags to affect the behavior * of the parser. * @return uri container to hold parsed data, or NULL if there is error * @see evhttp_uri_free() */ EVENT2_EXPORT_SYMBOL struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags); /** Tolerate URIs that do not conform to RFC3986. * * Unfortunately, some HTTP clients generate URIs that, according to RFC3986, * are not conformant URIs. If you need to support these URIs, you can * do so by passing this flag to evhttp_uri_parse_with_flags. * * Currently, these changes are: *
    *
  • Nonconformant URIs are allowed to contain otherwise unreasonable * characters in their path, query, and fragment components. *
*/ #define EVHTTP_URI_NONCONFORMANT 0x01 /** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */ EVENT2_EXPORT_SYMBOL struct evhttp_uri *evhttp_uri_parse(const char *source_uri); /** * Free all memory allocated for a parsed uri. Only use this for URIs * generated by evhttp_uri_parse. * * @param uri container with parsed data * @see evhttp_uri_parse() */ EVENT2_EXPORT_SYMBOL void evhttp_uri_free(struct evhttp_uri *uri); /** * Join together the uri parts from parsed data to form a URI-Reference. * * Note that no escaping of reserved characters is done on the members * of the evhttp_uri, so the generated string might not be a valid URI * unless the members of evhttp_uri are themselves valid. * * @param uri container with parsed data * @param buf destination buffer * @param limit destination buffer size * @return an joined uri as string or NULL on error * @see evhttp_uri_parse() */ EVENT2_EXPORT_SYMBOL char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit); #ifdef __cplusplus } #endif #endif /* EVENT2_HTTP_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/rpc_compat.h0000644000076400001440000000445714111362573022344 0ustar00bernatusers00000000000000/* * Copyright (c) 2006-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ #define EVENT2_RPC_COMPAT_H_INCLUDED_ /** @file event2/rpc_compat.h Deprecated versions of the functions in rpc.h: provided only for backwards compatibility. */ #ifdef __cplusplus extern "C" { #endif /** backwards compatible accessors that work only with gcc */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) #undef EVTAG_ASSIGN #undef EVTAG_GET #undef EVTAG_ADD #define EVTAG_ASSIGN(msg, member, args...) \ (*(msg)->base->member##_assign)(msg, ## args) #define EVTAG_GET(msg, member, args...) \ (*(msg)->base->member##_get)(msg, ## args) #define EVTAG_ADD(msg, member, args...) \ (*(msg)->base->member##_add)(msg, ## args) #endif #define EVTAG_LEN(msg, member) ((msg)->member##_length) #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/thread.h0000644000076400001440000002334014111362573021454 0ustar00bernatusers00000000000000/* * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_THREAD_H_INCLUDED_ #define EVENT2_THREAD_H_INCLUDED_ /** @file event2/thread.h Functions for multi-threaded applications using Libevent. When using a multi-threaded application in which multiple threads add and delete events from a single event base, Libevent needs to lock its data structures. Like the memory-management function hooks, all of the threading functions _must_ be set up before an event_base is created if you want the base to use them. Most programs will either be using Windows threads or Posix threads. You can configure Libevent to use one of these event_use_windows_threads() or event_use_pthreads() respectively. If you're using another threading library, you'll need to configure threading functions manually using evthread_set_lock_callbacks() and evthread_set_condition_callbacks(). */ #include #ifdef __cplusplus extern "C" { #endif #include /** @name Flags passed to lock functions @{ */ /** A flag passed to a locking callback when the lock was allocated as a * read-write lock, and we want to acquire or release the lock for writing. */ #define EVTHREAD_WRITE 0x04 /** A flag passed to a locking callback when the lock was allocated as a * read-write lock, and we want to acquire or release the lock for reading. */ #define EVTHREAD_READ 0x08 /** A flag passed to a locking callback when we don't want to block waiting * for the lock; if we can't get the lock immediately, we will instead * return nonzero from the locking callback. */ #define EVTHREAD_TRY 0x10 /**@}*/ #if !defined(EVENT__DISABLE_THREAD_SUPPORT) || defined(EVENT_IN_DOXYGEN_) #define EVTHREAD_LOCK_API_VERSION 1 /** @name Types of locks @{*/ /** A recursive lock is one that can be acquired multiple times at once by the * same thread. No other process can allocate the lock until the thread that * has been holding it has unlocked it as many times as it locked it. */ #define EVTHREAD_LOCKTYPE_RECURSIVE 1 /* A read-write lock is one that allows multiple simultaneous readers, but * where any one writer excludes all other writers and readers. */ #define EVTHREAD_LOCKTYPE_READWRITE 2 /**@}*/ /** This structure describes the interface a threading library uses for * locking. It's used to tell evthread_set_lock_callbacks() how to use * locking on this platform. */ struct evthread_lock_callbacks { /** The current version of the locking API. Set this to * EVTHREAD_LOCK_API_VERSION */ int lock_api_version; /** Which kinds of locks does this version of the locking API * support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and * EVTHREAD_LOCKTYPE_READWRITE. * * (Note that RECURSIVE locks are currently mandatory, and * READWRITE locks are not currently used.) **/ unsigned supported_locktypes; /** Function to allocate and initialize new lock of type 'locktype'. * Returns NULL on failure. */ void *(*alloc)(unsigned locktype); /** Funtion to release all storage held in 'lock', which was created * with type 'locktype'. */ void (*free)(void *lock, unsigned locktype); /** Acquire an already-allocated lock at 'lock' with mode 'mode'. * Returns 0 on success, and nonzero on failure. */ int (*lock)(unsigned mode, void *lock); /** Release a lock at 'lock' using mode 'mode'. Returns 0 on success, * and nonzero on failure. */ int (*unlock)(unsigned mode, void *lock); }; /** Sets a group of functions that Libevent should use for locking. * For full information on the required callback API, see the * documentation for the individual members of evthread_lock_callbacks. * * Note that if you're using Windows or the Pthreads threading library, you * probably shouldn't call this function; instead, use * evthread_use_windows_threads() or evthread_use_posix_threads() if you can. */ EVENT2_EXPORT_SYMBOL int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *); #define EVTHREAD_CONDITION_API_VERSION 1 struct timeval; /** This structure describes the interface a threading library uses for * condition variables. It's used to tell evthread_set_condition_callbacks * how to use locking on this platform. */ struct evthread_condition_callbacks { /** The current version of the conditions API. Set this to * EVTHREAD_CONDITION_API_VERSION */ int condition_api_version; /** Function to allocate and initialize a new condition variable. * Returns the condition variable on success, and NULL on failure. * The 'condtype' argument will be 0 with this API version. */ void *(*alloc_condition)(unsigned condtype); /** Function to free a condition variable. */ void (*free_condition)(void *cond); /** Function to signal a condition variable. If 'broadcast' is 1, all * threads waiting on 'cond' should be woken; otherwise, only on one * thread is worken. Should return 0 on success, -1 on failure. * This function will only be called while holding the associated * lock for the condition. */ int (*signal_condition)(void *cond, int broadcast); /** Function to wait for a condition variable. The lock 'lock' * will be held when this function is called; should be released * while waiting for the condition to be come signalled, and * should be held again when this function returns. * If timeout is provided, it is interval of seconds to wait for * the event to become signalled; if it is NULL, the function * should wait indefinitely. * * The function should return -1 on error; 0 if the condition * was signalled, or 1 on a timeout. */ int (*wait_condition)(void *cond, void *lock, const struct timeval *timeout); }; /** Sets a group of functions that Libevent should use for condition variables. * For full information on the required callback API, see the * documentation for the individual members of evthread_condition_callbacks. * * Note that if you're using Windows or the Pthreads threading library, you * probably shouldn't call this function; instead, use * evthread_use_windows_threads() or evthread_use_pthreads() if you can. */ EVENT2_EXPORT_SYMBOL int evthread_set_condition_callbacks( const struct evthread_condition_callbacks *); /** Sets the function for determining the thread id. @param base the event base for which to set the id function @param id_fn the identify function Libevent should invoke to determine the identity of a thread. */ EVENT2_EXPORT_SYMBOL void evthread_set_id_callback( unsigned long (*id_fn)(void)); #if (defined(_WIN32) && !defined(EVENT__DISABLE_THREAD_SUPPORT)) || defined(EVENT_IN_DOXYGEN_) /** Sets up Libevent for use with Windows builtin locking and thread ID functions. Unavailable if Libevent is not built for Windows. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evthread_use_windows_threads(void); /** Defined if Libevent was built with support for evthread_use_windows_threads() */ #define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1 #endif #if defined(EVENT__HAVE_PTHREADS) || defined(EVENT_IN_DOXYGEN_) /** Sets up Libevent for use with Pthreads locking and thread ID functions. Unavailable if Libevent is not build for use with pthreads. Requires libraries to link against Libevent_pthreads as well as Libevent. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evthread_use_pthreads(void); /** Defined if Libevent was built with support for evthread_use_pthreads() */ #define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1 #endif /** Enable debugging wrappers around the current lock callbacks. If Libevent * makes one of several common locking errors, exit with an assertion failure. * * If you're going to call this function, you must do so before any locks are * allocated. **/ EVENT2_EXPORT_SYMBOL void evthread_enable_lock_debugging(void); /* Old (misspelled) version: This is deprecated; use * evthread_enable_log_debugging instead. */ EVENT2_EXPORT_SYMBOL void evthread_enable_lock_debuging(void); #endif /* EVENT__DISABLE_THREAD_SUPPORT */ struct event_base; /** Make sure it's safe to tell an event base to wake up from another thread or a signal handler. You shouldn't need to call this by hand; configuring the base with thread support should be necessary and sufficient. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int evthread_make_base_notifiable(struct event_base *base); #ifdef __cplusplus } #endif #endif /* EVENT2_THREAD_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/http_struct.h0000644000076400001440000001131114111362573022563 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_HTTP_STRUCT_H_INCLUDED_ #define EVENT2_HTTP_STRUCT_H_INCLUDED_ /** @file event2/http_struct.h Data structures for http. Using these structures may hurt forward compatibility with later versions of Libevent: be careful! */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /** * the request structure that a server receives. * WARNING: expect this structure to change. I will try to provide * reasonable accessors. */ struct evhttp_request { #if defined(TAILQ_ENTRY) TAILQ_ENTRY(evhttp_request) next; #else struct { struct evhttp_request *tqe_next; struct evhttp_request **tqe_prev; } next; #endif /* the connection object that this request belongs to */ struct evhttp_connection *evcon; int flags; /** The request obj owns the evhttp connection and needs to free it */ #define EVHTTP_REQ_OWN_CONNECTION 0x0001 /** Request was made via a proxy */ #define EVHTTP_PROXY_REQUEST 0x0002 /** The request object is owned by the user; the user must free it */ #define EVHTTP_USER_OWNED 0x0004 /** The request will be used again upstack; freeing must be deferred */ #define EVHTTP_REQ_DEFER_FREE 0x0008 /** The request should be freed upstack */ #define EVHTTP_REQ_NEEDS_FREE 0x0010 struct evkeyvalq *input_headers; struct evkeyvalq *output_headers; /* address of the remote host and the port connection came from */ char *remote_host; ev_uint16_t remote_port; /* cache of the hostname for evhttp_request_get_host */ char *host_cache; enum evhttp_request_kind kind; enum evhttp_cmd_type type; size_t headers_size; size_t body_size; char *uri; /* uri after HTTP request was parsed */ struct evhttp_uri *uri_elems; /* uri elements */ char major; /* HTTP Major number */ char minor; /* HTTP Minor number */ int response_code; /* HTTP Response code */ char *response_code_line; /* Readable response */ struct evbuffer *input_buffer; /* read data */ ev_int64_t ntoread; unsigned chunked:1, /* a chunked request */ userdone:1; /* the user has sent all data */ struct evbuffer *output_buffer; /* outgoing post or data */ /* Callback */ void (*cb)(struct evhttp_request *, void *); void *cb_arg; /* * Chunked data callback - call for each completed chunk if * specified. If not specified, all the data is delivered via * the regular callback. */ void (*chunk_cb)(struct evhttp_request *, void *); /* * Callback added for forked-daapd so they can collect ICY * (shoutcast) metadata from the http header. If return * int is negative the connection will be closed. */ int (*header_cb)(struct evhttp_request *, void *); /* * Error callback - called when error is occured. * @see evhttp_request_error for error types. * * @see evhttp_request_set_error_cb() */ void (*error_cb)(enum evhttp_request_error, void *); /* * Send complete callback - called when the request is actually * sent and completed. */ void (*on_complete_cb)(struct evhttp_request *, void *); void *on_complete_cb_arg; }; #ifdef __cplusplus } #endif #endif /* EVENT2_HTTP_STRUCT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/rpc_struct.h0000644000076400001440000000701614111362573022377 0ustar00bernatusers00000000000000/* * Copyright (c) 2006-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_RPC_STRUCT_H_INCLUDED_ #define EVENT2_RPC_STRUCT_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif /** @file event2/rpc_struct.h Structures used by rpc.h. Using these structures directly may harm forward compatibility: be careful! */ /* Fix so that people don't have to run with */ #ifndef TAILQ_ENTRY #define EVENT_DEFINED_TQENTRY_ #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } #endif /* !TAILQ_ENTRY */ /** * provides information about the completed RPC request. */ struct evrpc_status { #define EVRPC_STATUS_ERR_NONE 0 #define EVRPC_STATUS_ERR_TIMEOUT 1 #define EVRPC_STATUS_ERR_BADPAYLOAD 2 #define EVRPC_STATUS_ERR_UNSTARTED 3 #define EVRPC_STATUS_ERR_HOOKABORTED 4 int error; /* for looking at headers or other information */ struct evhttp_request *http_req; }; /* the structure below needs to be synchronized with evrpc_req_generic */ /* Encapsulates a request */ struct evrpc { TAILQ_ENTRY(evrpc) next; /* the URI at which the request handler lives */ const char* uri; /* creates a new request structure */ void *(*request_new)(void *); void *request_new_arg; /* frees the request structure */ void (*request_free)(void *); /* unmarshals the buffer into the proper request structure */ int (*request_unmarshal)(void *, struct evbuffer *); /* creates a new reply structure */ void *(*reply_new)(void *); void *reply_new_arg; /* frees the reply structure */ void (*reply_free)(void *); /* verifies that the reply is valid */ int (*reply_complete)(void *); /* marshals the reply into a buffer */ void (*reply_marshal)(struct evbuffer*, void *); /* the callback invoked for each received rpc */ void (*cb)(struct evrpc_req_generic *, void *); void *cb_arg; /* reference for further configuration */ struct evrpc_base *base; }; #ifdef EVENT_DEFINED_TQENTRY_ #undef TAILQ_ENTRY #endif #ifdef __cplusplus } #endif #endif /* EVENT2_RPC_STRUCT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/dns.h0000644000076400001440000006656214111362573021006 0ustar00bernatusers00000000000000/* * Copyright (c) 2006-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The original DNS code is due to Adam Langley with heavy * modifications by Nick Mathewson. Adam put his DNS software in the * public domain. You can find his original copyright below. Please, * aware that the code as part of Libevent is governed by the 3-clause * BSD license above. * * This software is Public Domain. To view a copy of the public domain dedication, * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. * * I ask and expect, but do not require, that all derivative works contain an * attribution similar to: * Parts developed by Adam Langley * * You may wish to replace the word "Parts" with something else depending on * the amount of original code. * * (Derivative works does not include programs which link against, run or include * the source verbatim in their source distributions) */ /** @file event2/dns.h * * Welcome, gentle reader * * Async DNS lookups are really a whole lot harder than they should be, * mostly stemming from the fact that the libc resolver has never been * very good at them. Before you use this library you should see if libc * can do the job for you with the modern async call getaddrinfo_a * (see http://www.imperialviolet.org/page25.html#e498). Otherwise, * please continue. * * The library keeps track of the state of nameservers and will avoid * them when they go down. Otherwise it will round robin between them. * * Quick start guide: * #include "evdns.h" * void callback(int result, char type, int count, int ttl, * void *addresses, void *arg); * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); * evdns_resolve("www.hostname.com", 0, callback, NULL); * * When the lookup is complete the callback function is called. The * first argument will be one of the DNS_ERR_* defines in evdns.h. * Hopefully it will be DNS_ERR_NONE, in which case type will be * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time * which the data can be cached for (in seconds), addresses will point * to an array of uint32_t's and arg will be whatever you passed to * evdns_resolve. * * Searching: * * In order for this library to be a good replacement for glibc's resolver it * supports searching. This involves setting a list of default domains, in * which names will be queried for. The number of dots in the query name * determines the order in which this list is used. * * Searching appears to be a single lookup from the point of view of the API, * although many DNS queries may be generated from a single call to * evdns_resolve. Searching can also drastically slow down the resolution * of names. * * To disable searching: * 1. Never set it up. If you never call evdns_resolv_conf_parse or * evdns_search_add then no searching will occur. * * 2. If you do call evdns_resolv_conf_parse then don't pass * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). * * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. * * The order of searches depends on the number of dots in the name. If the * number is greater than the ndots setting then the names is first tried * globally. Otherwise each search domain is appended in turn. * * The ndots setting can either be set from a resolv.conf, or by calling * evdns_search_ndots_set. * * For example, with ndots set to 1 (the default) and a search domain list of * ["myhome.net"]: * Query: www * Order: www.myhome.net, www. * * Query: www.abc * Order: www.abc., www.abc.myhome.net * * Internals: * * Requests are kept in two queues. The first is the inflight queue. In * this queue requests have an allocated transaction id and nameserver. * They will soon be transmitted if they haven't already been. * * The second is the waiting queue. The size of the inflight ring is * limited and all other requests wait in waiting queue for space. This * bounds the number of concurrent requests so that we don't flood the * nameserver. Several algorithms require a full walk of the inflight * queue and so bounding its size keeps thing going nicely under huge * (many thousands of requests) loads. * * If a nameserver loses too many requests it is considered down and we * try not to use it. After a while we send a probe to that nameserver * (a lookup for google.com) and, if it replies, we consider it working * again. If the nameserver fails a probe we wait longer to try again * with the next probe. */ #ifndef EVENT2_DNS_H_INCLUDED_ #define EVENT2_DNS_H_INCLUDED_ #include #ifdef __cplusplus extern "C" { #endif /* For integer types. */ #include /** Error codes 0-5 are as described in RFC 1035. */ #define DNS_ERR_NONE 0 /** The name server was unable to interpret the query */ #define DNS_ERR_FORMAT 1 /** The name server was unable to process this query due to a problem with the * name server */ #define DNS_ERR_SERVERFAILED 2 /** The domain name does not exist */ #define DNS_ERR_NOTEXIST 3 /** The name server does not support the requested kind of query */ #define DNS_ERR_NOTIMPL 4 /** The name server refuses to reform the specified operation for policy * reasons */ #define DNS_ERR_REFUSED 5 /** The reply was truncated or ill-formatted */ #define DNS_ERR_TRUNCATED 65 /** An unknown error occurred */ #define DNS_ERR_UNKNOWN 66 /** Communication with the server timed out */ #define DNS_ERR_TIMEOUT 67 /** The request was canceled because the DNS subsystem was shut down. */ #define DNS_ERR_SHUTDOWN 68 /** The request was canceled via a call to evdns_cancel_request */ #define DNS_ERR_CANCEL 69 /** There were no answers and no error condition in the DNS packet. * This can happen when you ask for an address that exists, but a record * type that doesn't. */ #define DNS_ERR_NODATA 70 #define DNS_IPv4_A 1 #define DNS_PTR 2 #define DNS_IPv6_AAAA 3 #define DNS_QUERY_NO_SEARCH 1 /* Allow searching */ #define DNS_OPTION_SEARCH 1 /* Parse "nameserver" and add default if no such section */ #define DNS_OPTION_NAMESERVERS 2 /* Parse additional options like: * - timeout: * - getaddrinfo-allow-skew: * - max-timeouts: * - max-inflight: * - attempts: * - randomize-case: * - initial-probe-timeout: */ #define DNS_OPTION_MISC 4 /* Load hosts file (i.e. "/etc/hosts") */ #define DNS_OPTION_HOSTSFILE 8 /** * All above: * - DNS_OPTION_SEARCH * - DNS_OPTION_NAMESERVERS * - DNS_OPTION_MISC * - DNS_OPTION_HOSTSFILE */ #define DNS_OPTIONS_ALL ( \ DNS_OPTION_SEARCH | \ DNS_OPTION_NAMESERVERS | \ DNS_OPTION_MISC | \ DNS_OPTION_HOSTSFILE | \ 0 \ ) /* Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers * in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) */ #define DNS_OPTION_NAMESERVERS_NO_DEFAULT 16 /* Obsolete name for DNS_QUERY_NO_SEARCH */ #define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH /** * The callback that contains the results from a lookup. * - result is one of the DNS_ERR_* values (DNS_ERR_NONE for success) * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA * - count contains the number of addresses of form type * - ttl is the number of seconds the resolution may be cached for. * - addresses needs to be cast according to type. It will be an array of * 4-byte sequences for ipv4, or an array of 16-byte sequences for ipv6, * or a nul-terminated string for PTR. */ typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); struct evdns_base; struct event_base; /** Flag for evdns_base_new: process resolv.conf. */ #define EVDNS_BASE_INITIALIZE_NAMESERVERS 1 /** Flag for evdns_base_new: Do not prevent the libevent event loop from * exiting when we have no active dns requests. */ #define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000 /** Flag for evdns_base_new: If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not * add default nameserver if there are no nameservers in resolv.conf * @see DNS_OPTION_NAMESERVERS_NO_DEFAULT */ #define EVDNS_BASE_NAMESERVERS_NO_DEFAULT 0x10000 /** Initialize the asynchronous DNS library. This function initializes support for non-blocking name resolution by calling evdns_resolv_conf_parse() on UNIX and evdns_config_windows_nameservers() on Windows. @param event_base the event base to associate the dns client with @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS| EVDNS_BASE_DISABLE_WHEN_INACTIVE|EVDNS_BASE_NAMESERVERS_NO_DEFAULT @return evdns_base object if successful, or NULL if an error occurred. @see evdns_base_free() */ EVENT2_EXPORT_SYMBOL struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers); /** Shut down the asynchronous DNS resolver and terminate all active requests. If the 'fail_requests' option is enabled, all active requests will return an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, the requests will be silently discarded. @param evdns_base the evdns base to free @param fail_requests if zero, active requests will be aborted; if non-zero, active requests will return DNS_ERR_SHUTDOWN. @see evdns_base_new() */ EVENT2_EXPORT_SYMBOL void evdns_base_free(struct evdns_base *base, int fail_requests); /** Remove all hosts entries that have been loaded into the event_base via evdns_base_load_hosts or via event_base_resolv_conf_parse. @param evdns_base the evdns base to remove outdated host addresses from */ EVENT2_EXPORT_SYMBOL void evdns_base_clear_host_addresses(struct evdns_base *base); /** Convert a DNS error code to a string. @param err the DNS error code @return a string containing an explanation of the error code */ EVENT2_EXPORT_SYMBOL const char *evdns_err_to_string(int err); /** Add a nameserver. The address should be an IPv4 address in network byte order. The type of address is chosen so that it matches in_addr.s_addr. @param base the evdns_base to which to add the name server @param address an IP address in network byte order @return 0 if successful, or -1 if an error occurred @see evdns_base_nameserver_ip_add() */ EVENT2_EXPORT_SYMBOL int evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address); /** Get the number of configured nameservers. This returns the number of configured nameservers (not necessarily the number of running nameservers). This is useful for double-checking whether our calls to the various nameserver configuration functions have been successful. @param base the evdns_base to which to apply this operation @return the number of configured nameservers @see evdns_base_nameserver_add() */ EVENT2_EXPORT_SYMBOL int evdns_base_count_nameservers(struct evdns_base *base); /** Remove all configured nameservers, and suspend all pending resolves. Resolves will not necessarily be re-attempted until evdns_base_resume() is called. @param base the evdns_base to which to apply this operation @return 0 if successful, or -1 if an error occurred @see evdns_base_resume() */ EVENT2_EXPORT_SYMBOL int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base); /** Resume normal operation and continue any suspended resolve requests. Re-attempt resolves left in limbo after an earlier call to evdns_base_clear_nameservers_and_suspend(). @param base the evdns_base to which to apply this operation @return 0 if successful, or -1 if an error occurred @see evdns_base_clear_nameservers_and_suspend() */ EVENT2_EXPORT_SYMBOL int evdns_base_resume(struct evdns_base *base); /** Add a nameserver by string address. This function parses a n IPv4 or IPv6 address from a string and adds it as a nameserver. It supports the following formats: - [IPv6Address]:port - [IPv6Address] - IPv6Address - IPv4Address:port - IPv4Address If no port is specified, it defaults to 53. @param base the evdns_base to which to apply this operation @return 0 if successful, or -1 if an error occurred @see evdns_base_nameserver_add() */ EVENT2_EXPORT_SYMBOL int evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string); /** Add a nameserver by sockaddr. **/ EVENT2_EXPORT_SYMBOL int evdns_base_nameserver_sockaddr_add(struct evdns_base *base, const struct sockaddr *sa, ev_socklen_t len, unsigned flags); struct evdns_request; /** Lookup an A record for a given name. @param base the evdns_base to which to apply this operation @param name a DNS hostname @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return an evdns_request object if successful, or NULL if an error occurred. @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() */ EVENT2_EXPORT_SYMBOL struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); /** Lookup an AAAA record for a given name. @param base the evdns_base to which to apply this operation @param name a DNS hostname @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return an evdns_request object if successful, or NULL if an error occurred. @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() */ EVENT2_EXPORT_SYMBOL struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); struct in_addr; struct in6_addr; /** Lookup a PTR record for a given IP address. @param base the evdns_base to which to apply this operation @param in an IPv4 address @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return an evdns_request object if successful, or NULL if an error occurred. @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() */ EVENT2_EXPORT_SYMBOL struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); /** Lookup a PTR record for a given IPv6 address. @param base the evdns_base to which to apply this operation @param in an IPv6 address @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return an evdns_request object if successful, or NULL if an error occurred. @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() */ EVENT2_EXPORT_SYMBOL struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); /** Cancels a pending DNS resolution request. @param base the evdns_base that was used to make the request @param req the evdns_request that was returned by calling a resolve function @see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse */ EVENT2_EXPORT_SYMBOL void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req); /** Set the value of a configuration option. The currently available configuration options are: ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case, bind-to, initial-probe-timeout, getaddrinfo-allow-skew, so-rcvbuf, so-sndbuf. In versions before Libevent 2.0.3-alpha, the option name needed to end with a colon. @param base the evdns_base to which to apply this operation @param option the name of the configuration option to be modified @param val the value to be set @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val); /** Parse a resolv.conf file. The 'flags' parameter determines what information is parsed from the resolv.conf file. See the man page for resolv.conf for the format of this file. The following directives are not parsed from the file: sortlist, rotate, no-check-names, inet6, debug. If this function encounters an error, the possible return values are: 1 = failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of memory, 5 = short read from file, 6 = no nameservers listed in the file @param base the evdns_base to which to apply this operation @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT @param filename the path to the resolv.conf file @return 0 if successful, or various positive error codes if an error occurred (see above) @see resolv.conf(3), evdns_config_windows_nameservers() */ EVENT2_EXPORT_SYMBOL int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename); /** Load an /etc/hosts-style file from 'hosts_fname' into 'base'. If hosts_fname is NULL, add minimal entries for localhost, and nothing else. Note that only evdns_getaddrinfo uses the /etc/hosts entries. This function does not replace previously loaded hosts entries; to do that, call evdns_base_clear_host_addresses first. Return 0 on success, negative on failure. */ EVENT2_EXPORT_SYMBOL int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname); #if defined(EVENT_IN_DOXYGEN_) || defined(_WIN32) /** Obtain nameserver information using the Windows API. Attempt to configure a set of nameservers based on platform settings on a win32 host. Preferentially tries to use GetNetworkParams; if that fails, looks in the registry. @return 0 if successful, or -1 if an error occurred @see evdns_resolv_conf_parse() */ EVENT2_EXPORT_SYMBOL int evdns_base_config_windows_nameservers(struct evdns_base *); #define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED #endif /** Clear the list of search domains. */ EVENT2_EXPORT_SYMBOL void evdns_base_search_clear(struct evdns_base *base); /** Add a domain to the list of search domains @param domain the domain to be added to the search list */ EVENT2_EXPORT_SYMBOL void evdns_base_search_add(struct evdns_base *base, const char *domain); /** Set the 'ndots' parameter for searches. Sets the number of dots which, when found in a name, causes the first query to be without any search domain. @param ndots the new ndots parameter */ EVENT2_EXPORT_SYMBOL void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots); /** A callback that is invoked when a log message is generated @param is_warning indicates if the log message is a 'warning' @param msg the content of the log message */ typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); /** Set the callback function to handle DNS log messages. If this callback is not set, evdns log messages are handled with the regular Libevent logging system. @param fn the callback to be invoked when a log message is generated */ EVENT2_EXPORT_SYMBOL void evdns_set_log_fn(evdns_debug_log_fn_type fn); /** Set a callback that will be invoked to generate transaction IDs. By default, we pick transaction IDs based on the current clock time, which is bad for security. @param fn the new callback, or NULL to use the default. NOTE: This function has no effect in Libevent 2.0.4-alpha and later, since Libevent now provides its own secure RNG. */ EVENT2_EXPORT_SYMBOL void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)); /** Set a callback used to generate random bytes. By default, we use the same function as passed to evdns_set_transaction_id_fn to generate bytes two at a time. If a function is provided here, it's also used to generate transaction IDs. NOTE: This function has no effect in Libevent 2.0.4-alpha and later, since Libevent now provides its own secure RNG. */ EVENT2_EXPORT_SYMBOL void evdns_set_random_bytes_fn(void (*fn)(char *, size_t)); /* * Functions used to implement a DNS server. */ struct evdns_server_request; struct evdns_server_question; /** A callback to implement a DNS server. The callback function receives a DNS request. It should then optionally add a number of answers to the reply using the evdns_server_request_add_*_reply functions, before calling either evdns_server_request_respond to send the reply back, or evdns_server_request_drop to decline to answer the request. @param req A newly received request @param user_data A pointer that was passed to evdns_add_server_port_with_base(). */ typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); #define EVDNS_ANSWER_SECTION 0 #define EVDNS_AUTHORITY_SECTION 1 #define EVDNS_ADDITIONAL_SECTION 2 #define EVDNS_TYPE_A 1 #define EVDNS_TYPE_NS 2 #define EVDNS_TYPE_CNAME 5 #define EVDNS_TYPE_SOA 6 #define EVDNS_TYPE_PTR 12 #define EVDNS_TYPE_MX 15 #define EVDNS_TYPE_TXT 16 #define EVDNS_TYPE_AAAA 28 #define EVDNS_QTYPE_AXFR 252 #define EVDNS_QTYPE_ALL 255 #define EVDNS_CLASS_INET 1 /* flags that can be set in answers; as part of the err parameter */ #define EVDNS_FLAGS_AA 0x400 #define EVDNS_FLAGS_RD 0x080 /** Create a new DNS server port. @param base The event base to handle events for the server port. @param socket A UDP socket to accept DNS requests. @param flags Always 0 for now. @param callback A function to invoke whenever we get a DNS request on the socket. @param user_data Data to pass to the callback. @return an evdns_server_port structure for this server port or NULL if an error occurred. */ EVENT2_EXPORT_SYMBOL struct evdns_server_port *evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data); /** Close down a DNS server port, and free associated structures. */ EVENT2_EXPORT_SYMBOL void evdns_close_server_port(struct evdns_server_port *port); /** Sets some flags in a reply we're building. Allows setting of the AA or RD flags */ EVENT2_EXPORT_SYMBOL void evdns_server_request_set_flags(struct evdns_server_request *req, int flags); /* Functions to add an answer to an in-progress DNS reply. */ EVENT2_EXPORT_SYMBOL int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); EVENT2_EXPORT_SYMBOL int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); EVENT2_EXPORT_SYMBOL int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); EVENT2_EXPORT_SYMBOL int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); EVENT2_EXPORT_SYMBOL int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); /** Send back a response to a DNS request, and free the request structure. */ EVENT2_EXPORT_SYMBOL int evdns_server_request_respond(struct evdns_server_request *req, int err); /** Free a DNS request without sending back a reply. */ EVENT2_EXPORT_SYMBOL int evdns_server_request_drop(struct evdns_server_request *req); struct sockaddr; /** Get the address that made a DNS request. */ EVENT2_EXPORT_SYMBOL int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len); /** Callback for evdns_getaddrinfo. */ typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg); struct evdns_base; struct evdns_getaddrinfo_request; /** Make a non-blocking getaddrinfo request using the dns_base in 'dns_base'. * * If we can answer the request immediately (with an error or not!), then we * invoke cb immediately and return NULL. Otherwise we return * an evdns_getaddrinfo_request and invoke cb later. * * When the callback is invoked, we pass as its first argument the error code * that getaddrinfo would return (or 0 for no error). As its second argument, * we pass the evutil_addrinfo structures we found (or NULL on error). We * pass 'arg' as the third argument. * * Limitations: * * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. * - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0. * - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0. */ EVENT2_EXPORT_SYMBOL struct evdns_getaddrinfo_request *evdns_getaddrinfo( struct evdns_base *dns_base, const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, evdns_getaddrinfo_cb cb, void *arg); /* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the * getaddrinfo's callback has been invoked. The resolves will be canceled, * and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */ EVENT2_EXPORT_SYMBOL void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req); /** Retrieve the address of the 'idx'th configured nameserver. @param base The evdns_base to examine. @param idx The index of the nameserver to get the address of. @param sa A location to receive the server's address. @param len The number of bytes available at sa. @return the number of bytes written into sa on success. On failure, returns -1 if idx is greater than the number of configured nameservers, or a value greater than 'len' if len was not high enough. */ EVENT2_EXPORT_SYMBOL int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx, struct sockaddr *sa, ev_socklen_t len); #ifdef __cplusplus } #endif #endif /* !EVENT2_DNS_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/event_struct.h0000644000076400001440000001164014111362573022732 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_EVENT_STRUCT_H_INCLUDED_ #define EVENT2_EVENT_STRUCT_H_INCLUDED_ /** @file event2/event_struct.h Structures used by event.h. Using these structures directly WILL harm forward compatibility: be careful. No field declared in this file should be used directly in user code. Except for historical reasons, these fields would not be exposed at all. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /* For evkeyvalq */ #include #define EVLIST_TIMEOUT 0x01 #define EVLIST_INSERTED 0x02 #define EVLIST_SIGNAL 0x04 #define EVLIST_ACTIVE 0x08 #define EVLIST_INTERNAL 0x10 #define EVLIST_ACTIVE_LATER 0x20 #define EVLIST_FINALIZING 0x40 #define EVLIST_INIT 0x80 #define EVLIST_ALL 0xff /* Fix so that people don't have to run with */ #ifndef TAILQ_ENTRY #define EVENT_DEFINED_TQENTRY_ #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } #endif /* !TAILQ_ENTRY */ #ifndef TAILQ_HEAD #define EVENT_DEFINED_TQHEAD_ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; \ struct type **tqh_last; \ } #endif /* Fix so that people don't have to run with */ #ifndef LIST_ENTRY #define EVENT_DEFINED_LISTENTRY_ #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } #endif /* !LIST_ENTRY */ #ifndef LIST_HEAD #define EVENT_DEFINED_LISTHEAD_ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #endif /* !LIST_HEAD */ struct event; struct event_callback { TAILQ_ENTRY(event_callback) evcb_active_next; short evcb_flags; ev_uint8_t evcb_pri; /* smaller numbers are higher priority */ ev_uint8_t evcb_closure; /* allows us to adopt for different types of events */ union { void (*evcb_callback)(evutil_socket_t, short, void *); void (*evcb_selfcb)(struct event_callback *, void *); void (*evcb_evfinalize)(struct event *, void *); void (*evcb_cbfinalize)(struct event_callback *, void *); } evcb_cb_union; void *evcb_arg; }; struct event_base; struct event { struct event_callback ev_evcallback; /* for managing timeouts */ union { TAILQ_ENTRY(event) ev_next_with_common_timeout; int min_heap_idx; } ev_timeout_pos; evutil_socket_t ev_fd; struct event_base *ev_base; union { /* used for io events */ struct { LIST_ENTRY (event) ev_io_next; struct timeval ev_timeout; } ev_io; /* used by signal events */ struct { LIST_ENTRY (event) ev_signal_next; short ev_ncalls; /* Allows deletes in callback */ short *ev_pncalls; } ev_signal; } ev_; short ev_events; short ev_res; /* result passed to event callback */ struct timeval ev_timeout; }; TAILQ_HEAD (event_list, event); #ifdef EVENT_DEFINED_TQENTRY_ #undef TAILQ_ENTRY #endif #ifdef EVENT_DEFINED_TQHEAD_ #undef TAILQ_HEAD #endif LIST_HEAD (event_dlist, event); #ifdef EVENT_DEFINED_LISTENTRY_ #undef LIST_ENTRY #endif #ifdef EVENT_DEFINED_LISTHEAD_ #undef LIST_HEAD #endif #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_STRUCT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/bufferevent.h0000644000076400001440000010357314111362573022527 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_BUFFEREVENT_H_INCLUDED_ #define EVENT2_BUFFEREVENT_H_INCLUDED_ /** @file event2/bufferevent.h Functions for buffering data for network sending or receiving. Bufferevents are higher level than evbuffers: each has an underlying evbuffer for reading and one for writing, and callbacks that are invoked under certain circumstances. A bufferevent provides input and output buffers that get filled and drained automatically. The user of a bufferevent no longer deals directly with the I/O, but instead is reading from input and writing to output buffers. Once initialized, the bufferevent structure can be used repeatedly with bufferevent_enable() and bufferevent_disable(). When reading is enabled, the bufferevent will try to read from the file descriptor onto its input buffer, and call the read callback. When writing is enabled, the bufferevent will try to write data onto its file descriptor when the output buffer has enough data, and call the write callback when the output buffer is sufficiently drained. Bufferevents come in several flavors, including:
Socket-based bufferevents
A bufferevent that reads and writes data onto a network socket. Created with bufferevent_socket_new().
Paired bufferevents
A pair of bufferevents that send and receive data to one another without touching the network. Created with bufferevent_pair_new().
Filtering bufferevents
A bufferevent that transforms data, and sends or receives it over another underlying bufferevent. Created with bufferevent_filter_new().
SSL-backed bufferevents
A bufferevent that uses the openssl library to send and receive data over an encrypted connection. Created with bufferevent_openssl_socket_new() or bufferevent_openssl_filter_new().
*/ #include #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /** @name Bufferevent event codes These flags are passed as arguments to a bufferevent's event callback. @{ */ #define BEV_EVENT_READING 0x01 /**< error encountered while reading */ #define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */ #define BEV_EVENT_EOF 0x10 /**< eof file reached */ #define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */ #define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */ #define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */ /**@}*/ /** An opaque type for handling buffered IO @see event2/bufferevent.h */ struct bufferevent #ifdef EVENT_IN_DOXYGEN_ {} #endif ; struct event_base; struct evbuffer; struct sockaddr; /** A read or write callback for a bufferevent. The read callback is triggered when new data arrives in the input buffer and the amount of readable data exceed the low watermark which is 0 by default. The write callback is triggered if the write buffer has been exhausted or fell below its low watermark. @param bev the bufferevent that triggered the callback @param ctx the user-specified context for this bufferevent */ typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx); /** An event/error callback for a bufferevent. The event callback is triggered if either an EOF condition or another unrecoverable error was encountered. For bufferevents with deferred callbacks, this is a bitwise OR of all errors that have happened on the bufferevent since the last callback invocation. @param bev the bufferevent for which the error condition was reached @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING to indicate if the error was encountered on the read or write path, and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR, BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED. @param ctx the user-specified context for this bufferevent */ typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx); /** Options that can be specified when creating a bufferevent */ enum bufferevent_options { /** If set, we close the underlying file * descriptor/bufferevent/whatever when this bufferevent is freed. */ BEV_OPT_CLOSE_ON_FREE = (1<<0), /** If set, and threading is enabled, operations on this bufferevent * are protected by a lock */ BEV_OPT_THREADSAFE = (1<<1), /** If set, callbacks are run deferred in the event loop. */ BEV_OPT_DEFER_CALLBACKS = (1<<2), /** If set, callbacks are executed without locks being held on the * bufferevent. This option currently requires that * BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent * might remove the requirement.*/ BEV_OPT_UNLOCK_CALLBACKS = (1<<3) }; /** Create a new socket bufferevent over an existing socket. @param base the event base to associate with the new bufferevent. @param fd the file descriptor from which data is read and written to. This file descriptor is not allowed to be a pipe(2). It is safe to set the fd to -1, so long as you later set it with bufferevent_setfd or bufferevent_socket_connect(). @param options Zero or more BEV_OPT_* flags @return a pointer to a newly allocated bufferevent struct, or NULL if an error occurred @see bufferevent_free() */ EVENT2_EXPORT_SYMBOL struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options); /** Launch a connect() attempt with a socket-based bufferevent. When the connect succeeds, the eventcb will be invoked with BEV_EVENT_CONNECTED set. If the bufferevent does not already have a socket set, we allocate a new socket here and make it nonblocking before we begin. If no address is provided, we assume that the socket is already connecting, and configure the bufferevent so that a BEV_EVENT_CONNECTED event will be yielded when it is done connecting. @param bufev an existing bufferevent allocated with bufferevent_socket_new(). @param addr the address we should connect to @param socklen The length of the address @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_socket_connect(struct bufferevent *, const struct sockaddr *, int); struct evdns_base; /** Resolve the hostname 'hostname' and connect to it as with bufferevent_socket_connect(). @param bufev An existing bufferevent allocated with bufferevent_socket_new() @param evdns_base Optionally, an evdns_base to use for resolving hostnames asynchronously. May be set to NULL for a blocking resolve. @param family A preferred address family to resolve addresses to, or AF_UNSPEC for no preference. Only AF_INET, AF_INET6, and AF_UNSPEC are supported. @param hostname The hostname to resolve; see below for notes on recognized formats @param port The port to connect to on the resolved address. @return 0 if successful, -1 on failure. Recognized hostname formats are: www.example.com (hostname) 1.2.3.4 (ipv4address) ::1 (ipv6address) [::1] ([ipv6address]) Performance note: If you do not provide an evdns_base, this function may block while it waits for a DNS response. This is probably not what you want. */ EVENT2_EXPORT_SYMBOL int bufferevent_socket_connect_hostname(struct bufferevent *, struct evdns_base *, int, const char *, int); /** Return the error code for the last failed DNS lookup attempt made by bufferevent_socket_connect_hostname(). @param bev The bufferevent object. @return DNS error code. @see evutil_gai_strerror() */ EVENT2_EXPORT_SYMBOL int bufferevent_socket_get_dns_error(struct bufferevent *bev); /** Assign a bufferevent to a specific event_base. NOTE that only socket bufferevents support this function. @param base an event_base returned by event_init() @param bufev a bufferevent struct returned by bufferevent_new() or bufferevent_socket_new() @return 0 if successful, or -1 if an error occurred @see bufferevent_new() */ EVENT2_EXPORT_SYMBOL int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); /** Return the event_base used by a bufferevent */ EVENT2_EXPORT_SYMBOL struct event_base *bufferevent_get_base(struct bufferevent *bev); /** Assign a priority to a bufferevent. Only supported for socket bufferevents. @param bufev a bufferevent struct @param pri the priority to be assigned @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int bufferevent_priority_set(struct bufferevent *bufev, int pri); /** Return the priority of a bufferevent. Only supported for socket bufferevents */ EVENT2_EXPORT_SYMBOL int bufferevent_get_priority(const struct bufferevent *bufev); /** Deallocate the storage associated with a bufferevent structure. If there is pending data to write on the bufferevent, it probably won't be flushed before the bufferevent is freed. @param bufev the bufferevent structure to be freed. */ EVENT2_EXPORT_SYMBOL void bufferevent_free(struct bufferevent *bufev); /** Changes the callbacks for a bufferevent. @param bufev the bufferevent object for which to change callbacks @param readcb callback to invoke when there is data to be read, or NULL if no callback is desired @param writecb callback to invoke when the file descriptor is ready for writing, or NULL if no callback is desired @param eventcb callback to invoke when there is an event on the file descriptor @param cbarg an argument that will be supplied to each of the callbacks (readcb, writecb, and errorcb) @see bufferevent_new() */ EVENT2_EXPORT_SYMBOL void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg); /** Retrieves the callbacks for a bufferevent. @param bufev the bufferevent to examine. @param readcb_ptr if readcb_ptr is nonnull, *readcb_ptr is set to the current read callback for the bufferevent. @param writecb_ptr if writecb_ptr is nonnull, *writecb_ptr is set to the current write callback for the bufferevent. @param eventcb_ptr if eventcb_ptr is nonnull, *eventcb_ptr is set to the current event callback for the bufferevent. @param cbarg_ptr if cbarg_ptr is nonnull, *cbarg_ptr is set to the current callback argument for the bufferevent. @see buffervent_setcb() */ EVENT2_EXPORT_SYMBOL void bufferevent_getcb(struct bufferevent *bufev, bufferevent_data_cb *readcb_ptr, bufferevent_data_cb *writecb_ptr, bufferevent_event_cb *eventcb_ptr, void **cbarg_ptr); /** Changes the file descriptor on which the bufferevent operates. Not supported for all bufferevent types. @param bufev the bufferevent object for which to change the file descriptor @param fd the file descriptor to operate on */ EVENT2_EXPORT_SYMBOL int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd); /** Returns the file descriptor associated with a bufferevent, or -1 if no file descriptor is associated with the bufferevent. */ EVENT2_EXPORT_SYMBOL evutil_socket_t bufferevent_getfd(struct bufferevent *bufev); /** Returns the underlying bufferevent associated with a bufferevent (if the bufferevent is a wrapper), or NULL if there is no underlying bufferevent. */ EVENT2_EXPORT_SYMBOL struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev); /** Write data to a bufferevent buffer. The bufferevent_write() function can be used to write data to the file descriptor. The data is appended to the output buffer and written to the descriptor automatically as it becomes available for writing. @param bufev the bufferevent to be written to @param data a pointer to the data to be written @param size the length of the data, in bytes @return 0 if successful, or -1 if an error occurred @see bufferevent_write_buffer() */ EVENT2_EXPORT_SYMBOL int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size); /** Write data from an evbuffer to a bufferevent buffer. The evbuffer is being drained as a result. @param bufev the bufferevent to be written to @param buf the evbuffer to be written @return 0 if successful, or -1 if an error occurred @see bufferevent_write() */ EVENT2_EXPORT_SYMBOL int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); /** Read data from a bufferevent buffer. The bufferevent_read() function is used to read data from the input buffer. @param bufev the bufferevent to be read from @param data pointer to a buffer that will store the data @param size the size of the data buffer, in bytes @return the amount of data read, in bytes. */ EVENT2_EXPORT_SYMBOL size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); /** Read data from a bufferevent buffer into an evbuffer. This avoids memory copies. @param bufev the bufferevent to be read from @param buf the evbuffer to which to add data @return 0 if successful, or -1 if an error occurred. */ EVENT2_EXPORT_SYMBOL int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf); /** Returns the input buffer. The user MUST NOT set the callback on this buffer. @param bufev the bufferevent from which to get the evbuffer @return the evbuffer object for the input buffer */ EVENT2_EXPORT_SYMBOL struct evbuffer *bufferevent_get_input(struct bufferevent *bufev); /** Returns the output buffer. The user MUST NOT set the callback on this buffer. When filters are being used, the filters need to be manually triggered if the output buffer was manipulated. @param bufev the bufferevent from which to get the evbuffer @return the evbuffer object for the output buffer */ EVENT2_EXPORT_SYMBOL struct evbuffer *bufferevent_get_output(struct bufferevent *bufev); /** Enable a bufferevent. @param bufev the bufferevent to be enabled @param event any combination of EV_READ | EV_WRITE. @return 0 if successful, or -1 if an error occurred @see bufferevent_disable() */ EVENT2_EXPORT_SYMBOL int bufferevent_enable(struct bufferevent *bufev, short event); /** Disable a bufferevent. @param bufev the bufferevent to be disabled @param event any combination of EV_READ | EV_WRITE. @return 0 if successful, or -1 if an error occurred @see bufferevent_enable() */ EVENT2_EXPORT_SYMBOL int bufferevent_disable(struct bufferevent *bufev, short event); /** Return the events that are enabled on a given bufferevent. @param bufev the bufferevent to inspect @return A combination of EV_READ | EV_WRITE */ EVENT2_EXPORT_SYMBOL short bufferevent_get_enabled(struct bufferevent *bufev); /** Set the read and write timeout for a bufferevent. A bufferevent's timeout will fire the first time that the indicated amount of time has elapsed since a successful read or write operation, during which the bufferevent was trying to read or write. (In other words, if reading or writing is disabled, or if the bufferevent's read or write operation has been suspended because there's no data to write, or not enough bandwidth, or so on, the timeout isn't active. The timeout only becomes active when we we're willing to actually read or write.) Calling bufferevent_enable or setting a timeout for a bufferevent whose timeout is already pending resets its timeout. If the timeout elapses, the corresponding operation (EV_READ or EV_WRITE) becomes disabled until you re-enable it again. The bufferevent's event callback is called with the BEV_EVENT_TIMEOUT|BEV_EVENT_READING or BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING. @param bufev the bufferevent to be modified @param timeout_read the read timeout, or NULL @param timeout_write the write timeout, or NULL */ EVENT2_EXPORT_SYMBOL int bufferevent_set_timeouts(struct bufferevent *bufev, const struct timeval *timeout_read, const struct timeval *timeout_write); /** Sets the watermarks for read and write events. On input, a bufferevent does not invoke the user read callback unless there is at least low watermark data in the buffer. If the read buffer is beyond the high watermark, the bufferevent stops reading from the network. But be aware that bufferevent input/read buffer can overrun high watermark limit (typical example is openssl bufferevent), so you should not relay in this. On output, the user write callback is invoked whenever the buffered data falls below the low watermark. Filters that write to this bufev will try not to write more bytes to this buffer than the high watermark would allow, except when flushing. @param bufev the bufferevent to be modified @param events EV_READ, EV_WRITE or both @param lowmark the lower watermark to set @param highmark the high watermark to set */ EVENT2_EXPORT_SYMBOL void bufferevent_setwatermark(struct bufferevent *bufev, short events, size_t lowmark, size_t highmark); /** Retrieves the watermarks for read or write events. Returns non-zero if events contains not only EV_READ or EV_WRITE. Returns zero if events equal EV_READ or EV_WRITE @param bufev the bufferevent to be examined @param events EV_READ or EV_WRITE @param lowmark receives the lower watermark if not NULL @param highmark receives the high watermark if not NULL */ EVENT2_EXPORT_SYMBOL int bufferevent_getwatermark(struct bufferevent *bufev, short events, size_t *lowmark, size_t *highmark); /** Acquire the lock on a bufferevent. Has no effect if locking was not enabled with BEV_OPT_THREADSAFE. */ EVENT2_EXPORT_SYMBOL void bufferevent_lock(struct bufferevent *bufev); /** Release the lock on a bufferevent. Has no effect if locking was not enabled with BEV_OPT_THREADSAFE. */ EVENT2_EXPORT_SYMBOL void bufferevent_unlock(struct bufferevent *bufev); /** * Public interface to manually increase the reference count of a bufferevent * this is useful in situations where a user may reference the bufferevent * somewhere else (unknown to libevent) * * @param bufev the bufferevent to increase the refcount on * */ EVENT2_EXPORT_SYMBOL void bufferevent_incref(struct bufferevent *bufev); /** * Public interface to manually decrement the reference count of a bufferevent * * Warning: make sure you know what you're doing. This is mainly used in * conjunction with bufferevent_incref(). This will free up all data associated * with a bufferevent if the reference count hits 0. * * @param bufev the bufferevent to decrement the refcount on * * @return 1 if the bufferevent was freed, otherwise 0 (still referenced) */ EVENT2_EXPORT_SYMBOL int bufferevent_decref(struct bufferevent *bufev); /** Flags that can be passed into filters to let them know how to deal with the incoming data. */ enum bufferevent_flush_mode { /** usually set when processing data */ BEV_NORMAL = 0, /** want to checkpoint all data sent. */ BEV_FLUSH = 1, /** encountered EOF on read or done sending data */ BEV_FINISHED = 2 }; /** Triggers the bufferevent to produce more data if possible. @param bufev the bufferevent object @param iotype either EV_READ or EV_WRITE or both. @param mode either BEV_NORMAL or BEV_FLUSH or BEV_FINISHED @return -1 on failure, 0 if no data was produces, 1 if data was produced */ EVENT2_EXPORT_SYMBOL int bufferevent_flush(struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode mode); /** Flags for bufferevent_trigger(_event) that modify when and how to trigger the callback. */ enum bufferevent_trigger_options { /** trigger the callback regardless of the watermarks */ BEV_TRIG_IGNORE_WATERMARKS = (1<<16), /** defer even if the callbacks are not */ BEV_TRIG_DEFER_CALLBACKS = BEV_OPT_DEFER_CALLBACKS /* (Note: for internal reasons, these need to be disjoint from * bufferevent_options, except when they mean the same thing. */ }; /** Triggers bufferevent data callbacks. The function will honor watermarks unless options contain BEV_TRIG_IGNORE_WATERMARKS. If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred. @param bufev the bufferevent object @param iotype either EV_READ or EV_WRITE or both. @param options */ EVENT2_EXPORT_SYMBOL void bufferevent_trigger(struct bufferevent *bufev, short iotype, int options); /** Triggers the bufferevent event callback. If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred. @param bufev the bufferevent object @param what the flags to pass onto the event callback @param options */ EVENT2_EXPORT_SYMBOL void bufferevent_trigger_event(struct bufferevent *bufev, short what, int options); /** @name Filtering support @{ */ /** Values that filters can return. */ enum bufferevent_filter_result { /** everything is okay */ BEV_OK = 0, /** the filter needs to read more data before output */ BEV_NEED_MORE = 1, /** the filter encountered a critical error, no further data can be processed. */ BEV_ERROR = 2 }; /** A callback function to implement a filter for a bufferevent. @param src An evbuffer to drain data from. @param dst An evbuffer to add data to. @param limit A suggested upper bound of bytes to write to dst. The filter may ignore this value, but doing so means that it will overflow the high-water mark associated with dst. -1 means "no limit". @param mode Whether we should write data as may be convenient (BEV_NORMAL), or flush as much data as we can (BEV_FLUSH), or flush as much as we can, possibly including an end-of-stream marker (BEV_FINISH). @param ctx A user-supplied pointer. @return BEV_OK if we wrote some data; BEV_NEED_MORE if we can't produce any more output until we get some input; and BEV_ERROR on an error. */ typedef enum bufferevent_filter_result (*bufferevent_filter_cb)( struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx); /** Allocate a new filtering bufferevent on top of an existing bufferevent. @param underlying the underlying bufferevent. @param input_filter The filter to apply to data we read from the underlying bufferevent @param output_filter The filer to apply to data we write to the underlying bufferevent @param options A bitfield of bufferevent options. @param free_context A function to use to free the filter context when this bufferevent is freed. @param ctx A context pointer to pass to the filter functions. */ EVENT2_EXPORT_SYMBOL struct bufferevent * bufferevent_filter_new(struct bufferevent *underlying, bufferevent_filter_cb input_filter, bufferevent_filter_cb output_filter, int options, void (*free_context)(void *), void *ctx); /**@}*/ /** Allocate a pair of linked bufferevents. The bufferevents behave as would two bufferevent_sock instances connected to opposite ends of a socketpair(), except that no internal socketpair is allocated. @param base The event base to associate with the socketpair. @param options A set of options for this bufferevent @param pair A pointer to an array to hold the two new bufferevent objects. @return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_pair_new(struct event_base *base, int options, struct bufferevent *pair[2]); /** Given one bufferevent returned by bufferevent_pair_new(), returns the other one if it still exists. Otherwise returns NULL. */ EVENT2_EXPORT_SYMBOL struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev); /** Abstract type used to configure rate-limiting on a bufferevent or a group of bufferevents. */ struct ev_token_bucket_cfg; /** A group of bufferevents which are configured to respect the same rate limit. */ struct bufferevent_rate_limit_group; /** Maximum configurable rate- or burst-limit. */ #define EV_RATE_LIMIT_MAX EV_SSIZE_MAX /** Initialize and return a new object to configure the rate-limiting behavior of bufferevents. @param read_rate The maximum number of bytes to read per tick on average. @param read_burst The maximum number of bytes to read in any single tick. @param write_rate The maximum number of bytes to write per tick on average. @param write_burst The maximum number of bytes to write in any single tick. @param tick_len The length of a single tick. Defaults to one second. Any fractions of a millisecond are ignored. Note that all rate-limits hare are currently best-effort: future versions of Libevent may implement them more tightly. */ EVENT2_EXPORT_SYMBOL struct ev_token_bucket_cfg *ev_token_bucket_cfg_new( size_t read_rate, size_t read_burst, size_t write_rate, size_t write_burst, const struct timeval *tick_len); /** Free all storage held in 'cfg'. Note: 'cfg' is not currently reference-counted; it is not safe to free it until no bufferevent is using it. */ EVENT2_EXPORT_SYMBOL void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg); /** Set the rate-limit of a the bufferevent 'bev' to the one specified in 'cfg'. If 'cfg' is NULL, disable any per-bufferevent rate-limiting on 'bev'. Note that only some bufferevent types currently respect rate-limiting. They are: socket-based bufferevents (normal and IOCP-based), and SSL-based bufferevents. Return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_set_rate_limit(struct bufferevent *bev, struct ev_token_bucket_cfg *cfg); /** Create a new rate-limit group for bufferevents. A rate-limit group constrains the maximum number of bytes sent and received, in toto, by all of its bufferevents. @param base An event_base to run any necessary timeouts for the group. Note that all bufferevents in the group do not necessarily need to share this event_base. @param cfg The rate-limit for this group. Note that all rate-limits hare are currently best-effort: future versions of Libevent may implement them more tightly. Note also that only some bufferevent types currently respect rate-limiting. They are: socket-based bufferevents (normal and IOCP-based), and SSL-based bufferevents. */ EVENT2_EXPORT_SYMBOL struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new( struct event_base *base, const struct ev_token_bucket_cfg *cfg); /** Change the rate-limiting settings for a given rate-limiting group. Return 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_rate_limit_group_set_cfg( struct bufferevent_rate_limit_group *, const struct ev_token_bucket_cfg *); /** Change the smallest quantum we're willing to allocate to any single bufferevent in a group for reading or writing at a time. The rationale is that, because of TCP/IP protocol overheads and kernel behavior, if a rate-limiting group is so tight on bandwidth that you're only willing to send 1 byte per tick per bufferevent, you might instead want to batch up the reads and writes so that you send N bytes per 1/N of the bufferevents (chosen at random) each tick, so you still wind up send 1 byte per tick per bufferevent on average, but you don't send so many tiny packets. The default min-share is currently 64 bytes. Returns 0 on success, -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_rate_limit_group_set_min_share( struct bufferevent_rate_limit_group *, size_t); /** Free a rate-limiting group. The group must have no members when this function is called. */ EVENT2_EXPORT_SYMBOL void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *); /** Add 'bev' to the list of bufferevents whose aggregate reading and writing is restricted by 'g'. If 'g' is NULL, remove 'bev' from its current group. A bufferevent may belong to no more than one rate-limit group at a time. If 'bev' is already a member of a group, it will be removed from its old group before being added to 'g'. Return 0 on success and -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_add_to_rate_limit_group(struct bufferevent *bev, struct bufferevent_rate_limit_group *g); /** Remove 'bev' from its current rate-limit group (if any). */ EVENT2_EXPORT_SYMBOL int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev); /** Set the size limit for single read operation. Set to 0 for a reasonable default. Return 0 on success and -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size); /** Set the size limit for single write operation. Set to 0 for a reasonable default. Return 0 on success and -1 on failure. */ EVENT2_EXPORT_SYMBOL int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size); /** Get the current size limit for single read operation. */ EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev); /** Get the current size limit for single write operation. */ EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev); /** @name Rate limit inspection Return the current read or write bucket size for a bufferevent. If it is not configured with a per-bufferevent ratelimit, return EV_SSIZE_MAX. This function does not inspect the group limit, if any. Note that it can return a negative value if the bufferevent has been made to read or write more than its limit. @{ */ EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev); EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev); /*@}*/ EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev); EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_get_max_to_write(struct bufferevent *bev); EVENT2_EXPORT_SYMBOL const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct bufferevent * bev); /** @name Group Rate limit inspection Return the read or write bucket size for a bufferevent rate limit group. Note that it can return a negative value if bufferevents in the group have been made to read or write more than their limits. @{ */ EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_rate_limit_group_get_read_limit( struct bufferevent_rate_limit_group *); EVENT2_EXPORT_SYMBOL ev_ssize_t bufferevent_rate_limit_group_get_write_limit( struct bufferevent_rate_limit_group *); /*@}*/ /** @name Rate limit manipulation Subtract a number of bytes from a bufferevent's read or write bucket. The decrement value can be negative, if you want to manually refill the bucket. If the change puts the bucket above or below zero, the bufferevent will resume or suspend reading writing as appropriate. These functions make no change in the buckets for the bufferevent's group, if any. Returns 0 on success, -1 on internal error. @{ */ EVENT2_EXPORT_SYMBOL int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr); EVENT2_EXPORT_SYMBOL int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr); /*@}*/ /** @name Group rate limit manipulation Subtract a number of bytes from a bufferevent rate-limiting group's read or write bucket. The decrement value can be negative, if you want to manually refill the bucket. If the change puts the bucket above or below zero, the bufferevents in the group will resume or suspend reading writing as appropriate. Returns 0 on success, -1 on internal error. @{ */ EVENT2_EXPORT_SYMBOL int bufferevent_rate_limit_group_decrement_read( struct bufferevent_rate_limit_group *, ev_ssize_t); EVENT2_EXPORT_SYMBOL int bufferevent_rate_limit_group_decrement_write( struct bufferevent_rate_limit_group *, ev_ssize_t); /*@}*/ /** * Inspect the total bytes read/written on a group. * * Set the variable pointed to by total_read_out to the total number of bytes * ever read on grp, and the variable pointed to by total_written_out to the * total number of bytes ever written on grp. */ EVENT2_EXPORT_SYMBOL void bufferevent_rate_limit_group_get_totals( struct bufferevent_rate_limit_group *grp, ev_uint64_t *total_read_out, ev_uint64_t *total_written_out); /** * Reset the total bytes read/written on a group. * * Reset the number of bytes read or written on grp as given by * bufferevent_rate_limit_group_reset_totals(). */ EVENT2_EXPORT_SYMBOL void bufferevent_rate_limit_group_reset_totals( struct bufferevent_rate_limit_group *grp); #ifdef __cplusplus } #endif #endif /* EVENT2_BUFFEREVENT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/http_compat.h0000644000076400001440000000630114111362573022525 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_HTTP_COMPAT_H_INCLUDED_ #define EVENT2_HTTP_COMPAT_H_INCLUDED_ /** @file event2/http_compat.h Potentially non-threadsafe versions of the functions in http.h: provided only for backwards compatibility. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include /** * Start an HTTP server on the specified address and port * * @deprecated It does not allow an event base to be specified * * @param address the address to which the HTTP server should be bound * @param port the port number on which the HTTP server should listen * @return a pointer to a newly initialized evhttp server structure * or NULL on error */ EVENT2_EXPORT_SYMBOL struct evhttp *evhttp_start(const char *address, ev_uint16_t port); /** * A connection object that can be used to for making HTTP requests. The * connection object tries to establish the connection when it is given an * http request object. * * @deprecated It does not allow an event base to be specified */ EVENT2_EXPORT_SYMBOL struct evhttp_connection *evhttp_connection_new( const char *address, ev_uint16_t port); /** * Associates an event base with the connection - can only be called * on a freshly created connection object that has not been used yet. * * @deprecated XXXX Why? */ EVENT2_EXPORT_SYMBOL void evhttp_connection_set_base(struct evhttp_connection *evcon, struct event_base *base); /** Returns the request URI */ #define evhttp_request_uri evhttp_request_get_uri #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/dns_compat.h0000644000076400001440000003045414111362573022340 0ustar00bernatusers00000000000000/* * Copyright (c) 2006-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_DNS_COMPAT_H_INCLUDED_ #define EVENT2_DNS_COMPAT_H_INCLUDED_ /** @file event2/dns_compat.h Potentially non-threadsafe versions of the functions in dns.h: provided only for backwards compatibility. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include #include /** Initialize the asynchronous DNS library. This function initializes support for non-blocking name resolution by calling evdns_resolv_conf_parse() on UNIX and evdns_config_windows_nameservers() on Windows. @deprecated This function is deprecated because it always uses the current event base, and is easily confused by multiple calls to event_init(), and so is not safe for multithreaded use. Additionally, it allocates a global structure that only one thread can use. The replacement is evdns_base_new(). @return 0 if successful, or -1 if an error occurred @see evdns_shutdown() */ EVENT2_EXPORT_SYMBOL int evdns_init(void); struct evdns_base; /** Return the global evdns_base created by event_init() and used by the other deprecated functions. @deprecated This function is deprecated because use of the global evdns_base is error-prone. */ EVENT2_EXPORT_SYMBOL struct evdns_base *evdns_get_global_base(void); /** Shut down the asynchronous DNS resolver and terminate all active requests. If the 'fail_requests' option is enabled, all active requests will return an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, the requests will be silently discarded. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_shutdown(). @param fail_requests if zero, active requests will be aborted; if non-zero, active requests will return DNS_ERR_SHUTDOWN. @see evdns_init() */ EVENT2_EXPORT_SYMBOL void evdns_shutdown(int fail_requests); /** Add a nameserver. The address should be an IPv4 address in network byte order. The type of address is chosen so that it matches in_addr.s_addr. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_nameserver_add(). @param address an IP address in network byte order @return 0 if successful, or -1 if an error occurred @see evdns_nameserver_ip_add() */ EVENT2_EXPORT_SYMBOL int evdns_nameserver_add(unsigned long int address); /** Get the number of configured nameservers. This returns the number of configured nameservers (not necessarily the number of running nameservers). This is useful for double-checking whether our calls to the various nameserver configuration functions have been successful. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_count_nameservers(). @return the number of configured nameservers @see evdns_nameserver_add() */ EVENT2_EXPORT_SYMBOL int evdns_count_nameservers(void); /** Remove all configured nameservers, and suspend all pending resolves. Resolves will not necessarily be re-attempted until evdns_resume() is called. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_clear_nameservers_and_suspend(). @return 0 if successful, or -1 if an error occurred @see evdns_resume() */ EVENT2_EXPORT_SYMBOL int evdns_clear_nameservers_and_suspend(void); /** Resume normal operation and continue any suspended resolve requests. Re-attempt resolves left in limbo after an earlier call to evdns_clear_nameservers_and_suspend(). @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_resume(). @return 0 if successful, or -1 if an error occurred @see evdns_clear_nameservers_and_suspend() */ EVENT2_EXPORT_SYMBOL int evdns_resume(void); /** Add a nameserver. This wraps the evdns_nameserver_add() function by parsing a string as an IP address and adds it as a nameserver. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_nameserver_ip_add(). @return 0 if successful, or -1 if an error occurred @see evdns_nameserver_add() */ EVENT2_EXPORT_SYMBOL int evdns_nameserver_ip_add(const char *ip_as_string); /** Lookup an A record for a given name. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_resolve_ipv4(). @param name a DNS hostname @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return 0 if successful, or -1 if an error occurred @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() */ EVENT2_EXPORT_SYMBOL int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); /** Lookup an AAAA record for a given name. @param name a DNS hostname @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return 0 if successful, or -1 if an error occurred @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() */ EVENT2_EXPORT_SYMBOL int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); struct in_addr; struct in6_addr; /** Lookup a PTR record for a given IP address. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_resolve_reverse(). @param in an IPv4 address @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return 0 if successful, or -1 if an error occurred @see evdns_resolve_reverse_ipv6() */ EVENT2_EXPORT_SYMBOL int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); /** Lookup a PTR record for a given IPv6 address. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_resolve_reverse_ipv6(). @param in an IPv6 address @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. @param callback a callback function to invoke when the request is completed @param ptr an argument to pass to the callback function @return 0 if successful, or -1 if an error occurred @see evdns_resolve_reverse_ipv6() */ EVENT2_EXPORT_SYMBOL int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); /** Set the value of a configuration option. The currently available configuration options are: ndots, timeout, max-timeouts, max-inflight, and attempts @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_set_option(). @param option the name of the configuration option to be modified @param val the value to be set @param flags Ignored. @return 0 if successful, or -1 if an error occurred */ EVENT2_EXPORT_SYMBOL int evdns_set_option(const char *option, const char *val, int flags); /** Parse a resolv.conf file. The 'flags' parameter determines what information is parsed from the resolv.conf file. See the man page for resolv.conf for the format of this file. The following directives are not parsed from the file: sortlist, rotate, no-check-names, inet6, debug. If this function encounters an error, the possible return values are: 1 = failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of memory, 5 = short read from file, 6 = no nameservers listed in the file @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_resolv_conf_parse(). @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| DNS_OPTIONS_ALL @param filename the path to the resolv.conf file @return 0 if successful, or various positive error codes if an error occurred (see above) @see resolv.conf(3), evdns_config_windows_nameservers() */ EVENT2_EXPORT_SYMBOL int evdns_resolv_conf_parse(int flags, const char *const filename); /** Clear the list of search domains. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_search_clear(). */ EVENT2_EXPORT_SYMBOL void evdns_search_clear(void); /** Add a domain to the list of search domains @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_search_add(). @param domain the domain to be added to the search list */ EVENT2_EXPORT_SYMBOL void evdns_search_add(const char *domain); /** Set the 'ndots' parameter for searches. Sets the number of dots which, when found in a name, causes the first query to be without any search domain. @deprecated This function is deprecated because it does not allow the caller to specify which evdns_base it applies to. The recommended function is evdns_base_search_ndots_set(). @param ndots the new ndots parameter */ EVENT2_EXPORT_SYMBOL void evdns_search_ndots_set(const int ndots); /** As evdns_server_new_with_base. @deprecated This function is deprecated because it does not allow the caller to specify which even_base it uses. The recommended function is evdns_add_server_port_with_base(). */ EVENT2_EXPORT_SYMBOL struct evdns_server_port * evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data); #ifdef _WIN32 EVENT2_EXPORT_SYMBOL int evdns_config_windows_nameservers(void); #define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED #endif #ifdef __cplusplus } #endif #endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/tag.h0000644000076400001440000001146214111362573020762 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_TAG_H_INCLUDED_ #define EVENT2_TAG_H_INCLUDED_ /** @file event2/tag.h Helper functions for reading and writing tagged data onto buffers. */ #include #ifdef __cplusplus extern "C" { #endif #include #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif /* For int types. */ #include struct evbuffer; /* * Marshaling tagged data - We assume that all tags are inserted in their * numeric order - so that unknown tags will always be higher than the * known ones - and we can just ignore the end of an event buffer. */ EVENT2_EXPORT_SYMBOL void evtag_init(void); /** Unmarshals the header and returns the length of the payload @param evbuf the buffer from which to unmarshal data @param ptag a pointer in which the tag id is being stored @returns -1 on failure or the number of bytes in the remaining payload. */ EVENT2_EXPORT_SYMBOL int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag); EVENT2_EXPORT_SYMBOL void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, ev_uint32_t len); EVENT2_EXPORT_SYMBOL void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag, struct evbuffer *data); /** Encode an integer and store it in an evbuffer. We encode integers by nybbles; the first nibble contains the number of significant nibbles - 1; this allows us to encode up to 64-bit integers. This function is byte-order independent. @param evbuf evbuffer to store the encoded number @param number a 32-bit integer */ EVENT2_EXPORT_SYMBOL void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number); EVENT2_EXPORT_SYMBOL void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number); EVENT2_EXPORT_SYMBOL void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer); EVENT2_EXPORT_SYMBOL void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint64_t integer); EVENT2_EXPORT_SYMBOL void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string); EVENT2_EXPORT_SYMBOL void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv); EVENT2_EXPORT_SYMBOL int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst); EVENT2_EXPORT_SYMBOL int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); EVENT2_EXPORT_SYMBOL int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); EVENT2_EXPORT_SYMBOL int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); EVENT2_EXPORT_SYMBOL int evtag_consume(struct evbuffer *evbuf); EVENT2_EXPORT_SYMBOL int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint32_t *pinteger); EVENT2_EXPORT_SYMBOL int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint64_t *pinteger); EVENT2_EXPORT_SYMBOL int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, size_t len); EVENT2_EXPORT_SYMBOL int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring); EVENT2_EXPORT_SYMBOL int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv); #ifdef __cplusplus } #endif #endif /* EVENT2_TAG_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/event2/rpc.h0000644000076400001440000005240414111362573020774 0ustar00bernatusers00000000000000/* * Copyright (c) 2006-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT2_RPC_H_INCLUDED_ #define EVENT2_RPC_H_INCLUDED_ /* For int types. */ #include #include #ifdef __cplusplus extern "C" { #endif /** @file rpc.h * * This header files provides basic support for an RPC server and client. * * To support RPCs in a server, every supported RPC command needs to be * defined and registered. * * EVRPC_HEADER(SendCommand, Request, Reply); * * SendCommand is the name of the RPC command. * Request is the name of a structure generated by event_rpcgen.py. * It contains all parameters relating to the SendCommand RPC. The * server needs to fill in the Reply structure. * Reply is the name of a structure generated by event_rpcgen.py. It * contains the answer to the RPC. * * To register an RPC with an HTTP server, you need to first create an RPC * base with: * * struct evrpc_base *base = evrpc_init(http); * * A specific RPC can then be registered with * * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg); * * when the server receives an appropriately formatted RPC, the user callback * is invoked. The callback needs to fill in the reply structure. * * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg); * * To send the reply, call EVRPC_REQUEST_DONE(rpc); * * See the regression test for an example. */ /** Determines if the member has been set in the message @param msg the message to inspect @param member the member variable to test for presences @return 1 if it's present or 0 otherwise. */ #define EVTAG_HAS(msg, member) \ ((msg)->member##_set == 1) #ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ /** Assigns a value to the member in the message. @param msg the message to which to assign a value @param member the name of the member variable @param value the value to assign */ #define EVTAG_ASSIGN(msg, member, value) \ (*(msg)->base->member##_assign)((msg), (value)) /** Assigns a value to the member in the message. @param msg the message to which to assign a value @param member the name of the member variable @param value the value to assign @param len the length of the value */ #define EVTAG_ASSIGN_WITH_LEN(msg, member, value, len) \ (*(msg)->base->member##_assign)((msg), (value), (len)) /** Returns the value for a member. @param msg the message from which to get the value @param member the name of the member variable @param pvalue a pointer to the variable to hold the value @return 0 on success, -1 otherwise. */ #define EVTAG_GET(msg, member, pvalue) \ (*(msg)->base->member##_get)((msg), (pvalue)) /** Returns the value for a member. @param msg the message from which to get the value @param member the name of the member variable @param pvalue a pointer to the variable to hold the value @param plen a pointer to the length of the value @return 0 on success, -1 otherwise. */ #define EVTAG_GET_WITH_LEN(msg, member, pvalue, plen) \ (*(msg)->base->member##_get)((msg), (pvalue), (plen)) #endif /* EVENT2_RPC_COMPAT_H_INCLUDED_ */ /** Adds a value to an array. */ #define EVTAG_ARRAY_ADD_VALUE(msg, member, value) \ (*(msg)->base->member##_add)((msg), (value)) /** Allocates a new entry in the array and returns it. */ #define EVTAG_ARRAY_ADD(msg, member) \ (*(msg)->base->member##_add)(msg) /** Gets a variable at the specified offset from the array. */ #define EVTAG_ARRAY_GET(msg, member, offset, pvalue) \ (*(msg)->base->member##_get)((msg), (offset), (pvalue)) /** Returns the number of entries in the array. */ #define EVTAG_ARRAY_LEN(msg, member) ((msg)->member##_length) struct evbuffer; struct event_base; struct evrpc_req_generic; struct evrpc_request_wrapper; struct evrpc; /** The type of a specific RPC Message * * @param rpcname the name of the RPC message */ #define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname struct evhttp_request; struct evrpc_status; struct evrpc_hook_meta; /** Creates the definitions and prototypes for an RPC * * You need to use EVRPC_HEADER to create structures and function prototypes * needed by the server and client implementation. The structures have to be * defined in an .rpc file and converted to source code via event_rpcgen.py * * @param rpcname the name of the RPC * @param reqstruct the name of the RPC request structure * @param replystruct the name of the RPC reply structure * @see EVRPC_GENERATE() */ #define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \ EVRPC_STRUCT(rpcname) { \ struct evrpc_hook_meta *hook_meta; \ struct reqstruct* request; \ struct rplystruct* reply; \ struct evrpc* rpc; \ struct evhttp_request* http_req; \ struct evbuffer* rpc_data; \ }; \ EVENT2_EXPORT_SYMBOL \ int evrpc_send_request_##rpcname(struct evrpc_pool *, \ struct reqstruct *, struct rplystruct *, \ void (*)(struct evrpc_status *, \ struct reqstruct *, struct rplystruct *, void *cbarg), \ void *); struct evrpc_pool; /** use EVRPC_GENERATE instead */ EVENT2_EXPORT_SYMBOL struct evrpc_request_wrapper *evrpc_make_request_ctx( struct evrpc_pool *pool, void *request, void *reply, const char *rpcname, void (*req_marshal)(struct evbuffer*, void *), void (*rpl_clear)(void *), int (*rpl_unmarshal)(void *, struct evbuffer *), void (*cb)(struct evrpc_status *, void *, void *, void *), void *cbarg); /** Creates a context structure that contains rpc specific information. * * EVRPC_MAKE_CTX is used to populate a RPC specific context that * contains information about marshaling the RPC data types. * * @param rpcname the name of the RPC * @param reqstruct the name of the RPC request structure * @param replystruct the name of the RPC reply structure * @param pool the evrpc_pool over which to make the request * @param request a pointer to the RPC request structure object * @param reply a pointer to the RPC reply structure object * @param cb the callback function to call when the RPC has completed * @param cbarg the argument to supply to the callback */ #define EVRPC_MAKE_CTX(rpcname, reqstruct, rplystruct, \ pool, request, reply, cb, cbarg) \ evrpc_make_request_ctx(pool, request, reply, \ #rpcname, \ (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ (void (*)(void *))rplystruct##_clear, \ (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \ (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ cbarg) /** Generates the code for receiving and sending an RPC message * * EVRPC_GENERATE is used to create the code corresponding to sending * and receiving a particular RPC message * * @param rpcname the name of the RPC * @param reqstruct the name of the RPC request structure * @param replystruct the name of the RPC reply structure * @see EVRPC_HEADER() */ #define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \ int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \ struct reqstruct *request, struct rplystruct *reply, \ void (*cb)(struct evrpc_status *, \ struct reqstruct *, struct rplystruct *, void *cbarg), \ void *cbarg) { \ return evrpc_send_request_generic(pool, request, reply, \ (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ cbarg, \ #rpcname, \ (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ (void (*)(void *))rplystruct##_clear, \ (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal); \ } /** Provides access to the HTTP request object underlying an RPC * * Access to the underlying http object; can be used to look at headers or * for getting the remote ip address * * @param rpc_req the rpc request structure provided to the server callback * @return an struct evhttp_request object that can be inspected for * HTTP headers or sender information. */ #define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req /** completes the server response to an rpc request */ EVENT2_EXPORT_SYMBOL void evrpc_request_done(struct evrpc_req_generic *req); /** accessors for request and reply */ EVENT2_EXPORT_SYMBOL void *evrpc_get_request(struct evrpc_req_generic *req); EVENT2_EXPORT_SYMBOL void *evrpc_get_reply(struct evrpc_req_generic *req); /** Creates the reply to an RPC request * * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected * to have been filled in. The request and reply pointers become invalid * after this call has finished. * * @param rpc_req the rpc request structure provided to the server callback */ #define EVRPC_REQUEST_DONE(rpc_req) do { \ struct evrpc_req_generic *req_ = (struct evrpc_req_generic *)(rpc_req); \ evrpc_request_done(req_); \ } while (0) struct evrpc_base; struct evhttp; /* functions to start up the rpc system */ /** Creates a new rpc base from which RPC requests can be received * * @param server a pointer to an existing HTTP server * @return a newly allocated evrpc_base struct or NULL if an error occurred * @see evrpc_free() */ EVENT2_EXPORT_SYMBOL struct evrpc_base *evrpc_init(struct evhttp *server); /** * Frees the evrpc base * * For now, you are responsible for making sure that no rpcs are ongoing. * * @param base the evrpc_base object to be freed * @see evrpc_init */ EVENT2_EXPORT_SYMBOL void evrpc_free(struct evrpc_base *base); /** register RPCs with the HTTP Server * * registers a new RPC with the HTTP server, each RPC needs to have * a unique name under which it can be identified. * * @param base the evrpc_base structure in which the RPC should be * registered. * @param name the name of the RPC * @param request the name of the RPC request structure * @param reply the name of the RPC reply structure * @param callback the callback that should be invoked when the RPC * is received. The callback has the following prototype * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg) * @param cbarg an additional parameter that can be passed to the callback. * The parameter can be used to carry around state. */ #define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \ evrpc_register_generic(base, #name, \ (void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \ (void *(*)(void *))request##_new_with_arg, NULL, \ (void (*)(void *))request##_free, \ (int (*)(void *, struct evbuffer *))request##_unmarshal, \ (void *(*)(void *))reply##_new_with_arg, NULL, \ (void (*)(void *))reply##_free, \ (int (*)(void *))reply##_complete, \ (void (*)(struct evbuffer *, void *))reply##_marshal) /** Low level function for registering an RPC with a server. Use EVRPC_REGISTER() instead. @see EVRPC_REGISTER() */ EVENT2_EXPORT_SYMBOL int evrpc_register_rpc(struct evrpc_base *, struct evrpc *, void (*)(struct evrpc_req_generic*, void *), void *); /** * Unregisters an already registered RPC * * @param base the evrpc_base object from which to unregister an RPC * @param name the name of the rpc to unregister * @return -1 on error or 0 when successful. * @see EVRPC_REGISTER() */ #define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name) EVENT2_EXPORT_SYMBOL int evrpc_unregister_rpc(struct evrpc_base *base, const char *name); /* * Client-side RPC support */ struct evhttp_connection; struct evrpc_status; /** launches an RPC and sends it to the server * * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server. * * @param name the name of the RPC * @param pool the evrpc_pool that contains the connection objects over which * the request should be sent. * @param request a pointer to the RPC request structure - it contains the * data to be sent to the server. * @param reply a pointer to the RPC reply structure. It is going to be filled * if the request was answered successfully * @param cb the callback to invoke when the RPC request has been answered * @param cbarg an additional argument to be passed to the client * @return 0 on success, -1 on failure */ #define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \ evrpc_send_request_##name((pool), (request), (reply), (cb), (cbarg)) /** Makes an RPC request based on the provided context. This is a low-level function and should not be used directly unless a custom context object is provided. Use EVRPC_MAKE_REQUEST() instead. @param ctx a context from EVRPC_MAKE_CTX() @returns 0 on success, -1 otherwise. @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX() */ EVENT2_EXPORT_SYMBOL int evrpc_make_request(struct evrpc_request_wrapper *ctx); /** creates an rpc connection pool * * a pool has a number of connections associated with it. * rpc requests are always made via a pool. * * @param base a pointer to an struct event_based object; can be left NULL * in singled-threaded applications * @return a newly allocated struct evrpc_pool object or NULL if an error * occurred * @see evrpc_pool_free() */ EVENT2_EXPORT_SYMBOL struct evrpc_pool *evrpc_pool_new(struct event_base *base); /** frees an rpc connection pool * * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new() * @see evrpc_pool_new() */ EVENT2_EXPORT_SYMBOL void evrpc_pool_free(struct evrpc_pool *pool); /** * Adds a connection over which rpc can be dispatched to the pool. * * The connection object must have been newly created. * * @param pool the pool to which to add the connection * @param evcon the connection to add to the pool. */ EVENT2_EXPORT_SYMBOL void evrpc_pool_add_connection(struct evrpc_pool *pool, struct evhttp_connection *evcon); /** * Removes a connection from the pool. * * The connection object must have been newly created. * * @param pool the pool from which to remove the connection * @param evcon the connection to remove from the pool. */ EVENT2_EXPORT_SYMBOL void evrpc_pool_remove_connection(struct evrpc_pool *pool, struct evhttp_connection *evcon); /** * Sets the timeout in secs after which a request has to complete. The * RPC is completely aborted if it does not complete by then. Setting * the timeout to 0 means that it never timeouts and can be used to * implement callback type RPCs. * * Any connection already in the pool will be updated with the new * timeout. Connections added to the pool after set_timeout has be * called receive the pool timeout only if no timeout has been set * for the connection itself. * * @param pool a pointer to a struct evrpc_pool object * @param timeout_in_secs the number of seconds after which a request should * timeout and a failure be returned to the callback. */ EVENT2_EXPORT_SYMBOL void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs); /** * Hooks for changing the input and output of RPCs; this can be used to * implement compression, authentication, encryption, ... */ enum EVRPC_HOOK_TYPE { EVRPC_INPUT, /**< apply the function to an input hook */ EVRPC_OUTPUT /**< apply the function to an output hook */ }; #ifndef _WIN32 /** Deprecated alias for EVRPC_INPUT. Not available on windows, where it * conflicts with platform headers. */ #define INPUT EVRPC_INPUT /** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it * conflicts with platform headers. */ #define OUTPUT EVRPC_OUTPUT #endif /** * Return value from hook processing functions */ enum EVRPC_HOOK_RESULT { EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */ EVRPC_CONTINUE = 0, /**< continue processing the rpc */ EVRPC_PAUSE = 1 /**< pause processing request until resumed */ }; /** adds a processing hook to either an rpc base or rpc pool * * If a hook returns TERMINATE, the processing is aborted. On CONTINUE, * the request is immediately processed after the hook returns. If the * hook returns PAUSE, request processing stops until evrpc_resume_request() * has been called. * * The add functions return handles that can be used for removing hooks. * * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool * @param hook_type either INPUT or OUTPUT * @param cb the callback to call when the hook is activated * @param cb_arg an additional argument for the callback * @return a handle to the hook so it can be removed later * @see evrpc_remove_hook() */ EVENT2_EXPORT_SYMBOL void *evrpc_add_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *), void *cb_arg); /** removes a previously added hook * * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool * @param hook_type either INPUT or OUTPUT * @param handle a handle returned by evrpc_add_hook() * @return 1 on success or 0 on failure * @see evrpc_add_hook() */ EVENT2_EXPORT_SYMBOL int evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle); /** resume a paused request * * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool * @param ctx the context pointer provided to the original hook call */ EVENT2_EXPORT_SYMBOL int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res); /** adds meta data to request * * evrpc_hook_add_meta() allows hooks to add meta data to a request. for * a client request, the meta data can be inserted by an outgoing request hook * and retrieved by the incoming request hook. * * @param ctx the context provided to the hook call * @param key a NUL-terminated c-string * @param data the data to be associated with the key * @param data_size the size of the data */ EVENT2_EXPORT_SYMBOL void evrpc_hook_add_meta(void *ctx, const char *key, const void *data, size_t data_size); /** retrieves meta data previously associated * * evrpc_hook_find_meta() can be used to retrieve meta data associated to a * request by a previous hook. * @param ctx the context provided to the hook call * @param key a NUL-terminated c-string * @param data pointer to a data pointer that will contain the retrieved data * @param data_size pointer to the size of the data * @return 0 on success or -1 on failure */ EVENT2_EXPORT_SYMBOL int evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size); /** * returns the connection object associated with the request * * @param ctx the context provided to the hook call * @return a pointer to the evhttp_connection object or NULL if an error * occurred */ EVENT2_EXPORT_SYMBOL struct evhttp_connection *evrpc_hook_get_connection(void *ctx); /** Function for sending a generic RPC request. Do not call this function directly, use EVRPC_MAKE_REQUEST() instead. @see EVRPC_MAKE_REQUEST() */ EVENT2_EXPORT_SYMBOL int evrpc_send_request_generic(struct evrpc_pool *pool, void *request, void *reply, void (*cb)(struct evrpc_status *, void *, void *, void *), void *cb_arg, const char *rpcname, void (*req_marshal)(struct evbuffer *, void *), void (*rpl_clear)(void *), int (*rpl_unmarshal)(void *, struct evbuffer *)); /** Function for registering a generic RPC with the RPC base. Do not call this function directly, use EVRPC_REGISTER() instead. @see EVRPC_REGISTER() */ EVENT2_EXPORT_SYMBOL int evrpc_register_generic(struct evrpc_base *base, const char *name, void (*callback)(struct evrpc_req_generic *, void *), void *cbarg, void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *), int (*req_unmarshal)(void *, struct evbuffer *), void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *), int (*rpl_complete)(void *), void (*rpl_marshal)(struct evbuffer *, void *)); /** accessors for obscure and undocumented functionality */ EVENT2_EXPORT_SYMBOL struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx); EVENT2_EXPORT_SYMBOL void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx, struct evrpc_pool *pool); EVENT2_EXPORT_SYMBOL void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx, void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg), void *cb_arg); #ifdef __cplusplus } #endif #endif /* EVENT2_RPC_H_INCLUDED_ */ lldpd-1.0.13/libevent/include/include.am0000644000076400001440000000267414111362571020600 0ustar00bernatusers00000000000000# include/include.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. include_event2dir = $(includedir)/event2 EVENT2_EXPORT = \ include/event2/buffer.h \ include/event2/buffer_compat.h \ include/event2/bufferevent.h \ include/event2/bufferevent_compat.h \ include/event2/bufferevent_struct.h \ include/event2/dns.h \ include/event2/dns_compat.h \ include/event2/dns_struct.h \ include/event2/event.h \ include/event2/event_compat.h \ include/event2/event_struct.h \ include/event2/http.h \ include/event2/http_compat.h \ include/event2/http_struct.h \ include/event2/keyvalq_struct.h \ include/event2/listener.h \ include/event2/rpc.h \ include/event2/rpc_compat.h \ include/event2/rpc_struct.h \ include/event2/tag.h \ include/event2/tag_compat.h \ include/event2/thread.h \ include/event2/util.h \ include/event2/visibility.h if OPENSSL EVENT2_EXPORT += include/event2/bufferevent_ssl.h endif ## Without the nobase_ prefixing, Automake would strip "include/event2/" from ## the source header filename to derive the installed header filename. ## With nobase_ the installed path is $(includedir)/include/event2/ev*.h. if INSTALL_LIBEVENT include_event2_HEADERS = $(EVENT2_EXPORT) nodist_include_event2_HEADERS = include/event2/event-config.h else noinst_HEADERS += $(EVENT2_EXPORT) nodist_noinst_HEADERS = include/event2/event-config.h endif lldpd-1.0.13/libevent/include/evhttp.h0000644000076400001440000000376314111362571020321 0ustar00bernatusers00000000000000/* * Copyright 2000-2007 Niels Provos * Copyright 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT1_EVHTTP_H_INCLUDED_ #define EVENT1_EVHTTP_H_INCLUDED_ /** @file evhttp.h An http implementation subsystem for Libevent. The header is deprecated in Libevent 2.0 and later; please use instead. Depending on what functionality you need, you may also want to include more of the other headers. */ #include #include #include #include #endif /* EVENT1_EVHTTP_H_INCLUDED_ */ lldpd-1.0.13/libevent/event-internal.h0000644000076400001440000004200414111362570020305 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVENT_INTERNAL_H_INCLUDED_ #define EVENT_INTERNAL_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.h" #include "evconfig-private.h" #include #include #include "event2/event_struct.h" #include "minheap-internal.h" #include "evsignal-internal.h" #include "mm-internal.h" #include "defer-internal.h" /* map union members back */ /* mutually exclusive */ #define ev_signal_next ev_.ev_signal.ev_signal_next #define ev_io_next ev_.ev_io.ev_io_next #define ev_io_timeout ev_.ev_io.ev_timeout /* used only by signals */ #define ev_ncalls ev_.ev_signal.ev_ncalls #define ev_pncalls ev_.ev_signal.ev_pncalls #define ev_pri ev_evcallback.evcb_pri #define ev_flags ev_evcallback.evcb_flags #define ev_closure ev_evcallback.evcb_closure #define ev_callback ev_evcallback.evcb_cb_union.evcb_callback #define ev_arg ev_evcallback.evcb_arg /** @name Event closure codes Possible values for evcb_closure in struct event_callback @{ */ /** A regular event. Uses the evcb_callback callback */ #define EV_CLOSURE_EVENT 0 /** A signal event. Uses the evcb_callback callback */ #define EV_CLOSURE_EVENT_SIGNAL 1 /** A persistent non-signal event. Uses the evcb_callback callback */ #define EV_CLOSURE_EVENT_PERSIST 2 /** A simple callback. Uses the evcb_selfcb callback. */ #define EV_CLOSURE_CB_SELF 3 /** A finalizing callback. Uses the evcb_cbfinalize callback. */ #define EV_CLOSURE_CB_FINALIZE 4 /** A finalizing event. Uses the evcb_evfinalize callback. */ #define EV_CLOSURE_EVENT_FINALIZE 5 /** A finalizing event that should get freed after. Uses the evcb_evfinalize * callback. */ #define EV_CLOSURE_EVENT_FINALIZE_FREE 6 /** @} */ /** Structure to define the backend of a given event_base. */ struct eventop { /** The name of this backend. */ const char *name; /** Function to set up an event_base to use this backend. It should * create a new structure holding whatever information is needed to * run the backend, and return it. The returned pointer will get * stored by event_init into the event_base.evbase field. On failure, * this function should return NULL. */ void *(*init)(struct event_base *); /** Enable reading/writing on a given fd or signal. 'events' will be * the events that we're trying to enable: one or more of EV_READ, * EV_WRITE, EV_SIGNAL, and EV_ET. 'old' will be those events that * were enabled on this fd previously. 'fdinfo' will be a structure * associated with the fd by the evmap; its size is defined by the * fdinfo field below. It will be set to 0 the first time the fd is * added. The function should return 0 on success and -1 on error. */ int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo); /** As "add", except 'events' contains the events we mean to disable. */ int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo); /** Function to implement the core of an event loop. It must see which added events are ready, and cause event_active to be called for each active event (usually via event_io_active or such). It should return 0 on success and -1 on error. */ int (*dispatch)(struct event_base *, struct timeval *); /** Function to clean up and free our data from the event_base. */ void (*dealloc)(struct event_base *); /** Flag: set if we need to reinitialize the event base after we fork. */ int need_reinit; /** Bit-array of supported event_method_features that this backend can * provide. */ enum event_method_feature features; /** Length of the extra information we should record for each fd that has one or more active events. This information is recorded as part of the evmap entry for each fd, and passed as an argument to the add and del functions above. */ size_t fdinfo_len; }; #ifdef _WIN32 /* If we're on win32, then file descriptors are not nice low densely packed integers. Instead, they are pointer-like windows handles, and we want to use a hashtable instead of an array to map fds to events. */ #define EVMAP_USE_HT #endif /* #define HT_CACHE_HASH_VALS */ #ifdef EVMAP_USE_HT #define HT_NO_CACHE_HASH_VALUES #include "ht-internal.h" struct event_map_entry; HT_HEAD(event_io_map, event_map_entry); #else #define event_io_map event_signal_map #endif /* Used to map signal numbers to a list of events. If EVMAP_USE_HT is not defined, this structure is also used as event_io_map, which maps fds to a list of events. */ struct event_signal_map { /* An array of evmap_io * or of evmap_signal *; empty entries are * set to NULL. */ void **entries; /* The number of entries available in entries */ int nentries; }; /* A list of events waiting on a given 'common' timeout value. Ordinarily, * events waiting for a timeout wait on a minheap. Sometimes, however, a * queue can be faster. **/ struct common_timeout_list { /* List of events currently waiting in the queue. */ struct event_list events; /* 'magic' timeval used to indicate the duration of events in this * queue. */ struct timeval duration; /* Event that triggers whenever one of the events in the queue is * ready to activate */ struct event timeout_event; /* The event_base that this timeout list is part of */ struct event_base *base; }; /** Mask used to get the real tv_usec value from a common timeout. */ #define COMMON_TIMEOUT_MICROSECONDS_MASK 0x000fffff struct event_change; /* List of 'changes' since the last call to eventop.dispatch. Only maintained * if the backend is using changesets. */ struct event_changelist { struct event_change *changes; int n_changes; int changes_size; }; #ifndef EVENT__DISABLE_DEBUG_MODE /* Global internal flag: set to one if debug mode is on. */ extern int event_debug_mode_on_; #define EVENT_DEBUG_MODE_IS_ON() (event_debug_mode_on_) #else #define EVENT_DEBUG_MODE_IS_ON() (0) #endif TAILQ_HEAD(evcallback_list, event_callback); /* Sets up an event for processing once */ struct event_once { LIST_ENTRY(event_once) next_once; struct event ev; void (*cb)(evutil_socket_t, short, void *); void *arg; }; struct event_base { /** Function pointers and other data to describe this event_base's * backend. */ const struct eventop *evsel; /** Pointer to backend-specific data. */ void *evbase; /** List of changes to tell backend about at next dispatch. Only used * by the O(1) backends. */ struct event_changelist changelist; /** Function pointers used to describe the backend that this event_base * uses for signals */ const struct eventop *evsigsel; /** Data to implement the common signal handler code. */ struct evsig_info sig; /** Number of virtual events */ int virtual_event_count; /** Maximum number of virtual events active */ int virtual_event_count_max; /** Number of total events added to this event_base */ int event_count; /** Maximum number of total events added to this event_base */ int event_count_max; /** Number of total events active in this event_base */ int event_count_active; /** Maximum number of total events active in this event_base */ int event_count_active_max; /** Set if we should terminate the loop once we're done processing * events. */ int event_gotterm; /** Set if we should terminate the loop immediately */ int event_break; /** Set if we should start a new instance of the loop immediately. */ int event_continue; /** The currently running priority of events */ int event_running_priority; /** Set if we're running the event_base_loop function, to prevent * reentrant invocation. */ int running_loop; /** Set to the number of deferred_cbs we've made 'active' in the * loop. This is a hack to prevent starvation; it would be smarter * to just use event_config_set_max_dispatch_interval's max_callbacks * feature */ int n_deferreds_queued; /* Active event management. */ /** An array of nactivequeues queues for active event_callbacks (ones * that have triggered, and whose callbacks need to be called). Low * priority numbers are more important, and stall higher ones. */ struct evcallback_list *activequeues; /** The length of the activequeues array */ int nactivequeues; /** A list of event_callbacks that should become active the next time * we process events, but not this time. */ struct evcallback_list active_later_queue; /* common timeout logic */ /** An array of common_timeout_list* for all of the common timeout * values we know. */ struct common_timeout_list **common_timeout_queues; /** The number of entries used in common_timeout_queues */ int n_common_timeouts; /** The total size of common_timeout_queues. */ int n_common_timeouts_allocated; /** Mapping from file descriptors to enabled (added) events */ struct event_io_map io; /** Mapping from signal numbers to enabled (added) events. */ struct event_signal_map sigmap; /** Priority queue of events with timeouts. */ struct min_heap timeheap; /** Stored timeval: used to avoid calling gettimeofday/clock_gettime * too often. */ struct timeval tv_cache; struct evutil_monotonic_timer monotonic_timer; /** Difference between internal time (maybe from clock_gettime) and * gettimeofday. */ struct timeval tv_clock_diff; /** Second in which we last updated tv_clock_diff, in monotonic time. */ time_t last_updated_clock_diff; #ifndef EVENT__DISABLE_THREAD_SUPPORT /* threading support */ /** The thread currently running the event_loop for this base */ unsigned long th_owner_id; /** A lock to prevent conflicting accesses to this event_base */ void *th_base_lock; /** A condition that gets signalled when we're done processing an * event with waiters on it. */ void *current_event_cond; /** Number of threads blocking on current_event_cond. */ int current_event_waiters; #endif /** The event whose callback is executing right now */ struct event_callback *current_event; #ifdef _WIN32 /** IOCP support structure, if IOCP is enabled. */ struct event_iocp_port *iocp; #endif /** Flags that this base was configured with */ enum event_base_config_flag flags; struct timeval max_dispatch_time; int max_dispatch_callbacks; int limit_callbacks_after_prio; /* Notify main thread to wake up break, etc. */ /** True if the base already has a pending notify, and we don't need * to add any more. */ int is_notify_pending; /** A socketpair used by some th_notify functions to wake up the main * thread. */ evutil_socket_t th_notify_fd[2]; /** An event used by some th_notify functions to wake up the main * thread. */ struct event th_notify; /** A function used to wake up the main thread from another thread. */ int (*th_notify_fn)(struct event_base *base); /** Saved seed for weak random number generator. Some backends use * this to produce fairness among sockets. Protected by th_base_lock. */ struct evutil_weakrand_state weakrand_seed; /** List of event_onces that have not yet fired. */ LIST_HEAD(once_event_list, event_once) once_events; }; struct event_config_entry { TAILQ_ENTRY(event_config_entry) next; const char *avoid_method; }; /** Internal structure: describes the configuration we want for an event_base * that we're about to allocate. */ struct event_config { TAILQ_HEAD(event_configq, event_config_entry) entries; int n_cpus_hint; struct timeval max_dispatch_interval; int max_dispatch_callbacks; int limit_callbacks_after_prio; enum event_method_feature require_features; enum event_base_config_flag flags; }; /* Internal use only: Functions that might be missing from */ #ifndef LIST_END #define LIST_END(head) NULL #endif #ifndef TAILQ_FIRST #define TAILQ_FIRST(head) ((head)->tqh_first) #endif #ifndef TAILQ_END #define TAILQ_END(head) NULL #endif #ifndef TAILQ_NEXT #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #endif #ifndef TAILQ_FOREACH #define TAILQ_FOREACH(var, head, field) \ for ((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #endif #ifndef TAILQ_INSERT_BEFORE #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #endif #define N_ACTIVE_CALLBACKS(base) \ ((base)->event_count_active) int evsig_set_handler_(struct event_base *base, int evsignal, void (*fn)(int)); int evsig_restore_handler_(struct event_base *base, int evsignal); int event_add_nolock_(struct event *ev, const struct timeval *tv, int tv_is_absolute); /** Argument for event_del_nolock_. Tells event_del not to block on the event * if it's running in another thread. */ #define EVENT_DEL_NOBLOCK 0 /** Argument for event_del_nolock_. Tells event_del to block on the event * if it's running in another thread, regardless of its value for EV_FINALIZE */ #define EVENT_DEL_BLOCK 1 /** Argument for event_del_nolock_. Tells event_del to block on the event * if it is running in another thread and it doesn't have EV_FINALIZE set. */ #define EVENT_DEL_AUTOBLOCK 2 /** Argument for event_del_nolock_. Tells event_del to proceed even if the * event is set up for finalization rather for regular use.*/ #define EVENT_DEL_EVEN_IF_FINALIZING 3 int event_del_nolock_(struct event *ev, int blocking); int event_remove_timer_nolock_(struct event *ev); void event_active_nolock_(struct event *ev, int res, short count); EVENT2_EXPORT_SYMBOL int event_callback_activate_(struct event_base *, struct event_callback *); int event_callback_activate_nolock_(struct event_base *, struct event_callback *); int event_callback_cancel_(struct event_base *base, struct event_callback *evcb); void event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *)); EVENT2_EXPORT_SYMBOL void event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *)); int event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcb, void (*cb)(struct event_callback *, void *)); EVENT2_EXPORT_SYMBOL void event_active_later_(struct event *ev, int res); void event_active_later_nolock_(struct event *ev, int res); int event_callback_activate_later_nolock_(struct event_base *base, struct event_callback *evcb); int event_callback_cancel_nolock_(struct event_base *base, struct event_callback *evcb, int even_if_finalizing); void event_callback_init_(struct event_base *base, struct event_callback *cb); /* FIXME document. */ EVENT2_EXPORT_SYMBOL void event_base_add_virtual_(struct event_base *base); void event_base_del_virtual_(struct event_base *base); /** For debugging: unless assertions are disabled, verify the referential integrity of the internal data structures of 'base'. This operation can be expensive. Returns on success; aborts on failure. */ EVENT2_EXPORT_SYMBOL void event_base_assert_ok_(struct event_base *base); void event_base_assert_ok_nolock_(struct event_base *base); /* Helper function: Call 'fn' exactly once every inserted or active event in * the event_base 'base'. * * If fn returns 0, continue on to the next event. Otherwise, return the same * value that fn returned. * * Requires that 'base' be locked. */ int event_base_foreach_event_nolock_(struct event_base *base, event_base_foreach_event_cb cb, void *arg); /* Cleanup function to reset debug mode during shutdown. * * Calling this function doesn't mean it'll be possible to re-enable * debug mode if any events were added. */ void event_disable_debug_mode(void); #ifdef __cplusplus } #endif #endif /* EVENT_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/minheap-internal.h0000644000076400001440000001560214111362570020611 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Copyright (c) 2006 Maxim Yegorushkin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MINHEAP_INTERNAL_H_INCLUDED_ #define MINHEAP_INTERNAL_H_INCLUDED_ #include "event2/event-config.h" #include "evconfig-private.h" #include "event2/event.h" #include "event2/event_struct.h" #include "event2/util.h" #include "util-internal.h" #include "mm-internal.h" typedef struct min_heap { struct event** p; unsigned n, a; } min_heap_t; static inline void min_heap_ctor_(min_heap_t* s); static inline void min_heap_dtor_(min_heap_t* s); static inline void min_heap_elem_init_(struct event* e); static inline int min_heap_elt_is_top_(const struct event *e); static inline int min_heap_empty_(min_heap_t* s); static inline unsigned min_heap_size_(min_heap_t* s); static inline struct event* min_heap_top_(min_heap_t* s); static inline int min_heap_reserve_(min_heap_t* s, unsigned n); static inline int min_heap_push_(min_heap_t* s, struct event* e); static inline struct event* min_heap_pop_(min_heap_t* s); static inline int min_heap_adjust_(min_heap_t *s, struct event* e); static inline int min_heap_erase_(min_heap_t* s, struct event* e); static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e); static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e); static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e); #define min_heap_elem_greater(a, b) \ (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >)) void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; } void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); } void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; } int min_heap_empty_(min_heap_t* s) { return 0u == s->n; } unsigned min_heap_size_(min_heap_t* s) { return s->n; } struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; } int min_heap_push_(min_heap_t* s, struct event* e) { if (s->n == UINT32_MAX || min_heap_reserve_(s, s->n + 1)) return -1; min_heap_shift_up_(s, s->n++, e); return 0; } struct event* min_heap_pop_(min_heap_t* s) { if (s->n) { struct event* e = *s->p; min_heap_shift_down_(s, 0u, s->p[--s->n]); e->ev_timeout_pos.min_heap_idx = -1; return e; } return 0; } int min_heap_elt_is_top_(const struct event *e) { return e->ev_timeout_pos.min_heap_idx == 0; } int min_heap_erase_(min_heap_t* s, struct event* e) { if (-1 != e->ev_timeout_pos.min_heap_idx) { struct event *last = s->p[--s->n]; unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; /* we replace e with the last element in the heap. We might need to shift it upward if it is less than its parent, or downward if it is greater than one or both its children. Since the children are known to be less than the parent, it can't need to shift both up and down. */ if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last)) min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last); else min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last); e->ev_timeout_pos.min_heap_idx = -1; return 0; } return -1; } int min_heap_adjust_(min_heap_t *s, struct event *e) { if (-1 == e->ev_timeout_pos.min_heap_idx) { return min_heap_push_(s, e); } else { unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2; /* The position of e has changed; we shift it up or down * as needed. We can't need to do both. */ if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e)) min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e); else min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e); return 0; } } int min_heap_reserve_(min_heap_t* s, unsigned n) { if (s->a < n) { struct event** p; unsigned a = s->a ? s->a * 2 : 8; if (a < n) a = n; #if (SIZE_MAX == UINT32_MAX) if (a > SIZE_MAX / sizeof *p) return -1; #endif if (!(p = (struct event**)mm_realloc(s->p, a * sizeof *p))) return -1; s->p = p; s->a = a; } return 0; } void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned parent = (hole_index - 1) / 2; do { (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = parent; parent = (hole_index - 1) / 2; } while (hole_index && min_heap_elem_greater(s->p[parent], e)); (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; } void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned parent = (hole_index - 1) / 2; while (hole_index && min_heap_elem_greater(s->p[parent], e)) { (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = parent; parent = (hole_index - 1) / 2; } (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; } void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) { unsigned min_child = 2 * (hole_index + 1); while (min_child <= s->n) { min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]); if (!(min_heap_elem_greater(e, s->p[min_child]))) break; (s->p[hole_index] = s->p[min_child])->ev_timeout_pos.min_heap_idx = hole_index; hole_index = min_child; min_child = 2 * (hole_index + 1); } (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index; } #endif /* MINHEAP_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/epoll.c0000644000076400001440000003504114111362570016463 0ustar00bernatusers00000000000000/* * Copyright 2000-2007 Niels Provos * Copyright 2007-2012 Niels Provos, Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_EPOLL #include #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef EVENT__HAVE_FCNTL_H #include #endif #ifdef EVENT__HAVE_SYS_TIMERFD_H #include #endif #include "event-internal.h" #include "evsignal-internal.h" #include "event2/thread.h" #include "evthread-internal.h" #include "log-internal.h" #include "evmap-internal.h" #include "changelist-internal.h" #include "time-internal.h" /* Since Linux 2.6.17, epoll is able to report about peer half-closed connection using special EPOLLRDHUP flag on a read event. */ #if !defined(EPOLLRDHUP) #define EPOLLRDHUP 0 #define EARLY_CLOSE_IF_HAVE_RDHUP 0 #else #define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE #endif #include "epolltable-internal.h" #if defined(EVENT__HAVE_SYS_TIMERFD_H) && \ defined(EVENT__HAVE_TIMERFD_CREATE) && \ defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \ defined(TFD_CLOEXEC) /* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available and working. This means that we can't support it on 2.6.25 (where timerfd was introduced) or 2.6.26, since 2.6.27 introduced those flags. */ #define USING_TIMERFD #endif struct epollop { struct epoll_event *events; int nevents; int epfd; #ifdef USING_TIMERFD int timerfd; #endif }; static void *epoll_init(struct event_base *); static int epoll_dispatch(struct event_base *, struct timeval *); static void epoll_dealloc(struct event_base *); static const struct eventop epollops_changelist = { "epoll (with changelist)", epoll_init, event_changelist_add_, event_changelist_del_, epoll_dispatch, epoll_dealloc, 1, /* need reinit */ EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP, EVENT_CHANGELIST_FDINFO_SIZE }; static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd, short old, short events, void *p); static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd, short old, short events, void *p); const struct eventop epollops = { "epoll", epoll_init, epoll_nochangelist_add, epoll_nochangelist_del, epoll_dispatch, epoll_dealloc, 1, /* need reinit */ EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE, 0 }; #define INITIAL_NEVENT 32 #define MAX_NEVENT 4096 /* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout * values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the * largest number of msec we can support here is 2147482. Let's * round that down by 47 seconds. */ #define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000) static void * epoll_init(struct event_base *base) { int epfd = -1; struct epollop *epollop; #ifdef EVENT__HAVE_EPOLL_CREATE1 /* First, try the shiny new epoll_create1 interface, if we have it. */ epfd = epoll_create1(EPOLL_CLOEXEC); #endif if (epfd == -1) { /* Initialize the kernel queue using the old interface. (The size field is ignored since 2.6.8.) */ if ((epfd = epoll_create(32000)) == -1) { if (errno != ENOSYS) event_warn("epoll_create"); return (NULL); } evutil_make_socket_closeonexec(epfd); } if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) { close(epfd); return (NULL); } epollop->epfd = epfd; /* Initialize fields */ epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event)); if (epollop->events == NULL) { mm_free(epollop); close(epfd); return (NULL); } epollop->nevents = INITIAL_NEVENT; if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 || ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 && evutil_getenv_("EVENT_EPOLL_USE_CHANGELIST") != NULL)) { base->evsel = &epollops_changelist; } #ifdef USING_TIMERFD /* The epoll interface ordinarily gives us one-millisecond precision, so on Linux it makes perfect sense to use the CLOCK_MONOTONIC_COARSE timer. But when the user has set the new PRECISE_TIMER flag for an event_base, we can try to use timerfd to give them finer granularity. */ if ((base->flags & EVENT_BASE_FLAG_PRECISE_TIMER) && base->monotonic_timer.monotonic_clock == CLOCK_MONOTONIC) { int fd; fd = epollop->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); if (epollop->timerfd >= 0) { struct epoll_event epev; memset(&epev, 0, sizeof(epev)); epev.data.fd = epollop->timerfd; epev.events = EPOLLIN; if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, fd, &epev) < 0) { event_warn("epoll_ctl(timerfd)"); close(fd); epollop->timerfd = -1; } } else { if (errno != EINVAL && errno != ENOSYS) { /* These errors probably mean that we were * compiled with timerfd/TFD_* support, but * we're running on a kernel that lacks those. */ event_warn("timerfd_create"); } epollop->timerfd = -1; } } else { epollop->timerfd = -1; } #endif evsig_init_(base); return (epollop); } static const char * change_to_string(int change) { change &= (EV_CHANGE_ADD|EV_CHANGE_DEL); if (change == EV_CHANGE_ADD) { return "add"; } else if (change == EV_CHANGE_DEL) { return "del"; } else if (change == 0) { return "none"; } else { return "???"; } } static const char * epoll_op_to_string(int op) { return op == EPOLL_CTL_ADD?"ADD": op == EPOLL_CTL_DEL?"DEL": op == EPOLL_CTL_MOD?"MOD": "???"; } #define PRINT_CHANGES(op, events, ch, status) \ "Epoll %s(%d) on fd %d " status ". " \ "Old events were %d; " \ "read change was %d (%s); " \ "write change was %d (%s); " \ "close change was %d (%s)", \ epoll_op_to_string(op), \ events, \ ch->fd, \ ch->old_events, \ ch->read_change, \ change_to_string(ch->read_change), \ ch->write_change, \ change_to_string(ch->write_change), \ ch->close_change, \ change_to_string(ch->close_change) static int epoll_apply_one_change(struct event_base *base, struct epollop *epollop, const struct event_change *ch) { struct epoll_event epev; int op, events = 0; int idx; idx = EPOLL_OP_TABLE_INDEX(ch); op = epoll_op_table[idx].op; events = epoll_op_table[idx].events; if (!events) { EVUTIL_ASSERT(op == 0); return 0; } if ((ch->read_change|ch->write_change|ch->close_change) & EV_CHANGE_ET) events |= EPOLLET; memset(&epev, 0, sizeof(epev)); epev.data.fd = ch->fd; epev.events = events; if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) { event_debug((PRINT_CHANGES(op, epev.events, ch, "okay"))); return 0; } switch (op) { case EPOLL_CTL_MOD: if (errno == ENOENT) { /* If a MOD operation fails with ENOENT, the * fd was probably closed and re-opened. We * should retry the operation as an ADD. */ if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) { event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too", (int)epev.events, ch->fd); return -1; } else { event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.", (int)epev.events, ch->fd)); return 0; } } break; case EPOLL_CTL_ADD: if (errno == EEXIST) { /* If an ADD operation fails with EEXIST, * either the operation was redundant (as with a * precautionary add), or we ran into a fun * kernel bug where using dup*() to duplicate the * same file into the same fd gives you the same epitem * rather than a fresh one. For the second case, * we must retry with MOD. */ if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) { event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too", (int)epev.events, ch->fd); return -1; } else { event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.", (int)epev.events, ch->fd)); return 0; } } break; case EPOLL_CTL_DEL: if (errno == ENOENT || errno == EBADF || errno == EPERM) { /* If a delete fails with one of these errors, * that's fine too: we closed the fd before we * got around to calling epoll_dispatch. */ event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.", (int)epev.events, ch->fd, strerror(errno))); return 0; } break; default: break; } event_warn(PRINT_CHANGES(op, epev.events, ch, "failed")); return -1; } static int epoll_apply_changes(struct event_base *base) { struct event_changelist *changelist = &base->changelist; struct epollop *epollop = base->evbase; struct event_change *ch; int r = 0; int i; for (i = 0; i < changelist->n_changes; ++i) { ch = &changelist->changes[i]; if (epoll_apply_one_change(base, epollop, ch) < 0) r = -1; } return (r); } static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd, short old, short events, void *p) { struct event_change ch; ch.fd = fd; ch.old_events = old; ch.read_change = ch.write_change = ch.close_change = 0; if (events & EV_WRITE) ch.write_change = EV_CHANGE_ADD | (events & EV_ET); if (events & EV_READ) ch.read_change = EV_CHANGE_ADD | (events & EV_ET); if (events & EV_CLOSED) ch.close_change = EV_CHANGE_ADD | (events & EV_ET); return epoll_apply_one_change(base, base->evbase, &ch); } static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd, short old, short events, void *p) { struct event_change ch; ch.fd = fd; ch.old_events = old; ch.read_change = ch.write_change = ch.close_change = 0; if (events & EV_WRITE) ch.write_change = EV_CHANGE_DEL | (events & EV_ET); if (events & EV_READ) ch.read_change = EV_CHANGE_DEL | (events & EV_ET); if (events & EV_CLOSED) ch.close_change = EV_CHANGE_DEL | (events & EV_ET); return epoll_apply_one_change(base, base->evbase, &ch); } static int epoll_dispatch(struct event_base *base, struct timeval *tv) { struct epollop *epollop = base->evbase; struct epoll_event *events = epollop->events; int i, res; long timeout = -1; #ifdef USING_TIMERFD if (epollop->timerfd >= 0) { struct itimerspec is; is.it_interval.tv_sec = 0; is.it_interval.tv_nsec = 0; if (tv == NULL) { /* No timeout; disarm the timer. */ is.it_value.tv_sec = 0; is.it_value.tv_nsec = 0; } else { if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* we need to exit immediately; timerfd can't * do that. */ timeout = 0; } is.it_value.tv_sec = tv->tv_sec; is.it_value.tv_nsec = tv->tv_usec * 1000; } /* TODO: we could avoid unnecessary syscalls here by only calling timerfd_settime when the top timeout changes, or when we're called with a different timeval. */ if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) { event_warn("timerfd_settime"); } } else #endif if (tv != NULL) { timeout = evutil_tv_to_msec_(tv); if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) { /* Linux kernels can wait forever if the timeout is * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */ timeout = MAX_EPOLL_TIMEOUT_MSEC; } } epoll_apply_changes(base); event_changelist_remove_all_(&base->changelist, base); EVBASE_RELEASE_LOCK(base, th_base_lock); res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); EVBASE_ACQUIRE_LOCK(base, th_base_lock); if (res == -1) { if (errno != EINTR) { event_warn("epoll_wait"); return (-1); } return (0); } event_debug(("%s: epoll_wait reports %d", __func__, res)); EVUTIL_ASSERT(res <= epollop->nevents); for (i = 0; i < res; i++) { int what = events[i].events; short ev = 0; #ifdef USING_TIMERFD if (events[i].data.fd == epollop->timerfd) continue; #endif if (what & EPOLLERR) { ev = EV_READ | EV_WRITE; } else if ((what & EPOLLHUP) && !(what & EPOLLRDHUP)) { ev = EV_READ | EV_WRITE; } else { if (what & EPOLLIN) ev |= EV_READ; if (what & EPOLLOUT) ev |= EV_WRITE; if (what & EPOLLRDHUP) ev |= EV_CLOSED; } if (!ev) continue; evmap_io_active_(base, events[i].data.fd, ev | EV_ET); } if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) { /* We used all of the event space this time. We should be ready for more events next time. */ int new_nevents = epollop->nevents * 2; struct epoll_event *new_events; new_events = mm_realloc(epollop->events, new_nevents * sizeof(struct epoll_event)); if (new_events) { epollop->events = new_events; epollop->nevents = new_nevents; } } return (0); } static void epoll_dealloc(struct event_base *base) { struct epollop *epollop = base->evbase; evsig_dealloc_(base); if (epollop->events) mm_free(epollop->events); if (epollop->epfd >= 0) close(epollop->epfd); #ifdef USING_TIMERFD if (epollop->timerfd >= 0) close(epollop->timerfd); #endif memset(epollop, 0, sizeof(struct epollop)); mm_free(epollop); } #endif /* EVENT__HAVE_EPOLL */ lldpd-1.0.13/libevent/util-internal.h0000644000076400001440000004244614111362570020153 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTIL_INTERNAL_H_INCLUDED_ #define UTIL_INTERNAL_H_INCLUDED_ #include "event2/event-config.h" #include "evconfig-private.h" #include /* For EVUTIL_ASSERT */ #include "log-internal.h" #include #include #ifdef EVENT__HAVE_SYS_SOCKET_H #include #endif #ifdef EVENT__HAVE_SYS_EVENTFD_H #include #endif #include "event2/util.h" #include "time-internal.h" #include "ipv6-internal.h" #ifdef __cplusplus extern "C" { #endif /* __has_attribute() wrapper */ #ifdef __has_attribute # define EVUTIL_HAS_ATTRIBUTE __has_attribute #endif /** clang 3 __has_attribute misbehaves in some versions */ #if defined(__clang__) && __clang__ == 1 # if defined(__apple_build_version__) # if __clang_major__ <= 6 # undef EVUTIL_HAS_ATTRIBUTE # endif # else /* !__apple_build_version__ */ # if __clang_major__ == 3 && __clang_minor__ >= 2 && __clang_minor__ <= 5 # undef EVUTIL_HAS_ATTRIBUTE # endif # endif /* __apple_build_version__ */ #endif /*\ defined(__clang__) && __clang__ == 1 */ #ifndef EVUTIL_HAS_ATTRIBUTE # define EVUTIL_HAS_ATTRIBUTE(x) 0 #endif /* If we need magic to say "inline", get it for free internally. */ #ifdef EVENT__inline #define inline EVENT__inline #endif /* Define to appropriate substitute if compiler doesnt have __func__ */ #if defined(EVENT__HAVE___func__) # ifndef __func__ # define __func__ __func__ # endif #elif defined(EVENT__HAVE___FUNCTION__) # define __func__ __FUNCTION__ #else # define __func__ __FILE__ #endif /* A good no-op to use in macro definitions. */ #define EVUTIL_NIL_STMT_ ((void)0) /* A no-op that tricks the compiler into thinking a condition is used while * definitely not making any code for it. Used to compile out asserts while * avoiding "unused variable" warnings. The "!" forces the compiler to * do the sizeof() on an int, in case "condition" is a bitfield value. */ #define EVUTIL_NIL_CONDITION_(condition) do { \ (void)sizeof(!(condition)); \ } while(0) /* Internal use only: macros to match patterns of error codes in a cross-platform way. We need these macros because of two historical reasons: first, nonblocking IO functions are generally written to give an error on the "blocked now, try later" case, so sometimes an error from a read, write, connect, or accept means "no error; just wait for more data," and we need to look at the error code. Second, Windows defines a different set of error codes for sockets. */ #ifndef _WIN32 #if EAGAIN == EWOULDBLOCK #define EVUTIL_ERR_IS_EAGAIN(e) \ ((e) == EAGAIN) #else #define EVUTIL_ERR_IS_EAGAIN(e) \ ((e) == EAGAIN || (e) == EWOULDBLOCK) #endif /* True iff e is an error that means a read/write operation can be retried. */ #define EVUTIL_ERR_RW_RETRIABLE(e) \ ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e)) /* True iff e is an error that means an connect can be retried. */ #define EVUTIL_ERR_CONNECT_RETRIABLE(e) \ ((e) == EINTR || (e) == EINPROGRESS) /* True iff e is an error that means a accept can be retried. */ #define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \ ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e) || (e) == ECONNABORTED) /* True iff e is an error that means the connection was refused */ #define EVUTIL_ERR_CONNECT_REFUSED(e) \ ((e) == ECONNREFUSED) #else /* Win32 */ #define EVUTIL_ERR_IS_EAGAIN(e) \ ((e) == WSAEWOULDBLOCK || (e) == EAGAIN) #define EVUTIL_ERR_RW_RETRIABLE(e) \ ((e) == WSAEWOULDBLOCK || \ (e) == WSAEINTR) #define EVUTIL_ERR_CONNECT_RETRIABLE(e) \ ((e) == WSAEWOULDBLOCK || \ (e) == WSAEINTR || \ (e) == WSAEINPROGRESS || \ (e) == WSAEINVAL) #define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \ EVUTIL_ERR_RW_RETRIABLE(e) #define EVUTIL_ERR_CONNECT_REFUSED(e) \ ((e) == WSAECONNREFUSED) #endif /* Arguments for shutdown() */ #ifdef SHUT_RD #define EVUTIL_SHUT_RD SHUT_RD #else #define EVUTIL_SHUT_RD 0 #endif #ifdef SHUT_WR #define EVUTIL_SHUT_WR SHUT_WR #else #define EVUTIL_SHUT_WR 1 /* SD_SEND */ #endif #ifdef SHUT_BOTH #define EVUTIL_SHUT_BOTH SHUT_BOTH #else #define EVUTIL_SHUT_BOTH 2 #endif /* Helper: Verify that all the elements in 'dlist' are internally consistent. * Checks for circular lists and bad prev/next pointers. * * Example usage: * EVUTIL_ASSERT_LIST_OK(eventlist, event, ev_next); */ #define EVUTIL_ASSERT_LIST_OK(dlist, type, field) do { \ struct type *elm1, *elm2, **nextp; \ if (LIST_EMPTY((dlist))) \ break; \ \ /* Check list for circularity using Floyd's */ \ /* 'Tortoise and Hare' algorithm */ \ elm1 = LIST_FIRST((dlist)); \ elm2 = LIST_NEXT(elm1, field); \ while (elm1 && elm2) { \ EVUTIL_ASSERT(elm1 != elm2); \ elm1 = LIST_NEXT(elm1, field); \ elm2 = LIST_NEXT(elm2, field); \ if (!elm2) \ break; \ EVUTIL_ASSERT(elm1 != elm2); \ elm2 = LIST_NEXT(elm2, field); \ } \ \ /* Now check next and prev pointers for consistency. */ \ nextp = &LIST_FIRST((dlist)); \ elm1 = LIST_FIRST((dlist)); \ while (elm1) { \ EVUTIL_ASSERT(*nextp == elm1); \ EVUTIL_ASSERT(nextp == elm1->field.le_prev); \ nextp = &LIST_NEXT(elm1, field); \ elm1 = *nextp; \ } \ } while (0) /* Helper: Verify that all the elements in a TAILQ are internally consistent. * Checks for circular lists and bad prev/next pointers. * * Example usage: * EVUTIL_ASSERT_TAILQ_OK(activelist, event, ev_active_next); */ #define EVUTIL_ASSERT_TAILQ_OK(tailq, type, field) do { \ struct type *elm1, *elm2, **nextp; \ if (TAILQ_EMPTY((tailq))) \ break; \ \ /* Check list for circularity using Floyd's */ \ /* 'Tortoise and Hare' algorithm */ \ elm1 = TAILQ_FIRST((tailq)); \ elm2 = TAILQ_NEXT(elm1, field); \ while (elm1 && elm2) { \ EVUTIL_ASSERT(elm1 != elm2); \ elm1 = TAILQ_NEXT(elm1, field); \ elm2 = TAILQ_NEXT(elm2, field); \ if (!elm2) \ break; \ EVUTIL_ASSERT(elm1 != elm2); \ elm2 = TAILQ_NEXT(elm2, field); \ } \ \ /* Now check next and prev pointers for consistency. */ \ nextp = &TAILQ_FIRST((tailq)); \ elm1 = TAILQ_FIRST((tailq)); \ while (elm1) { \ EVUTIL_ASSERT(*nextp == elm1); \ EVUTIL_ASSERT(nextp == elm1->field.tqe_prev); \ nextp = &TAILQ_NEXT(elm1, field); \ elm1 = *nextp; \ } \ EVUTIL_ASSERT(nextp == (tailq)->tqh_last); \ } while (0) /* Locale-independent replacements for some ctypes functions. Use these * when you care about ASCII's notion of character types, because you are about * to send those types onto the wire. */ EVENT2_EXPORT_SYMBOL int EVUTIL_ISALPHA_(char c); EVENT2_EXPORT_SYMBOL int EVUTIL_ISALNUM_(char c); int EVUTIL_ISSPACE_(char c); EVENT2_EXPORT_SYMBOL int EVUTIL_ISDIGIT_(char c); EVENT2_EXPORT_SYMBOL int EVUTIL_ISXDIGIT_(char c); int EVUTIL_ISPRINT_(char c); int EVUTIL_ISLOWER_(char c); int EVUTIL_ISUPPER_(char c); EVENT2_EXPORT_SYMBOL char EVUTIL_TOUPPER_(char c); EVENT2_EXPORT_SYMBOL char EVUTIL_TOLOWER_(char c); /** Remove all trailing horizontal whitespace (space or tab) from the end of a * string */ EVENT2_EXPORT_SYMBOL void evutil_rtrim_lws_(char *); /** Helper macro. If we know that a given pointer points to a field in a structure, return a pointer to the structure itself. Used to implement our half-baked C OO. Example: struct subtype { int x; struct supertype common; int y; }; ... void fn(struct supertype *super) { struct subtype *sub = EVUTIL_UPCAST(super, struct subtype, common); ... } */ #define EVUTIL_UPCAST(ptr, type, field) \ ((type *)(((char*)(ptr)) - evutil_offsetof(type, field))) /* As open(pathname, flags, mode), except that the file is always opened with * the close-on-exec flag set. (And the mode argument is mandatory.) */ int evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode); EVENT2_EXPORT_SYMBOL int evutil_read_file_(const char *filename, char **content_out, size_t *len_out, int is_binary); EVENT2_EXPORT_SYMBOL int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen); int evutil_socket_finished_connecting_(evutil_socket_t fd); EVENT2_EXPORT_SYMBOL int evutil_ersatz_socketpair_(int, int , int, evutil_socket_t[]); int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa, ev_socklen_t *socklen, int port); const char *evutil_getenv_(const char *name); /* Structure to hold the state of our weak random number generator. */ struct evutil_weakrand_state { ev_uint32_t seed; }; #define EVUTIL_WEAKRAND_MAX EV_INT32_MAX /* Initialize the state of a week random number generator based on 'seed'. If * the seed is 0, construct a new seed based on not-very-strong platform * entropy, like the PID and the time of day. * * This function, and the other evutil_weakrand* functions, are meant for * speed, not security or statistical strength. If you need a RNG which an * attacker can't predict, or which passes strong statistical tests, use the * evutil_secure_rng* functions instead. */ EVENT2_EXPORT_SYMBOL ev_uint32_t evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed); /* Return a pseudorandom value between 0 and EVUTIL_WEAKRAND_MAX inclusive. * Updates the state in 'seed' as needed -- this value must be protected by a * lock. */ EVENT2_EXPORT_SYMBOL ev_int32_t evutil_weakrand_(struct evutil_weakrand_state *seed); /* Return a pseudorandom value x such that 0 <= x < top. top must be no more * than EVUTIL_WEAKRAND_MAX. Updates the state in 'seed' as needed -- this * value must be proteced by a lock */ EVENT2_EXPORT_SYMBOL ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t top); /* Evaluates to the same boolean value as 'p', and hints to the compiler that * we expect this value to be false. */ #if defined(__GNUC__) && __GNUC__ >= 3 /* gcc 3.0 or later */ #define EVUTIL_UNLIKELY(p) __builtin_expect(!!(p),0) #else #define EVUTIL_UNLIKELY(p) (p) #endif #if EVUTIL_HAS_ATTRIBUTE(fallthrough) #define EVUTIL_FALLTHROUGH __attribute__((fallthrough)) #else #define EVUTIL_FALLTHROUGH /* fallthrough */ #endif /* Replacement for assert() that calls event_errx on failure. */ #ifdef NDEBUG #define EVUTIL_ASSERT(cond) EVUTIL_NIL_CONDITION_(cond) #define EVUTIL_FAILURE_CHECK(cond) 0 #else #define EVUTIL_ASSERT(cond) \ do { \ if (EVUTIL_UNLIKELY(!(cond))) { \ event_errx(EVENT_ERR_ABORT_, \ "%s:%d: Assertion %s failed in %s", \ __FILE__,__LINE__,#cond,__func__); \ /* In case a user-supplied handler tries to */ \ /* return control to us, log and abort here. */ \ (void)fprintf(stderr, \ "%s:%d: Assertion %s failed in %s", \ __FILE__,__LINE__,#cond,__func__); \ abort(); \ } \ } while (0) #define EVUTIL_FAILURE_CHECK(cond) EVUTIL_UNLIKELY(cond) #endif #ifndef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE /* Replacement for sockaddr storage that we can use internally on platforms * that lack it. It is not space-efficient, but neither is sockaddr_storage. */ struct sockaddr_storage { union { struct sockaddr ss_sa; struct sockaddr_in ss_sin; struct sockaddr_in6 ss_sin6; char ss_padding[128]; } ss_union; }; #define ss_family ss_union.ss_sa.sa_family #endif /* Internal addrinfo error code. This one is returned from only from * evutil_getaddrinfo_common_, when we are sure that we'll have to hit a DNS * server. */ #define EVUTIL_EAI_NEED_RESOLVE -90002 struct evdns_base; struct evdns_getaddrinfo_request; typedef struct evdns_getaddrinfo_request* (*evdns_getaddrinfo_fn)( struct evdns_base *base, const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, void (*cb)(int, struct evutil_addrinfo *, void *), void *arg); EVENT2_EXPORT_SYMBOL void evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn); typedef void (*evdns_getaddrinfo_cancel_fn)( struct evdns_getaddrinfo_request *req); EVENT2_EXPORT_SYMBOL void evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel_fn fn); EVENT2_EXPORT_SYMBOL struct evutil_addrinfo *evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen, const struct evutil_addrinfo *hints); EVENT2_EXPORT_SYMBOL struct evutil_addrinfo *evutil_addrinfo_append_(struct evutil_addrinfo *first, struct evutil_addrinfo *append); EVENT2_EXPORT_SYMBOL void evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints); EVENT2_EXPORT_SYMBOL int evutil_getaddrinfo_common_(const char *nodename, const char *servname, struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum); struct evdns_getaddrinfo_request *evutil_getaddrinfo_async_( struct evdns_base *dns_base, const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, void (*cb)(int, struct evutil_addrinfo *, void *), void *arg); void evutil_getaddrinfo_cancel_async_(struct evdns_getaddrinfo_request *data); /** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or * ::1). */ EVENT2_EXPORT_SYMBOL int evutil_sockaddr_is_loopback_(const struct sockaddr *sa); /** Formats a sockaddr sa into a string buffer of size outlen stored in out. Returns a pointer to out. Always writes something into out, so it's safe to use the output of this function without checking it for NULL. */ EVENT2_EXPORT_SYMBOL const char *evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen); int evutil_hex_char_to_int_(char c); void evutil_free_secure_rng_globals_(void); void evutil_free_globals_(void); #ifdef _WIN32 EVENT2_EXPORT_SYMBOL HMODULE evutil_load_windows_system_library_(const TCHAR *library_name); #endif #ifndef EV_SIZE_FMT #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) #define EV_U64_FMT "%I64u" #define EV_I64_FMT "%I64d" #define EV_I64_ARG(x) ((__int64)(x)) #define EV_U64_ARG(x) ((unsigned __int64)(x)) #else #define EV_U64_FMT "%llu" #define EV_I64_FMT "%lld" #define EV_I64_ARG(x) ((long long)(x)) #define EV_U64_ARG(x) ((unsigned long long)(x)) #endif #endif #ifdef _WIN32 #define EV_SOCK_FMT EV_I64_FMT #define EV_SOCK_ARG(x) EV_I64_ARG((x)) #else #define EV_SOCK_FMT "%d" #define EV_SOCK_ARG(x) (x) #endif #if defined(__STDC__) && defined(__STDC_VERSION__) && !defined(__MINGW64_VERSION_MAJOR) #if (__STDC_VERSION__ >= 199901L) #define EV_SIZE_FMT "%zu" #define EV_SSIZE_FMT "%zd" #define EV_SIZE_ARG(x) (x) #define EV_SSIZE_ARG(x) (x) #endif #endif #ifndef EV_SIZE_FMT #if (EVENT__SIZEOF_SIZE_T <= EVENT__SIZEOF_LONG) #define EV_SIZE_FMT "%lu" #define EV_SSIZE_FMT "%ld" #define EV_SIZE_ARG(x) ((unsigned long)(x)) #define EV_SSIZE_ARG(x) ((long)(x)) #else #define EV_SIZE_FMT EV_U64_FMT #define EV_SSIZE_FMT EV_I64_FMT #define EV_SIZE_ARG(x) EV_U64_ARG(x) #define EV_SSIZE_ARG(x) EV_I64_ARG(x) #endif #endif EVENT2_EXPORT_SYMBOL evutil_socket_t evutil_socket_(int domain, int type, int protocol); evutil_socket_t evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr, ev_socklen_t *addrlen, int flags); /* used by one of the test programs.. */ EVENT2_EXPORT_SYMBOL int evutil_make_internal_pipe_(evutil_socket_t fd[2]); evutil_socket_t evutil_eventfd_(unsigned initval, int flags); #ifdef SOCK_NONBLOCK #define EVUTIL_SOCK_NONBLOCK SOCK_NONBLOCK #else #define EVUTIL_SOCK_NONBLOCK 0x4000000 #endif #ifdef SOCK_CLOEXEC #define EVUTIL_SOCK_CLOEXEC SOCK_CLOEXEC #else #define EVUTIL_SOCK_CLOEXEC 0x80000000 #endif #ifdef EFD_NONBLOCK #define EVUTIL_EFD_NONBLOCK EFD_NONBLOCK #else #define EVUTIL_EFD_NONBLOCK 0x4000 #endif #ifdef EFD_CLOEXEC #define EVUTIL_EFD_CLOEXEC EFD_CLOEXEC #else #define EVUTIL_EFD_CLOEXEC 0x8000 #endif void evutil_memclear_(void *mem, size_t len); struct in_addr; struct in6_addr; /* This is a any, loopback, link-local, multicast */ EVENT2_EXPORT_SYMBOL int evutil_v4addr_is_local_(const struct in_addr *in); /* This is a reserved, ipv4compat, ipv4map, loopback, * link-local, multicast, or unspecified address. */ EVENT2_EXPORT_SYMBOL int evutil_v6addr_is_local_(const struct in6_addr *in); #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/libevent_extra.pc.in0000644000076400001440000000043414111362570021146 0ustar00bernatusers00000000000000#libevent pkg-config source file prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libevent_extra Description: libevent_extra Version: @VERSION@ Requires: Conflicts: Libs: -L${libdir} -levent_extra Libs.private: @LIBS@ Cflags: -I${includedir} lldpd-1.0.13/libevent/arc4random.c0000644000076400001440000003051514111362570017403 0ustar00bernatusers00000000000000/* Portable arc4random.c based on arc4random.c from OpenBSD. * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson * * Note that in Libevent, this file isn't compiled directly. Instead, * it's included from evutil_rand.c */ /* * Copyright (c) 1996, David Mazieres * Copyright (c) 2008, Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Arc4 random number generator for OpenBSD. * * This code is derived from section 17.1 of Applied Cryptography, * second edition, which describes a stream cipher allegedly * compatible with RSA Labs "RC4" cipher (the actual description of * which is a trade secret). The same algorithm is used as a stream * cipher called "arcfour" in Tatu Ylonen's ssh package. * * Here the stream cipher has been modified always to include the time * when initializing the state. That makes it impossible to * regenerate the same random sequence twice, so this can't be used * for encryption, but will generate good random numbers. * * RC4 is a registered trademark of RSA Laboratories. */ #ifndef ARC4RANDOM_EXPORT #define ARC4RANDOM_EXPORT #endif #ifndef ARC4RANDOM_UINT32 #define ARC4RANDOM_UINT32 uint32_t #endif #ifndef ARC4RANDOM_NO_INCLUDES #include "evconfig-private.h" #ifdef _WIN32 #include #include #include #else #include #include #include #include #ifdef EVENT__HAVE_SYS_SYSCTL_H #include #endif #ifdef EVENT__HAVE_SYS_RANDOM_H #include #endif #endif #include #include #include #endif /* Add platform entropy 32 bytes (256 bits) at a time. */ #define ADD_ENTROPY 32 /* Re-seed from the platform RNG after generating this many bytes. */ #define BYTES_BEFORE_RESEED 1600000 struct arc4_stream { unsigned char i; unsigned char j; unsigned char s[256]; }; #ifdef _WIN32 #define getpid _getpid #define pid_t int #endif static int rs_initialized; static struct arc4_stream rs; static pid_t arc4_stir_pid; static int arc4_count; static inline unsigned char arc4_getbyte(void); static inline void arc4_init(void) { int n; for (n = 0; n < 256; n++) rs.s[n] = n; rs.i = 0; rs.j = 0; } static inline void arc4_addrandom(const unsigned char *dat, int datlen) { int n; unsigned char si; rs.i--; for (n = 0; n < 256; n++) { rs.i = (rs.i + 1); si = rs.s[rs.i]; rs.j = (rs.j + si + dat[n % datlen]); rs.s[rs.i] = rs.s[rs.j]; rs.s[rs.j] = si; } rs.j = rs.i; } #ifndef _WIN32 static ssize_t read_all(int fd, unsigned char *buf, size_t count) { size_t numread = 0; ssize_t result; while (numread < count) { result = read(fd, buf+numread, count-numread); if (result<0) return -1; else if (result == 0) break; numread += result; } return (ssize_t)numread; } #endif #ifdef _WIN32 #define TRY_SEED_WIN32 static int arc4_seed_win32(void) { /* This is adapted from Tor's crypto_seed_rng() */ static int provider_set = 0; static HCRYPTPROV provider; unsigned char buf[ADD_ENTROPY]; if (!provider_set) { if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { if (GetLastError() != (DWORD)NTE_BAD_KEYSET) return -1; } provider_set = 1; } if (!CryptGenRandom(provider, sizeof(buf), buf)) return -1; arc4_addrandom(buf, sizeof(buf)); evutil_memclear_(buf, sizeof(buf)); return 0; } #endif #if defined(EVENT__HAVE_GETRANDOM) #define TRY_SEED_GETRANDOM static int arc4_seed_getrandom(void) { unsigned char buf[ADD_ENTROPY]; size_t len, n; unsigned i; int any_set; memset(buf, 0, sizeof(buf)); for (len = 0; len < sizeof(buf); len += n) { n = sizeof(buf) - len; if (0 == getrandom(&buf[len], n, 0)) return -1; } /* make sure that the buffer actually got set. */ for (i=0,any_set=0; i sizeof(buf)) n = len - sizeof(buf); if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1) return -1; } } /* make sure that the buffer actually got set. */ for (i=any_set=0; i 0xffffffffUL) min = 0x100000000UL % upper_bound; #else /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ if (upper_bound > 0x80000000) min = 1 + ~upper_bound; /* 2**32 - upper_bound */ else { /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; } #endif /* * This could theoretically loop forever but each retry has * p > 0.5 (worst case, usually far better) of selecting a * number inside the range we need, so it should rarely need * to re-roll. */ for (;;) { r = arc4random(); if (r >= min) break; } return r % upper_bound; } #endif lldpd-1.0.13/libevent/Makefile.in0000644000076400001440000052176714143730642017274 0ustar00bernatusers00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. # include/include.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. # sample/include.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. # test/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. # Doxygen documentation will not be generated with default configuration, # unless '--enable-doxygen-doc' is configured. # The following targets are all about doxygen: # make # 'make doxygen' would be auto executed # make doxygen # generating doxygen documentation # make doxygen-doc # same as 'make doxygen' # make clean # clean docs generated by doxygen # make install # install doxygen documentation # make uninstall # uninstall doxygen documentation VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @PTHREADS_TRUE@am__append_1 = libevent_pthreads.la @PTHREADS_TRUE@am__append_2 = libevent_pthreads.pc @OPENSSL_TRUE@am__append_3 = libevent_openssl.la @OPENSSL_TRUE@am__append_4 = libevent_openssl.pc noinst_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_6) EXTRA_PROGRAMS = $(am__EXEEXT_1) @OPENSSL_TRUE@am__append_5 = include/event2/bufferevent_ssl.h @INSTALL_LIBEVENT_FALSE@am__append_6 = $(EVENT2_EXPORT) @OPENSSL_TRUE@am__append_7 = sample/le-proxy sample/https-client @BUILD_WIN32_TRUE@@OPENSSL_TRUE@am__append_8 = -lcrypt32 @OPENSSL_TRUE@am__append_9 = \ @OPENSSL_TRUE@ sample/hostcheck.h \ @OPENSSL_TRUE@ sample/openssl_hostname_validation.h @BUILD_SAMPLES_TRUE@am__append_10 = $(SAMPLES) @BUILD_REGRESS_TRUE@am__append_11 = $(TESTPROGRAMS) @BUILD_REGRESS_TRUE@am__append_12 = test/regress @BUILD_REGRESS_TRUE@am__append_13 = test/regress.gen.c test/regress.gen.h @PTHREADS_TRUE@am__append_14 = libevent_pthreads.la @BUILD_WIN32_TRUE@am__append_15 = test/regress_iocp.c @OPENSSL_TRUE@am__append_16 = test/regress_ssl.c @OPENSSL_TRUE@am__append_17 = $(OPENSSL_INCS) @OPENSSL_TRUE@am__append_18 = libevent_openssl.la $(OPENSSL_LIBS) ${OPENSSL_LIBADD} @BUILD_WIN32_TRUE@@THREADS_TRUE@am__append_19 = evthread_win32.c @STRLCPY_IMPL_TRUE@am__append_20 = strlcpy.c @SELECT_BACKEND_TRUE@am__append_21 = select.c @POLL_BACKEND_TRUE@am__append_22 = poll.c @DEVPOLL_BACKEND_TRUE@am__append_23 = devpoll.c @KQUEUE_BACKEND_TRUE@am__append_24 = kqueue.c @EPOLL_BACKEND_TRUE@am__append_25 = epoll.c @EVPORT_BACKEND_TRUE@am__append_26 = evport.c @SIGNAL_SUPPORT_TRUE@am__append_27 = signal.c @INSTALL_LIBEVENT_FALSE@am__append_28 = $(EVENT1_HDRS) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_backport_259_ssizet.m4 \ $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/ax_check_funcs_ex.m4 \ $(top_srcdir)/m4/ax_prog_doxygen.m4 \ $(top_srcdir)/m4/libevent_openssl.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/ntp_pkg_config.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__dist_bin_SCRIPTS_DIST) \ $(am__include_HEADERS_DIST) $(am__include_event2_HEADERS_DIST) \ $(am__noinst_HEADERS_DIST) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h evconfig-private.h CONFIG_CLEAN_FILES = libevent.pc libevent_openssl.pc \ libevent_pthreads.pc libevent_core.pc libevent_extra.pc CONFIG_CLEAN_VPATH_FILES = @BUILD_REGRESS_TRUE@am__EXEEXT_1 = test/regress$(EXEEXT) @OPENSSL_TRUE@am__EXEEXT_2 = sample/le-proxy$(EXEEXT) \ @OPENSSL_TRUE@ sample/https-client$(EXEEXT) am__EXEEXT_3 = sample/dns-example$(EXEEXT) \ sample/event-read-fifo$(EXEEXT) sample/hello-world$(EXEEXT) \ sample/http-server$(EXEEXT) sample/http-connect$(EXEEXT) \ sample/signal-test$(EXEEXT) sample/time-test$(EXEEXT) \ $(am__EXEEXT_2) @BUILD_SAMPLES_TRUE@am__EXEEXT_4 = $(am__EXEEXT_3) am__EXEEXT_5 = test/bench$(EXEEXT) test/bench_cascade$(EXEEXT) \ test/bench_http$(EXEEXT) test/bench_httpclient$(EXEEXT) \ test/test-changelist$(EXEEXT) test/test-dumpevents$(EXEEXT) \ test/test-eof$(EXEEXT) test/test-closed$(EXEEXT) \ test/test-fdleak$(EXEEXT) test/test-init$(EXEEXT) \ test/test-ratelim$(EXEEXT) test/test-time$(EXEEXT) \ test/test-weof$(EXEEXT) test/regress$(EXEEXT) @BUILD_REGRESS_TRUE@am__EXEEXT_6 = $(am__EXEEXT_5) PROGRAMS = $(noinst_PROGRAMS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(includedir)" "$(DESTDIR)$(include_event2dir)" \ "$(DESTDIR)$(include_event2dir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = libevent_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am__libevent_la_SOURCES_DIST = buffer.c bufferevent.c \ bufferevent_filter.c bufferevent_pair.c bufferevent_ratelim.c \ bufferevent_sock.c event.c evmap.c evthread.c evutil.c \ evutil_rand.c evutil_time.c listener.c log.c strlcpy.c \ select.c poll.c devpoll.c kqueue.c epoll.c evport.c signal.c \ win32select.c buffer_iocp.c event_iocp.c bufferevent_async.c \ evthread_win32.c evdns.c event_tagging.c evrpc.c http.c @STRLCPY_IMPL_TRUE@am__objects_1 = strlcpy.lo @SELECT_BACKEND_TRUE@am__objects_2 = select.lo @POLL_BACKEND_TRUE@am__objects_3 = poll.lo @DEVPOLL_BACKEND_TRUE@am__objects_4 = devpoll.lo @KQUEUE_BACKEND_TRUE@am__objects_5 = kqueue.lo @EPOLL_BACKEND_TRUE@am__objects_6 = epoll.lo @EVPORT_BACKEND_TRUE@am__objects_7 = evport.lo @SIGNAL_SUPPORT_TRUE@am__objects_8 = signal.lo @BUILD_WIN32_TRUE@@THREADS_TRUE@am__objects_9 = evthread_win32.lo @BUILD_WIN32_FALSE@am__objects_10 = $(am__objects_1) $(am__objects_2) \ @BUILD_WIN32_FALSE@ $(am__objects_3) $(am__objects_4) \ @BUILD_WIN32_FALSE@ $(am__objects_5) $(am__objects_6) \ @BUILD_WIN32_FALSE@ $(am__objects_7) $(am__objects_8) @BUILD_WIN32_TRUE@am__objects_10 = win32select.lo buffer_iocp.lo \ @BUILD_WIN32_TRUE@ event_iocp.lo bufferevent_async.lo \ @BUILD_WIN32_TRUE@ $(am__objects_9) $(am__objects_1) \ @BUILD_WIN32_TRUE@ $(am__objects_2) $(am__objects_3) \ @BUILD_WIN32_TRUE@ $(am__objects_4) $(am__objects_5) \ @BUILD_WIN32_TRUE@ $(am__objects_6) $(am__objects_7) \ @BUILD_WIN32_TRUE@ $(am__objects_8) am__objects_11 = buffer.lo bufferevent.lo bufferevent_filter.lo \ bufferevent_pair.lo bufferevent_ratelim.lo bufferevent_sock.lo \ event.lo evmap.lo evthread.lo evutil.lo evutil_rand.lo \ evutil_time.lo listener.lo log.lo $(am__objects_10) am__objects_12 = evdns.lo event_tagging.lo evrpc.lo http.lo am_libevent_la_OBJECTS = $(am__objects_11) $(am__objects_12) libevent_la_OBJECTS = $(am_libevent_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libevent_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libevent_la_LDFLAGS) $(LDFLAGS) -o $@ @INSTALL_LIBEVENT_FALSE@am_libevent_la_rpath = @INSTALL_LIBEVENT_TRUE@am_libevent_la_rpath = -rpath $(libdir) libevent_core_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am__libevent_core_la_SOURCES_DIST = buffer.c bufferevent.c \ bufferevent_filter.c bufferevent_pair.c bufferevent_ratelim.c \ bufferevent_sock.c event.c evmap.c evthread.c evutil.c \ evutil_rand.c evutil_time.c listener.c log.c strlcpy.c \ select.c poll.c devpoll.c kqueue.c epoll.c evport.c signal.c \ win32select.c buffer_iocp.c event_iocp.c bufferevent_async.c \ evthread_win32.c am_libevent_core_la_OBJECTS = $(am__objects_11) libevent_core_la_OBJECTS = $(am_libevent_core_la_OBJECTS) libevent_core_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libevent_core_la_LDFLAGS) $(LDFLAGS) \ -o $@ @INSTALL_LIBEVENT_FALSE@am_libevent_core_la_rpath = @INSTALL_LIBEVENT_TRUE@am_libevent_core_la_rpath = -rpath $(libdir) @BUILD_WITH_NO_UNDEFINED_TRUE@am__DEPENDENCIES_2 = libevent_core.la libevent_extra_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) am_libevent_extra_la_OBJECTS = $(am__objects_12) libevent_extra_la_OBJECTS = $(am_libevent_extra_la_OBJECTS) libevent_extra_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libevent_extra_la_LDFLAGS) $(LDFLAGS) \ -o $@ @INSTALL_LIBEVENT_FALSE@am_libevent_extra_la_rpath = @INSTALL_LIBEVENT_TRUE@am_libevent_extra_la_rpath = -rpath $(libdir) @OPENSSL_TRUE@libevent_openssl_la_DEPENDENCIES = \ @OPENSSL_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) am__libevent_openssl_la_SOURCES_DIST = bufferevent_openssl.c @OPENSSL_TRUE@am_libevent_openssl_la_OBJECTS = \ @OPENSSL_TRUE@ libevent_openssl_la-bufferevent_openssl.lo libevent_openssl_la_OBJECTS = $(am_libevent_openssl_la_OBJECTS) libevent_openssl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libevent_openssl_la_LDFLAGS) \ $(LDFLAGS) -o $@ @INSTALL_LIBEVENT_FALSE@@OPENSSL_TRUE@am_libevent_openssl_la_rpath = @INSTALL_LIBEVENT_TRUE@@OPENSSL_TRUE@am_libevent_openssl_la_rpath = \ @INSTALL_LIBEVENT_TRUE@@OPENSSL_TRUE@ -rpath $(libdir) @PTHREADS_TRUE@libevent_pthreads_la_DEPENDENCIES = \ @PTHREADS_TRUE@ $(am__DEPENDENCIES_2) am__libevent_pthreads_la_SOURCES_DIST = evthread_pthread.c @PTHREADS_TRUE@am_libevent_pthreads_la_OBJECTS = evthread_pthread.lo libevent_pthreads_la_OBJECTS = $(am_libevent_pthreads_la_OBJECTS) libevent_pthreads_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libevent_pthreads_la_LDFLAGS) \ $(LDFLAGS) -o $@ @INSTALL_LIBEVENT_FALSE@@PTHREADS_TRUE@am_libevent_pthreads_la_rpath = @INSTALL_LIBEVENT_TRUE@@PTHREADS_TRUE@am_libevent_pthreads_la_rpath = \ @INSTALL_LIBEVENT_TRUE@@PTHREADS_TRUE@ -rpath $(libdir) am__dirstamp = $(am__leading_dot)dirstamp am_sample_dns_example_OBJECTS = sample/dns-example.$(OBJEXT) sample_dns_example_OBJECTS = $(am_sample_dns_example_OBJECTS) sample_dns_example_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_sample_event_read_fifo_OBJECTS = sample/event-read-fifo.$(OBJEXT) sample_event_read_fifo_OBJECTS = $(am_sample_event_read_fifo_OBJECTS) sample_event_read_fifo_DEPENDENCIES = $(am__DEPENDENCIES_1) \ libevent.la am_sample_hello_world_OBJECTS = sample/hello-world.$(OBJEXT) sample_hello_world_OBJECTS = $(am_sample_hello_world_OBJECTS) sample_hello_world_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_sample_http_connect_OBJECTS = sample/http-connect.$(OBJEXT) sample_http_connect_OBJECTS = $(am_sample_http_connect_OBJECTS) sample_http_connect_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_sample_http_server_OBJECTS = sample/http-server.$(OBJEXT) sample_http_server_OBJECTS = $(am_sample_http_server_OBJECTS) sample_http_server_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am__sample_https_client_SOURCES_DIST = sample/https-client.c \ sample/hostcheck.c sample/openssl_hostname_validation.c @OPENSSL_TRUE@am_sample_https_client_OBJECTS = \ @OPENSSL_TRUE@ sample/https_client-https-client.$(OBJEXT) \ @OPENSSL_TRUE@ sample/https_client-hostcheck.$(OBJEXT) \ @OPENSSL_TRUE@ sample/https_client-openssl_hostname_validation.$(OBJEXT) sample_https_client_OBJECTS = $(am_sample_https_client_OBJECTS) @OPENSSL_TRUE@sample_https_client_DEPENDENCIES = libevent.la \ @OPENSSL_TRUE@ libevent_openssl.la $(am__DEPENDENCIES_1) \ @OPENSSL_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__sample_le_proxy_SOURCES_DIST = sample/le-proxy.c @OPENSSL_TRUE@am_sample_le_proxy_OBJECTS = \ @OPENSSL_TRUE@ sample/le_proxy-le-proxy.$(OBJEXT) sample_le_proxy_OBJECTS = $(am_sample_le_proxy_OBJECTS) @OPENSSL_TRUE@sample_le_proxy_DEPENDENCIES = libevent.la \ @OPENSSL_TRUE@ libevent_openssl.la $(am__DEPENDENCIES_1) \ @OPENSSL_TRUE@ $(am__DEPENDENCIES_1) am_sample_signal_test_OBJECTS = sample/signal-test.$(OBJEXT) sample_signal_test_OBJECTS = $(am_sample_signal_test_OBJECTS) sample_signal_test_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_sample_time_test_OBJECTS = sample/time-test.$(OBJEXT) sample_time_test_OBJECTS = $(am_sample_time_test_OBJECTS) sample_time_test_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_test_bench_OBJECTS = test/bench.$(OBJEXT) test_bench_OBJECTS = $(am_test_bench_OBJECTS) test_bench_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_test_bench_cascade_OBJECTS = test/bench_cascade.$(OBJEXT) test_bench_cascade_OBJECTS = $(am_test_bench_cascade_OBJECTS) test_bench_cascade_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_test_bench_http_OBJECTS = test/bench_http.$(OBJEXT) test_bench_http_OBJECTS = $(am_test_bench_http_OBJECTS) test_bench_http_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent.la am_test_bench_httpclient_OBJECTS = test/bench_httpclient.$(OBJEXT) test_bench_httpclient_OBJECTS = $(am_test_bench_httpclient_OBJECTS) test_bench_httpclient_DEPENDENCIES = $(am__DEPENDENCIES_1) \ libevent_core.la am__test_regress_SOURCES_DIST = test/regress.c test/regress.gen.c \ test/regress.gen.h test/regress_buffer.c \ test/regress_bufferevent.c test/regress_dns.c \ test/regress_et.c test/regress_finalize.c test/regress_http.c \ test/regress_listener.c test/regress_main.c \ test/regress_minheap.c test/regress_rpc.c \ test/regress_testutils.c test/regress_testutils.h \ test/regress_util.c test/tinytest.c test/regress_thread.c \ test/regress_zlib.c test/regress_iocp.c test/regress_ssl.c @BUILD_WIN32_FALSE@@PTHREADS_TRUE@am__objects_13 = test/regress-regress_thread.$(OBJEXT) @BUILD_WIN32_TRUE@@THREADS_TRUE@am__objects_13 = test/regress-regress_thread.$(OBJEXT) @PTHREADS_TRUE@@THREADS_FALSE@am__objects_13 = test/regress-regress_thread.$(OBJEXT) @ZLIB_REGRESS_TRUE@am__objects_14 = \ @ZLIB_REGRESS_TRUE@ test/regress-regress_zlib.$(OBJEXT) @BUILD_WIN32_TRUE@am__objects_15 = \ @BUILD_WIN32_TRUE@ test/regress-regress_iocp.$(OBJEXT) @OPENSSL_TRUE@am__objects_16 = test/regress-regress_ssl.$(OBJEXT) am_test_regress_OBJECTS = test/regress-regress.$(OBJEXT) \ test/regress-regress.gen.$(OBJEXT) \ test/regress-regress_buffer.$(OBJEXT) \ test/regress-regress_bufferevent.$(OBJEXT) \ test/regress-regress_dns.$(OBJEXT) \ test/regress-regress_et.$(OBJEXT) \ test/regress-regress_finalize.$(OBJEXT) \ test/regress-regress_http.$(OBJEXT) \ test/regress-regress_listener.$(OBJEXT) \ test/regress-regress_main.$(OBJEXT) \ test/regress-regress_minheap.$(OBJEXT) \ test/regress-regress_rpc.$(OBJEXT) \ test/regress-regress_testutils.$(OBJEXT) \ test/regress-regress_util.$(OBJEXT) \ test/regress-tinytest.$(OBJEXT) $(am__objects_13) \ $(am__objects_14) $(am__objects_15) $(am__objects_16) test_regress_OBJECTS = $(am_test_regress_OBJECTS) am__DEPENDENCIES_3 = $(am__append_14) @OPENSSL_TRUE@am__DEPENDENCIES_4 = libevent_openssl.la \ @OPENSSL_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) test_regress_DEPENDENCIES = $(am__DEPENDENCIES_1) libevent_core.la \ libevent_extra.la $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_4) test_regress_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(test_regress_LDFLAGS) $(LDFLAGS) -o $@ am_test_test_changelist_OBJECTS = test/test-changelist.$(OBJEXT) test_test_changelist_OBJECTS = $(am_test_test_changelist_OBJECTS) test_test_changelist_DEPENDENCIES = libevent_core.la am_test_test_closed_OBJECTS = test/test-closed.$(OBJEXT) test_test_closed_OBJECTS = $(am_test_test_closed_OBJECTS) test_test_closed_DEPENDENCIES = libevent_core.la am_test_test_dumpevents_OBJECTS = test/test-dumpevents.$(OBJEXT) test_test_dumpevents_OBJECTS = $(am_test_test_dumpevents_OBJECTS) test_test_dumpevents_DEPENDENCIES = libevent_core.la am_test_test_eof_OBJECTS = test/test-eof.$(OBJEXT) test_test_eof_OBJECTS = $(am_test_test_eof_OBJECTS) test_test_eof_DEPENDENCIES = libevent_core.la am_test_test_fdleak_OBJECTS = test/test-fdleak.$(OBJEXT) test_test_fdleak_OBJECTS = $(am_test_test_fdleak_OBJECTS) test_test_fdleak_DEPENDENCIES = libevent_core.la am_test_test_init_OBJECTS = test/test-init.$(OBJEXT) test_test_init_OBJECTS = $(am_test_test_init_OBJECTS) test_test_init_DEPENDENCIES = libevent_core.la am_test_test_ratelim_OBJECTS = test/test-ratelim.$(OBJEXT) test_test_ratelim_OBJECTS = $(am_test_test_ratelim_OBJECTS) test_test_ratelim_DEPENDENCIES = libevent_core.la am_test_test_time_OBJECTS = test/test-time.$(OBJEXT) test_test_time_OBJECTS = $(am_test_test_time_OBJECTS) test_test_time_DEPENDENCIES = libevent_core.la am_test_test_weof_OBJECTS = test/test-weof.$(OBJEXT) test_test_weof_OBJECTS = $(am_test_test_weof_OBJECTS) test_test_weof_DEPENDENCIES = libevent_core.la am__dist_bin_SCRIPTS_DIST = event_rpcgen.py SCRIPTS = $(dist_bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(DEPDIR)/epoll_sub.Plo ./$(DEPDIR)/buffer.Plo \ ./$(DEPDIR)/buffer_iocp.Plo ./$(DEPDIR)/bufferevent.Plo \ ./$(DEPDIR)/bufferevent_async.Plo \ ./$(DEPDIR)/bufferevent_filter.Plo \ ./$(DEPDIR)/bufferevent_pair.Plo \ ./$(DEPDIR)/bufferevent_ratelim.Plo \ ./$(DEPDIR)/bufferevent_sock.Plo ./$(DEPDIR)/devpoll.Plo \ ./$(DEPDIR)/epoll.Plo ./$(DEPDIR)/evdns.Plo \ ./$(DEPDIR)/event.Plo ./$(DEPDIR)/event_iocp.Plo \ ./$(DEPDIR)/event_tagging.Plo ./$(DEPDIR)/evmap.Plo \ ./$(DEPDIR)/evport.Plo ./$(DEPDIR)/evrpc.Plo \ ./$(DEPDIR)/evthread.Plo ./$(DEPDIR)/evthread_pthread.Plo \ ./$(DEPDIR)/evthread_win32.Plo ./$(DEPDIR)/evutil.Plo \ ./$(DEPDIR)/evutil_rand.Plo ./$(DEPDIR)/evutil_time.Plo \ ./$(DEPDIR)/http.Plo ./$(DEPDIR)/kqueue.Plo \ ./$(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Plo \ ./$(DEPDIR)/listener.Plo ./$(DEPDIR)/log.Plo \ ./$(DEPDIR)/poll.Plo ./$(DEPDIR)/select.Plo \ ./$(DEPDIR)/signal.Plo ./$(DEPDIR)/strlcpy.Plo \ ./$(DEPDIR)/win32select.Plo sample/$(DEPDIR)/dns-example.Po \ sample/$(DEPDIR)/event-read-fifo.Po \ sample/$(DEPDIR)/hello-world.Po \ sample/$(DEPDIR)/http-connect.Po \ sample/$(DEPDIR)/http-server.Po \ sample/$(DEPDIR)/https_client-hostcheck.Po \ sample/$(DEPDIR)/https_client-https-client.Po \ sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po \ sample/$(DEPDIR)/le_proxy-le-proxy.Po \ sample/$(DEPDIR)/signal-test.Po sample/$(DEPDIR)/time-test.Po \ test/$(DEPDIR)/bench.Po test/$(DEPDIR)/bench_cascade.Po \ test/$(DEPDIR)/bench_http.Po \ test/$(DEPDIR)/bench_httpclient.Po \ test/$(DEPDIR)/regress-regress.Po \ test/$(DEPDIR)/regress-regress.gen.Po \ test/$(DEPDIR)/regress-regress_buffer.Po \ test/$(DEPDIR)/regress-regress_bufferevent.Po \ test/$(DEPDIR)/regress-regress_dns.Po \ test/$(DEPDIR)/regress-regress_et.Po \ test/$(DEPDIR)/regress-regress_finalize.Po \ test/$(DEPDIR)/regress-regress_http.Po \ test/$(DEPDIR)/regress-regress_iocp.Po \ test/$(DEPDIR)/regress-regress_listener.Po \ test/$(DEPDIR)/regress-regress_main.Po \ test/$(DEPDIR)/regress-regress_minheap.Po \ test/$(DEPDIR)/regress-regress_rpc.Po \ test/$(DEPDIR)/regress-regress_ssl.Po \ test/$(DEPDIR)/regress-regress_testutils.Po \ test/$(DEPDIR)/regress-regress_thread.Po \ test/$(DEPDIR)/regress-regress_util.Po \ test/$(DEPDIR)/regress-regress_zlib.Po \ test/$(DEPDIR)/regress-tinytest.Po \ test/$(DEPDIR)/test-changelist.Po \ test/$(DEPDIR)/test-closed.Po \ test/$(DEPDIR)/test-dumpevents.Po test/$(DEPDIR)/test-eof.Po \ test/$(DEPDIR)/test-fdleak.Po test/$(DEPDIR)/test-init.Po \ test/$(DEPDIR)/test-ratelim.Po test/$(DEPDIR)/test-time.Po \ test/$(DEPDIR)/test-weof.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libevent_la_SOURCES) $(libevent_core_la_SOURCES) \ $(libevent_extra_la_SOURCES) $(libevent_openssl_la_SOURCES) \ $(libevent_pthreads_la_SOURCES) $(sample_dns_example_SOURCES) \ $(sample_event_read_fifo_SOURCES) \ $(sample_hello_world_SOURCES) $(sample_http_connect_SOURCES) \ $(sample_http_server_SOURCES) $(sample_https_client_SOURCES) \ $(sample_le_proxy_SOURCES) $(sample_signal_test_SOURCES) \ $(sample_time_test_SOURCES) $(test_bench_SOURCES) \ $(test_bench_cascade_SOURCES) $(test_bench_http_SOURCES) \ $(test_bench_httpclient_SOURCES) $(test_regress_SOURCES) \ $(test_test_changelist_SOURCES) $(test_test_closed_SOURCES) \ $(test_test_dumpevents_SOURCES) $(test_test_eof_SOURCES) \ $(test_test_fdleak_SOURCES) $(test_test_init_SOURCES) \ $(test_test_ratelim_SOURCES) $(test_test_time_SOURCES) \ $(test_test_weof_SOURCES) DIST_SOURCES = $(am__libevent_la_SOURCES_DIST) \ $(am__libevent_core_la_SOURCES_DIST) \ $(libevent_extra_la_SOURCES) \ $(am__libevent_openssl_la_SOURCES_DIST) \ $(am__libevent_pthreads_la_SOURCES_DIST) \ $(sample_dns_example_SOURCES) \ $(sample_event_read_fifo_SOURCES) \ $(sample_hello_world_SOURCES) $(sample_http_connect_SOURCES) \ $(sample_http_server_SOURCES) \ $(am__sample_https_client_SOURCES_DIST) \ $(am__sample_le_proxy_SOURCES_DIST) \ $(sample_signal_test_SOURCES) $(sample_time_test_SOURCES) \ $(test_bench_SOURCES) $(test_bench_cascade_SOURCES) \ $(test_bench_http_SOURCES) $(test_bench_httpclient_SOURCES) \ $(am__test_regress_SOURCES_DIST) \ $(test_test_changelist_SOURCES) $(test_test_closed_SOURCES) \ $(test_test_dumpevents_SOURCES) $(test_test_eof_SOURCES) \ $(test_test_fdleak_SOURCES) $(test_test_init_SOURCES) \ $(test_test_ratelim_SOURCES) $(test_test_time_SOURCES) \ $(test_test_weof_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man3_MANS) DATA = $(pkgconfig_DATA) am__include_HEADERS_DIST = include/evdns.h include/event.h \ include/evhttp.h include/evrpc.h include/evutil.h am__include_event2_HEADERS_DIST = include/event2/buffer.h \ include/event2/buffer_compat.h include/event2/bufferevent.h \ include/event2/bufferevent_compat.h \ include/event2/bufferevent_struct.h include/event2/dns.h \ include/event2/dns_compat.h include/event2/dns_struct.h \ include/event2/event.h include/event2/event_compat.h \ include/event2/event_struct.h include/event2/http.h \ include/event2/http_compat.h include/event2/http_struct.h \ include/event2/keyvalq_struct.h include/event2/listener.h \ include/event2/rpc.h include/event2/rpc_compat.h \ include/event2/rpc_struct.h include/event2/tag.h \ include/event2/tag_compat.h include/event2/thread.h \ include/event2/util.h include/event2/visibility.h \ include/event2/bufferevent_ssl.h am__noinst_HEADERS_DIST = include/event2/buffer.h \ include/event2/buffer_compat.h include/event2/bufferevent.h \ include/event2/bufferevent_compat.h \ include/event2/bufferevent_struct.h include/event2/dns.h \ include/event2/dns_compat.h include/event2/dns_struct.h \ include/event2/event.h include/event2/event_compat.h \ include/event2/event_struct.h include/event2/http.h \ include/event2/http_compat.h include/event2/http_struct.h \ include/event2/keyvalq_struct.h include/event2/listener.h \ include/event2/rpc.h include/event2/rpc_compat.h \ include/event2/rpc_struct.h include/event2/tag.h \ include/event2/tag_compat.h include/event2/thread.h \ include/event2/util.h include/event2/visibility.h \ include/event2/bufferevent_ssl.h sample/hostcheck.h \ sample/openssl_hostname_validation.h test/regress.h \ test/regress_thread.h test/tinytest.h test/tinytest_local.h \ test/tinytest_macros.h WIN32-Code/nmake/evconfig-private.h \ WIN32-Code/nmake/event2/event-config.h WIN32-Code/getopt.h \ WIN32-Code/getopt.c WIN32-Code/getopt_long.c WIN32-Code/tree.h \ bufferevent-internal.h changelist-internal.h \ compat/sys/queue.h defer-internal.h epolltable-internal.h \ evbuffer-internal.h event-internal.h evmap-internal.h \ evrpc-internal.h evsignal-internal.h evthread-internal.h \ ht-internal.h http-internal.h iocp-internal.h ipv6-internal.h \ kqueue-internal.h log-internal.h minheap-internal.h \ mm-internal.h ratelim-internal.h strlcpy-internal.h \ time-internal.h util-internal.h openssl-compat.h \ include/evdns.h include/event.h include/evhttp.h \ include/evrpc.h include/evutil.h HEADERS = $(include_HEADERS) $(include_event2_HEADERS) \ $(nodist_include_event2_HEADERS) $(nodist_noinst_HEADERS) \ $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ config.h.in evconfig-private.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope check recheck am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(srcdir)/doxygen.am $(srcdir)/evconfig-private.h.in \ $(srcdir)/include/include.am $(srcdir)/libevent.pc.in \ $(srcdir)/libevent_core.pc.in $(srcdir)/libevent_extra.pc.in \ $(srcdir)/libevent_openssl.pc.in \ $(srcdir)/libevent_pthreads.pc.in $(srcdir)/sample/include.am \ $(srcdir)/test/include.am $(top_srcdir)/build-aux/compile \ $(top_srcdir)/build-aux/config.guess \ $(top_srcdir)/build-aux/config.sub \ $(top_srcdir)/build-aux/depcomp \ $(top_srcdir)/build-aux/install-sh \ $(top_srcdir)/build-aux/ltmain.sh \ $(top_srcdir)/build-aux/missing \ $(top_srcdir)/build-aux/test-driver ChangeLog README.md \ build-aux/compile build-aux/config.guess build-aux/config.sub \ build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \ build-aux/missing epoll_sub.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DX_CONFIG = @DX_CONFIG@ DX_DOCDIR = @DX_DOCDIR@ DX_DOT = @DX_DOT@ DX_DOXYGEN = @DX_DOXYGEN@ DX_DVIPS = @DX_DVIPS@ DX_EGREP = @DX_EGREP@ DX_ENV = @DX_ENV@ DX_FLAG_chi = @DX_FLAG_chi@ DX_FLAG_chm = @DX_FLAG_chm@ DX_FLAG_doc = @DX_FLAG_doc@ DX_FLAG_dot = @DX_FLAG_dot@ DX_FLAG_html = @DX_FLAG_html@ DX_FLAG_man = @DX_FLAG_man@ DX_FLAG_pdf = @DX_FLAG_pdf@ DX_FLAG_ps = @DX_FLAG_ps@ DX_FLAG_rtf = @DX_FLAG_rtf@ DX_FLAG_xml = @DX_FLAG_xml@ DX_HHC = @DX_HHC@ DX_LATEX = @DX_LATEX@ DX_MAKEINDEX = @DX_MAKEINDEX@ DX_PDFLATEX = @DX_PDFLATEX@ DX_PERL = @DX_PERL@ DX_PROJECT = @DX_PROJECT@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EV_LIB_GDI = @EV_LIB_GDI@ EV_LIB_WS32 = @EV_LIB_WS32@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBEVENT_GC_SECTIONS = @LIBEVENT_GC_SECTIONS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_INCS = @OPENSSL_INCS@ OPENSSL_LIBADD = @OPENSSL_LIBADD@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ $(am__append_14) RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # 'foreign' means that we're not enforcing GNU package rules strictly. # '1.13' means that we need automake 1.13 or later (and we do). AUTOMAKE_OPTIONS = foreign 1.13 subdir-objects ACLOCAL_AMFLAGS = -I m4 # This is the "Release" of the Libevent ABI. It takes precedence over # the VERSION_INFO, so that two versions of Libevent with the same # "Release" are never binary-compatible. # # This number incremented once for the 2.0 release candidate, and # will increment for each series until we revise our interfaces enough # that we can seriously expect ABI compatibility between series. # RELEASE = -release 2.1 # This is the version info for the libevent binary API. It has three # numbers: # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary # API are we supplying? # Age -- How many previous binary API versions do we also # support? # # To increment a VERSION_INFO (current:revision:age): # If the ABI didn't change: # Return (current:revision+1:age) # If the ABI changed, but it's backward-compatible: # Return (current+1:0:age+1) # If the ABI changed and it isn't backward-compatible: # Return (current+1:0:0) # # Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES # UNLESS YOU REALLY REALLY HAVE TO. VERSION_INFO = 7:1:0 # History: RELEASE VERSION_INFO # 2.0.1-alpha -- 2.0 1:0:0 # 2.0.2-alpha -- 2:0:0 # 2.0.3-alpha -- 2:0:0 (should have incremented; didn't.) # 2.0.4-alpha -- 3:0:0 # 2.0.5-beta -- 4:0:0 # 2.0.6-rc -- 2.0 2:0:0 # 2.0.7-rc -- 2.0 3:0:1 # 2.0.8-rc -- 2.0 4:0:2 # 2.0.9-rc -- 2.0 5:0:0 (ABI changed slightly) # 2.0.10-stable-- 2.0 5:1:0 (No ABI change) # 2.0.11-stable-- 2.0 6:0:1 (ABI changed, backward-compatible) # 2.0.12-stable-- 2.0 6:1:1 (No ABI change) # 2.0.13-stable-- 2.0 6:2:1 (No ABI change) # 2.0.14-stable-- 2.0 6:3:1 (No ABI change) # 2.0.15-stable-- 2.0 6:3:1 (Forgot to update :( ) # 2.0.16-stable-- 2.0 6:4:1 (No ABI change) # 2.0.17-stable-- 2.0 6:5:1 (No ABI change) # 2.0.18-stable-- 2.0 6:6:1 (No ABI change) # 2.0.19-stable-- 2.0 6:7:1 (No ABI change) # 2.0.20-stable-- 2.0 6:8:1 (No ABI change) # 2.0.21-stable-- 2.0 6:9:1 (No ABI change) # # For Libevent 2.1: # 2.1.1-alpha -- 2.1 1:0:0 # 2.1.2-alpha -- 2.1 1:0:0 (should have been 2:0:1) # 2.1.3-alpha -- 2.1 3:0:0 (ABI changed slightly) # 2.1.4-alpha -- 2.1 4:0:0 (ABI changed slightly) # 2.1.5-beta -- 2.1 5:0:0 (ABI changed slightly) # 2.1.6-beta -- 2.1 6:0:0 (ABI changed slightly) # 2.1.7-beta -- 2.1 6:1:0 (ABI changed slightly) # 2.1.8-stable-- 2.1 6:2:0 (No ABI change) # 2.1.9-beta-- 2.1 6:3:0 (No ABI change) # 2.1.10-stable-- 2.1 6:4:0 (No ABI change, WRONG) # 2.1.11-stable-- 2.1 7:0:0 (ABI changed) # 2.1.12-stable-- 2.1 7:1:0 (No ABI change) # ABI version history for this package effectively restarts every time # we change RELEASE. Version 1.4.x had RELEASE of 1.4. # # Ideally, we would not be using RELEASE at all; instead we could just # use the VERSION_INFO field to label our backward-incompatible ABI # changes, and those would be few and far between. Unfortunately, # Libevent still exposes far too many volatile structures in its # headers, so we pretty much have to assume that most development # series will break ABI compatibility. For now, it's simplest just to # keep incrementing the RELEASE between series and resetting VERSION_INFO. # # Eventually, when we get to the point where the structures in the # headers are all non-changing (or not there at all!), we can shift to # a more normal worldview where backward-incompatible ABI changes are # nice and rare. For the next couple of years, though, 'struct event' # is user-visible, and so we can pretty much guarantee that release # series won't be binary-compatible. @INSTALL_LIBEVENT_TRUE@dist_bin_SCRIPTS = event_rpcgen.py pkgconfigdir = $(libdir)/pkgconfig LIBEVENT_PKGCONFIG = libevent.pc libevent_core.pc libevent_extra.pc \ $(am__append_2) $(am__append_4) # These sources are conditionally added by configure.ac or conditionally # included from other files. PLATFORM_DEPENDENT_SRC = \ arc4random.c \ epoll_sub.c CMAKE_FILES = \ cmake/AddCompilerFlags.cmake \ cmake/AddEventLibrary.cmake \ cmake/CheckConstExists.cmake \ cmake/CheckFileOffsetBits.c \ cmake/CheckFileOffsetBits.cmake \ cmake/CheckFunctionKeywords.cmake \ cmake/CheckPrototypeDefinition.c.in \ cmake/CheckPrototypeDefinition.cmake \ cmake/CheckWorkingKqueue.cmake \ cmake/CodeCoverage.cmake \ cmake/COPYING-CMAKE-SCRIPTS \ cmake/Copyright.txt \ cmake/LibeventConfig.cmake.in \ cmake/LibeventConfigVersion.cmake.in \ cmake/Macros.cmake \ cmake/Uninstall.cmake.in \ cmake/UseDoxygen.cmake \ cmake/VersionViaGit.cmake \ event-config.h.cmake \ evconfig-private.h.cmake \ CMakeLists.txt EXTRA_DIST = ChangeLog-1.4 ChangeLog-2.0 Doxyfile LICENSE \ Makefile.nmake test/Makefile.nmake autogen.sh event_rpcgen.py \ libevent.pc.in make-event-config.sed whatsnew-2.0.txt \ whatsnew-2.1.txt README.md $(CMAKE_FILES) \ $(PLATFORM_DEPENDENT_SRC) test/check-dumpevents.py \ test/regress.gen.c test/regress.gen.h test/regress.rpc \ test/rpcgen_wrapper.sh test/print-winsock-errors.c \ test/test.sh LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la \ $(am__append_1) $(am__append_3) @INSTALL_LIBEVENT_TRUE@lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA) @INSTALL_LIBEVENT_TRUE@pkgconfig_DATA = $(LIBEVENT_PKGCONFIG) @INSTALL_LIBEVENT_FALSE@noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA) EXTRA_SOURCE = noinst_HEADERS = $(am__append_6) $(am__append_9) test/regress.h \ test/regress_thread.h test/tinytest.h test/tinytest_local.h \ test/tinytest_macros.h WIN32-Code/nmake/evconfig-private.h \ WIN32-Code/nmake/event2/event-config.h WIN32-Code/getopt.h \ WIN32-Code/getopt.c WIN32-Code/getopt_long.c WIN32-Code/tree.h \ bufferevent-internal.h changelist-internal.h \ compat/sys/queue.h defer-internal.h epolltable-internal.h \ evbuffer-internal.h event-internal.h evmap-internal.h \ evrpc-internal.h evsignal-internal.h evthread-internal.h \ ht-internal.h http-internal.h iocp-internal.h ipv6-internal.h \ kqueue-internal.h log-internal.h minheap-internal.h \ mm-internal.h ratelim-internal.h ratelim-internal.h \ strlcpy-internal.h time-internal.h util-internal.h \ openssl-compat.h $(am__append_28) CLEANFILES = test/rpcgen-attempted DISTCLEANFILES = test/regress.gen.c test/regress.gen.h *~ libevent.pc \ libevent_core.pc libevent_extra.pc \ ./include/event2/event-config.h BUILT_SOURCES = $(am__append_13) include/event2/event-config.h include_event2dir = $(includedir)/event2 EVENT2_EXPORT = include/event2/buffer.h include/event2/buffer_compat.h \ include/event2/bufferevent.h \ include/event2/bufferevent_compat.h \ include/event2/bufferevent_struct.h include/event2/dns.h \ include/event2/dns_compat.h include/event2/dns_struct.h \ include/event2/event.h include/event2/event_compat.h \ include/event2/event_struct.h include/event2/http.h \ include/event2/http_compat.h include/event2/http_struct.h \ include/event2/keyvalq_struct.h include/event2/listener.h \ include/event2/rpc.h include/event2/rpc_compat.h \ include/event2/rpc_struct.h include/event2/tag.h \ include/event2/tag_compat.h include/event2/thread.h \ include/event2/util.h include/event2/visibility.h \ $(am__append_5) @INSTALL_LIBEVENT_TRUE@include_event2_HEADERS = $(EVENT2_EXPORT) @INSTALL_LIBEVENT_TRUE@nodist_include_event2_HEADERS = include/event2/event-config.h @INSTALL_LIBEVENT_FALSE@nodist_noinst_HEADERS = include/event2/event-config.h SAMPLES = sample/dns-example sample/event-read-fifo sample/hello-world \ sample/http-server sample/http-connect sample/signal-test \ sample/time-test $(am__append_7) @OPENSSL_TRUE@sample_le_proxy_SOURCES = sample/le-proxy.c @OPENSSL_TRUE@sample_le_proxy_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD) @OPENSSL_TRUE@sample_le_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS) @OPENSSL_TRUE@sample_https_client_SOURCES = \ @OPENSSL_TRUE@ sample/https-client.c \ @OPENSSL_TRUE@ sample/hostcheck.c \ @OPENSSL_TRUE@ sample/openssl_hostname_validation.c @OPENSSL_TRUE@sample_https_client_LDADD = libevent.la \ @OPENSSL_TRUE@ libevent_openssl.la $(OPENSSL_LIBS) \ @OPENSSL_TRUE@ $(OPENSSL_LIBADD) $(am__append_8) @OPENSSL_TRUE@sample_https_client_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS) sample_event_read_fifo_SOURCES = sample/event-read-fifo.c sample_event_read_fifo_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_time_test_SOURCES = sample/time-test.c sample_time_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_signal_test_SOURCES = sample/signal-test.c sample_signal_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_dns_example_SOURCES = sample/dns-example.c sample_dns_example_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_hello_world_SOURCES = sample/hello-world.c sample_hello_world_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_http_server_SOURCES = sample/http-server.c sample_http_server_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_http_connect_SOURCES = sample/http-connect.c sample_http_connect_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la regress_CPPFLAGS = -DTINYTEST_LOCAL TESTPROGRAMS = \ test/bench \ test/bench_cascade \ test/bench_http \ test/bench_httpclient \ test/test-changelist \ test/test-dumpevents \ test/test-eof \ test/test-closed \ test/test-fdleak \ test/test-init \ test/test-ratelim \ test/test-time \ test/test-weof \ test/regress TESTS = \ test_runner_epoll \ test_runner_select \ test_runner_kqueue \ test_runner_evport \ test_runner_devpoll \ test_runner_poll \ test_runner_win32 \ test_runner_timerfd \ test_runner_changelist \ test_runner_timerfd_changelist LOG_COMPILER = true TESTS_COMPILER = true test_test_init_SOURCES = test/test-init.c test_test_init_LDADD = libevent_core.la test_test_dumpevents_SOURCES = test/test-dumpevents.c test_test_dumpevents_LDADD = libevent_core.la test_test_eof_SOURCES = test/test-eof.c test_test_eof_LDADD = libevent_core.la test_test_closed_SOURCES = test/test-closed.c test_test_closed_LDADD = libevent_core.la test_test_changelist_SOURCES = test/test-changelist.c test_test_changelist_LDADD = libevent_core.la test_test_weof_SOURCES = test/test-weof.c test_test_weof_LDADD = libevent_core.la test_test_time_SOURCES = test/test-time.c test_test_time_LDADD = libevent_core.la test_test_ratelim_SOURCES = test/test-ratelim.c test_test_ratelim_LDADD = libevent_core.la -lm test_test_fdleak_SOURCES = test/test-fdleak.c test_test_fdleak_LDADD = libevent_core.la test_regress_SOURCES = test/regress.c test/regress.gen.c \ test/regress.gen.h test/regress_buffer.c \ test/regress_bufferevent.c test/regress_dns.c \ test/regress_et.c test/regress_finalize.c test/regress_http.c \ test/regress_listener.c test/regress_main.c \ test/regress_minheap.c test/regress_rpc.c \ test/regress_testutils.c test/regress_testutils.h \ test/regress_util.c test/tinytest.c $(regress_thread_SOURCES) \ $(regress_zlib_SOURCES) $(am__append_15) $(am__append_16) @BUILD_WIN32_TRUE@@THREADS_TRUE@regress_thread_SOURCES = test/regress_thread.c @PTHREADS_TRUE@regress_thread_SOURCES = test/regress_thread.c @ZLIB_REGRESS_TRUE@regress_zlib_SOURCES = test/regress_zlib.c test_regress_LDADD = $(LIBEVENT_GC_SECTIONS) libevent_core.la \ libevent_extra.la $(PTHREAD_LIBS) $(ZLIB_LIBS) \ $(am__append_18) test_regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) \ $(ZLIB_CFLAGS) -Itest $(am__append_17) test_regress_LDFLAGS = $(PTHREAD_CFLAGS) test_bench_SOURCES = test/bench.c test_bench_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la test_bench_cascade_SOURCES = test/bench_cascade.c test_bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la test_bench_http_SOURCES = test/bench_http.c test_bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la test_bench_httpclient_SOURCES = test/bench_httpclient.c test_bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) libevent_core.la @BUILD_WIN32_FALSE@SYS_CORE_LIBS = @BUILD_WIN32_TRUE@SYS_CORE_LIBS = -liphlpapi @BUILD_WIN32_FALSE@SYS_LIBS = @BUILD_WIN32_TRUE@SYS_LIBS = -lws2_32 -lshell32 -ladvapi32 @BUILD_WIN32_FALSE@SYS_SRC = $(am__append_20) $(am__append_21) \ @BUILD_WIN32_FALSE@ $(am__append_22) $(am__append_23) \ @BUILD_WIN32_FALSE@ $(am__append_24) $(am__append_25) \ @BUILD_WIN32_FALSE@ $(am__append_26) $(am__append_27) @BUILD_WIN32_TRUE@SYS_SRC = win32select.c buffer_iocp.c event_iocp.c \ @BUILD_WIN32_TRUE@ bufferevent_async.c $(am__append_19) \ @BUILD_WIN32_TRUE@ $(am__append_20) $(am__append_21) \ @BUILD_WIN32_TRUE@ $(am__append_22) $(am__append_23) \ @BUILD_WIN32_TRUE@ $(am__append_24) $(am__append_25) \ @BUILD_WIN32_TRUE@ $(am__append_26) $(am__append_27) @BUILD_WIN32_FALSE@SYS_INCLUDES = @BUILD_WIN32_TRUE@SYS_INCLUDES = -IWIN32-Code -IWIN32-Code/nmake CORE_SRC = \ buffer.c \ bufferevent.c \ bufferevent_filter.c \ bufferevent_pair.c \ bufferevent_ratelim.c \ bufferevent_sock.c \ event.c \ evmap.c \ evthread.c \ evutil.c \ evutil_rand.c \ evutil_time.c \ listener.c \ log.c \ $(SYS_SRC) EXTRAS_SRC = \ evdns.c \ event_tagging.c \ evrpc.c \ http.c @BUILD_WITH_NO_UNDEFINED_FALSE@NO_UNDEFINED = @BUILD_WITH_NO_UNDEFINED_TRUE@NO_UNDEFINED = -no-undefined @BUILD_WITH_NO_UNDEFINED_FALSE@MAYBE_CORE = @BUILD_WITH_NO_UNDEFINED_TRUE@MAYBE_CORE = libevent_core.la AM_CFLAGS = $(LIBEVENT_CFLAGS) AM_CPPFLAGS = -I$(srcdir)/compat -I./include -I$(srcdir)/include $(SYS_INCLUDES) $(LIBEVENT_CPPFLAGS) AM_LDFLAGS = $(LIBEVENT_LDFLAGS) GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) $(AM_LDFLAGS) libevent_la_SOURCES = $(CORE_SRC) $(EXTRAS_SRC) libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) $(SYS_CORE_LIBS) libevent_la_LDFLAGS = $(GENERIC_LDFLAGS) libevent_core_la_SOURCES = $(CORE_SRC) libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) $(SYS_CORE_LIBS) libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS) @PTHREADS_TRUE@libevent_pthreads_la_SOURCES = evthread_pthread.c @PTHREADS_TRUE@libevent_pthreads_la_LIBADD = $(MAYBE_CORE) @PTHREADS_TRUE@libevent_pthreads_la_LDFLAGS = $(GENERIC_LDFLAGS) libevent_extra_la_SOURCES = $(EXTRAS_SRC) libevent_extra_la_LIBADD = $(MAYBE_CORE) $(SYS_LIBS) libevent_extra_la_LDFLAGS = $(GENERIC_LDFLAGS) @OPENSSL_TRUE@libevent_openssl_la_SOURCES = bufferevent_openssl.c @OPENSSL_TRUE@libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS) @OPENSSL_TRUE@libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS) @OPENSSL_TRUE@libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS) EVENT1_HDRS = \ include/evdns.h \ include/event.h \ include/evhttp.h \ include/evrpc.h \ include/evutil.h @INSTALL_LIBEVENT_TRUE@include_HEADERS = $(EVENT1_HDRS) # integrate doxygen with automake targets @ENABLE_DOXYGEN_TRUE@man3_MANS = @DX_DOCDIR@/man/man3/* # Docs will be installed. It may be one or more docs supported # by doxygen, but does not include 'man'. @ENABLE_DOXYGEN_TRUE@docdirs = $(DX_INSTALL_DOCS) all: $(BUILT_SOURCES) config.h evconfig-private.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/include/include.am $(srcdir)/sample/include.am $(srcdir)/test/include.am $(srcdir)/doxygen.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(srcdir)/include/include.am $(srcdir)/sample/include.am $(srcdir)/test/include.am $(srcdir)/doxygen.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ evconfig-private.h: stamp-h2 @test -f $@ || rm -f stamp-h2 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h2 stamp-h2: $(srcdir)/evconfig-private.h.in $(top_builddir)/config.status @rm -f stamp-h2 cd $(top_builddir) && $(SHELL) ./config.status evconfig-private.h distclean-hdr: -rm -f config.h stamp-h1 evconfig-private.h stamp-h2 libevent.pc: $(top_builddir)/config.status $(srcdir)/libevent.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ libevent_openssl.pc: $(top_builddir)/config.status $(srcdir)/libevent_openssl.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ libevent_pthreads.pc: $(top_builddir)/config.status $(srcdir)/libevent_pthreads.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ libevent_core.pc: $(top_builddir)/config.status $(srcdir)/libevent_core.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ libevent_extra.pc: $(top_builddir)/config.status $(srcdir)/libevent_extra.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libevent.la: $(libevent_la_OBJECTS) $(libevent_la_DEPENDENCIES) $(EXTRA_libevent_la_DEPENDENCIES) $(AM_V_CCLD)$(libevent_la_LINK) $(am_libevent_la_rpath) $(libevent_la_OBJECTS) $(libevent_la_LIBADD) $(LIBS) libevent_core.la: $(libevent_core_la_OBJECTS) $(libevent_core_la_DEPENDENCIES) $(EXTRA_libevent_core_la_DEPENDENCIES) $(AM_V_CCLD)$(libevent_core_la_LINK) $(am_libevent_core_la_rpath) $(libevent_core_la_OBJECTS) $(libevent_core_la_LIBADD) $(LIBS) libevent_extra.la: $(libevent_extra_la_OBJECTS) $(libevent_extra_la_DEPENDENCIES) $(EXTRA_libevent_extra_la_DEPENDENCIES) $(AM_V_CCLD)$(libevent_extra_la_LINK) $(am_libevent_extra_la_rpath) $(libevent_extra_la_OBJECTS) $(libevent_extra_la_LIBADD) $(LIBS) libevent_openssl.la: $(libevent_openssl_la_OBJECTS) $(libevent_openssl_la_DEPENDENCIES) $(EXTRA_libevent_openssl_la_DEPENDENCIES) $(AM_V_CCLD)$(libevent_openssl_la_LINK) $(am_libevent_openssl_la_rpath) $(libevent_openssl_la_OBJECTS) $(libevent_openssl_la_LIBADD) $(LIBS) libevent_pthreads.la: $(libevent_pthreads_la_OBJECTS) $(libevent_pthreads_la_DEPENDENCIES) $(EXTRA_libevent_pthreads_la_DEPENDENCIES) $(AM_V_CCLD)$(libevent_pthreads_la_LINK) $(am_libevent_pthreads_la_rpath) $(libevent_pthreads_la_OBJECTS) $(libevent_pthreads_la_LIBADD) $(LIBS) sample/$(am__dirstamp): @$(MKDIR_P) sample @: > sample/$(am__dirstamp) sample/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) sample/$(DEPDIR) @: > sample/$(DEPDIR)/$(am__dirstamp) sample/dns-example.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/dns-example$(EXEEXT): $(sample_dns_example_OBJECTS) $(sample_dns_example_DEPENDENCIES) $(EXTRA_sample_dns_example_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/dns-example$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_dns_example_OBJECTS) $(sample_dns_example_LDADD) $(LIBS) sample/event-read-fifo.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/event-read-fifo$(EXEEXT): $(sample_event_read_fifo_OBJECTS) $(sample_event_read_fifo_DEPENDENCIES) $(EXTRA_sample_event_read_fifo_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/event-read-fifo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_event_read_fifo_OBJECTS) $(sample_event_read_fifo_LDADD) $(LIBS) sample/hello-world.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/hello-world$(EXEEXT): $(sample_hello_world_OBJECTS) $(sample_hello_world_DEPENDENCIES) $(EXTRA_sample_hello_world_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/hello-world$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_hello_world_OBJECTS) $(sample_hello_world_LDADD) $(LIBS) sample/http-connect.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/http-connect$(EXEEXT): $(sample_http_connect_OBJECTS) $(sample_http_connect_DEPENDENCIES) $(EXTRA_sample_http_connect_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/http-connect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_http_connect_OBJECTS) $(sample_http_connect_LDADD) $(LIBS) sample/http-server.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/http-server$(EXEEXT): $(sample_http_server_OBJECTS) $(sample_http_server_DEPENDENCIES) $(EXTRA_sample_http_server_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/http-server$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_http_server_OBJECTS) $(sample_http_server_LDADD) $(LIBS) sample/https_client-https-client.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/https_client-hostcheck.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/https_client-openssl_hostname_validation.$(OBJEXT): \ sample/$(am__dirstamp) sample/$(DEPDIR)/$(am__dirstamp) sample/https-client$(EXEEXT): $(sample_https_client_OBJECTS) $(sample_https_client_DEPENDENCIES) $(EXTRA_sample_https_client_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/https-client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_https_client_OBJECTS) $(sample_https_client_LDADD) $(LIBS) sample/le_proxy-le-proxy.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/le-proxy$(EXEEXT): $(sample_le_proxy_OBJECTS) $(sample_le_proxy_DEPENDENCIES) $(EXTRA_sample_le_proxy_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/le-proxy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_le_proxy_OBJECTS) $(sample_le_proxy_LDADD) $(LIBS) sample/signal-test.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/signal-test$(EXEEXT): $(sample_signal_test_OBJECTS) $(sample_signal_test_DEPENDENCIES) $(EXTRA_sample_signal_test_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/signal-test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_signal_test_OBJECTS) $(sample_signal_test_LDADD) $(LIBS) sample/time-test.$(OBJEXT): sample/$(am__dirstamp) \ sample/$(DEPDIR)/$(am__dirstamp) sample/time-test$(EXEEXT): $(sample_time_test_OBJECTS) $(sample_time_test_DEPENDENCIES) $(EXTRA_sample_time_test_DEPENDENCIES) sample/$(am__dirstamp) @rm -f sample/time-test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sample_time_test_OBJECTS) $(sample_time_test_LDADD) $(LIBS) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/bench.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/bench$(EXEEXT): $(test_bench_OBJECTS) $(test_bench_DEPENDENCIES) $(EXTRA_test_bench_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/bench$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bench_OBJECTS) $(test_bench_LDADD) $(LIBS) test/bench_cascade.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/bench_cascade$(EXEEXT): $(test_bench_cascade_OBJECTS) $(test_bench_cascade_DEPENDENCIES) $(EXTRA_test_bench_cascade_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/bench_cascade$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bench_cascade_OBJECTS) $(test_bench_cascade_LDADD) $(LIBS) test/bench_http.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/bench_http$(EXEEXT): $(test_bench_http_OBJECTS) $(test_bench_http_DEPENDENCIES) $(EXTRA_test_bench_http_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/bench_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bench_http_OBJECTS) $(test_bench_http_LDADD) $(LIBS) test/bench_httpclient.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/bench_httpclient$(EXEEXT): $(test_bench_httpclient_OBJECTS) $(test_bench_httpclient_DEPENDENCIES) $(EXTRA_test_bench_httpclient_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/bench_httpclient$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bench_httpclient_OBJECTS) $(test_bench_httpclient_LDADD) $(LIBS) test/regress-regress.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress.gen.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_buffer.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_bufferevent.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_dns.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_et.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_finalize.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_http.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_listener.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_main.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_minheap.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_rpc.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_testutils.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_util.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-tinytest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_thread.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_zlib.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_iocp.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress-regress_ssl.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/regress$(EXEEXT): $(test_regress_OBJECTS) $(test_regress_DEPENDENCIES) $(EXTRA_test_regress_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/regress$(EXEEXT) $(AM_V_CCLD)$(test_regress_LINK) $(test_regress_OBJECTS) $(test_regress_LDADD) $(LIBS) test/test-changelist.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-changelist$(EXEEXT): $(test_test_changelist_OBJECTS) $(test_test_changelist_DEPENDENCIES) $(EXTRA_test_test_changelist_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-changelist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_changelist_OBJECTS) $(test_test_changelist_LDADD) $(LIBS) test/test-closed.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-closed$(EXEEXT): $(test_test_closed_OBJECTS) $(test_test_closed_DEPENDENCIES) $(EXTRA_test_test_closed_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-closed$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_closed_OBJECTS) $(test_test_closed_LDADD) $(LIBS) test/test-dumpevents.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-dumpevents$(EXEEXT): $(test_test_dumpevents_OBJECTS) $(test_test_dumpevents_DEPENDENCIES) $(EXTRA_test_test_dumpevents_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-dumpevents$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_dumpevents_OBJECTS) $(test_test_dumpevents_LDADD) $(LIBS) test/test-eof.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-eof$(EXEEXT): $(test_test_eof_OBJECTS) $(test_test_eof_DEPENDENCIES) $(EXTRA_test_test_eof_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-eof$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_eof_OBJECTS) $(test_test_eof_LDADD) $(LIBS) test/test-fdleak.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-fdleak$(EXEEXT): $(test_test_fdleak_OBJECTS) $(test_test_fdleak_DEPENDENCIES) $(EXTRA_test_test_fdleak_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-fdleak$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_fdleak_OBJECTS) $(test_test_fdleak_LDADD) $(LIBS) test/test-init.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-init$(EXEEXT): $(test_test_init_OBJECTS) $(test_test_init_DEPENDENCIES) $(EXTRA_test_test_init_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-init$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_init_OBJECTS) $(test_test_init_LDADD) $(LIBS) test/test-ratelim.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-ratelim$(EXEEXT): $(test_test_ratelim_OBJECTS) $(test_test_ratelim_DEPENDENCIES) $(EXTRA_test_test_ratelim_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-ratelim$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_ratelim_OBJECTS) $(test_test_ratelim_LDADD) $(LIBS) test/test-time.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-time$(EXEEXT): $(test_test_time_OBJECTS) $(test_test_time_DEPENDENCIES) $(EXTRA_test_test_time_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-time$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_time_OBJECTS) $(test_test_time_LDADD) $(LIBS) test/test-weof.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-weof$(EXEEXT): $(test_test_weof_OBJECTS) $(test_test_weof_DEPENDENCIES) $(EXTRA_test_test_weof_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-weof$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_weof_OBJECTS) $(test_test_weof_LDADD) $(LIBS) install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f sample/*.$(OBJEXT) -rm -f test/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/epoll_sub.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer_iocp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_async.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_filter.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_pair.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_ratelim.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_sock.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devpoll.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epoll.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evdns.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_iocp.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_tagging.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evmap.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evport.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evrpc.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread_pthread.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread_win32.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evutil.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evutil_rand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evutil_time.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kqueue.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/poll.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32select.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/dns-example.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/event-read-fifo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/hello-world.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/http-connect.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/http-server.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/https_client-hostcheck.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/https_client-https-client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/le_proxy-le-proxy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/signal-test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@sample/$(DEPDIR)/time-test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bench.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bench_cascade.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bench_http.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bench_httpclient.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress.gen.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_buffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_bufferevent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_dns.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_et.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_finalize.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_http.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_iocp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_listener.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_minheap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_rpc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_ssl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_testutils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_thread.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_util.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-regress_zlib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/regress-tinytest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-changelist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-closed.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-dumpevents.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-eof.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-fdleak.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-init.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-ratelim.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-time.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-weof.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libevent_openssl_la-bufferevent_openssl.lo: bufferevent_openssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libevent_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libevent_openssl_la-bufferevent_openssl.lo -MD -MP -MF $(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Tpo -c -o libevent_openssl_la-bufferevent_openssl.lo `test -f 'bufferevent_openssl.c' || echo '$(srcdir)/'`bufferevent_openssl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Tpo $(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bufferevent_openssl.c' object='libevent_openssl_la-bufferevent_openssl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libevent_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libevent_openssl_la-bufferevent_openssl.lo `test -f 'bufferevent_openssl.c' || echo '$(srcdir)/'`bufferevent_openssl.c sample/https_client-https-client.o: sample/https-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-https-client.o -MD -MP -MF sample/$(DEPDIR)/https_client-https-client.Tpo -c -o sample/https_client-https-client.o `test -f 'sample/https-client.c' || echo '$(srcdir)/'`sample/https-client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-https-client.Tpo sample/$(DEPDIR)/https_client-https-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/https-client.c' object='sample/https_client-https-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-https-client.o `test -f 'sample/https-client.c' || echo '$(srcdir)/'`sample/https-client.c sample/https_client-https-client.obj: sample/https-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-https-client.obj -MD -MP -MF sample/$(DEPDIR)/https_client-https-client.Tpo -c -o sample/https_client-https-client.obj `if test -f 'sample/https-client.c'; then $(CYGPATH_W) 'sample/https-client.c'; else $(CYGPATH_W) '$(srcdir)/sample/https-client.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-https-client.Tpo sample/$(DEPDIR)/https_client-https-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/https-client.c' object='sample/https_client-https-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-https-client.obj `if test -f 'sample/https-client.c'; then $(CYGPATH_W) 'sample/https-client.c'; else $(CYGPATH_W) '$(srcdir)/sample/https-client.c'; fi` sample/https_client-hostcheck.o: sample/hostcheck.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-hostcheck.o -MD -MP -MF sample/$(DEPDIR)/https_client-hostcheck.Tpo -c -o sample/https_client-hostcheck.o `test -f 'sample/hostcheck.c' || echo '$(srcdir)/'`sample/hostcheck.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-hostcheck.Tpo sample/$(DEPDIR)/https_client-hostcheck.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/hostcheck.c' object='sample/https_client-hostcheck.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-hostcheck.o `test -f 'sample/hostcheck.c' || echo '$(srcdir)/'`sample/hostcheck.c sample/https_client-hostcheck.obj: sample/hostcheck.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-hostcheck.obj -MD -MP -MF sample/$(DEPDIR)/https_client-hostcheck.Tpo -c -o sample/https_client-hostcheck.obj `if test -f 'sample/hostcheck.c'; then $(CYGPATH_W) 'sample/hostcheck.c'; else $(CYGPATH_W) '$(srcdir)/sample/hostcheck.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-hostcheck.Tpo sample/$(DEPDIR)/https_client-hostcheck.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/hostcheck.c' object='sample/https_client-hostcheck.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-hostcheck.obj `if test -f 'sample/hostcheck.c'; then $(CYGPATH_W) 'sample/hostcheck.c'; else $(CYGPATH_W) '$(srcdir)/sample/hostcheck.c'; fi` sample/https_client-openssl_hostname_validation.o: sample/openssl_hostname_validation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-openssl_hostname_validation.o -MD -MP -MF sample/$(DEPDIR)/https_client-openssl_hostname_validation.Tpo -c -o sample/https_client-openssl_hostname_validation.o `test -f 'sample/openssl_hostname_validation.c' || echo '$(srcdir)/'`sample/openssl_hostname_validation.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-openssl_hostname_validation.Tpo sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/openssl_hostname_validation.c' object='sample/https_client-openssl_hostname_validation.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-openssl_hostname_validation.o `test -f 'sample/openssl_hostname_validation.c' || echo '$(srcdir)/'`sample/openssl_hostname_validation.c sample/https_client-openssl_hostname_validation.obj: sample/openssl_hostname_validation.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/https_client-openssl_hostname_validation.obj -MD -MP -MF sample/$(DEPDIR)/https_client-openssl_hostname_validation.Tpo -c -o sample/https_client-openssl_hostname_validation.obj `if test -f 'sample/openssl_hostname_validation.c'; then $(CYGPATH_W) 'sample/openssl_hostname_validation.c'; else $(CYGPATH_W) '$(srcdir)/sample/openssl_hostname_validation.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/https_client-openssl_hostname_validation.Tpo sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/openssl_hostname_validation.c' object='sample/https_client-openssl_hostname_validation.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_https_client_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/https_client-openssl_hostname_validation.obj `if test -f 'sample/openssl_hostname_validation.c'; then $(CYGPATH_W) 'sample/openssl_hostname_validation.c'; else $(CYGPATH_W) '$(srcdir)/sample/openssl_hostname_validation.c'; fi` sample/le_proxy-le-proxy.o: sample/le-proxy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_le_proxy_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/le_proxy-le-proxy.o -MD -MP -MF sample/$(DEPDIR)/le_proxy-le-proxy.Tpo -c -o sample/le_proxy-le-proxy.o `test -f 'sample/le-proxy.c' || echo '$(srcdir)/'`sample/le-proxy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/le_proxy-le-proxy.Tpo sample/$(DEPDIR)/le_proxy-le-proxy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/le-proxy.c' object='sample/le_proxy-le-proxy.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_le_proxy_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/le_proxy-le-proxy.o `test -f 'sample/le-proxy.c' || echo '$(srcdir)/'`sample/le-proxy.c sample/le_proxy-le-proxy.obj: sample/le-proxy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_le_proxy_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sample/le_proxy-le-proxy.obj -MD -MP -MF sample/$(DEPDIR)/le_proxy-le-proxy.Tpo -c -o sample/le_proxy-le-proxy.obj `if test -f 'sample/le-proxy.c'; then $(CYGPATH_W) 'sample/le-proxy.c'; else $(CYGPATH_W) '$(srcdir)/sample/le-proxy.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sample/$(DEPDIR)/le_proxy-le-proxy.Tpo sample/$(DEPDIR)/le_proxy-le-proxy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sample/le-proxy.c' object='sample/le_proxy-le-proxy.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sample_le_proxy_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sample/le_proxy-le-proxy.obj `if test -f 'sample/le-proxy.c'; then $(CYGPATH_W) 'sample/le-proxy.c'; else $(CYGPATH_W) '$(srcdir)/sample/le-proxy.c'; fi` test/regress-regress.o: test/regress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress.o -MD -MP -MF test/$(DEPDIR)/regress-regress.Tpo -c -o test/regress-regress.o `test -f 'test/regress.c' || echo '$(srcdir)/'`test/regress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress.Tpo test/$(DEPDIR)/regress-regress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress.c' object='test/regress-regress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress.o `test -f 'test/regress.c' || echo '$(srcdir)/'`test/regress.c test/regress-regress.obj: test/regress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress.obj -MD -MP -MF test/$(DEPDIR)/regress-regress.Tpo -c -o test/regress-regress.obj `if test -f 'test/regress.c'; then $(CYGPATH_W) 'test/regress.c'; else $(CYGPATH_W) '$(srcdir)/test/regress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress.Tpo test/$(DEPDIR)/regress-regress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress.c' object='test/regress-regress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress.obj `if test -f 'test/regress.c'; then $(CYGPATH_W) 'test/regress.c'; else $(CYGPATH_W) '$(srcdir)/test/regress.c'; fi` test/regress-regress.gen.o: test/regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress.gen.o -MD -MP -MF test/$(DEPDIR)/regress-regress.gen.Tpo -c -o test/regress-regress.gen.o `test -f 'test/regress.gen.c' || echo '$(srcdir)/'`test/regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress.gen.Tpo test/$(DEPDIR)/regress-regress.gen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress.gen.c' object='test/regress-regress.gen.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress.gen.o `test -f 'test/regress.gen.c' || echo '$(srcdir)/'`test/regress.gen.c test/regress-regress.gen.obj: test/regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress.gen.obj -MD -MP -MF test/$(DEPDIR)/regress-regress.gen.Tpo -c -o test/regress-regress.gen.obj `if test -f 'test/regress.gen.c'; then $(CYGPATH_W) 'test/regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/test/regress.gen.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress.gen.Tpo test/$(DEPDIR)/regress-regress.gen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress.gen.c' object='test/regress-regress.gen.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress.gen.obj `if test -f 'test/regress.gen.c'; then $(CYGPATH_W) 'test/regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/test/regress.gen.c'; fi` test/regress-regress_buffer.o: test/regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_buffer.o -MD -MP -MF test/$(DEPDIR)/regress-regress_buffer.Tpo -c -o test/regress-regress_buffer.o `test -f 'test/regress_buffer.c' || echo '$(srcdir)/'`test/regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_buffer.Tpo test/$(DEPDIR)/regress-regress_buffer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_buffer.c' object='test/regress-regress_buffer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_buffer.o `test -f 'test/regress_buffer.c' || echo '$(srcdir)/'`test/regress_buffer.c test/regress-regress_buffer.obj: test/regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_buffer.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_buffer.Tpo -c -o test/regress-regress_buffer.obj `if test -f 'test/regress_buffer.c'; then $(CYGPATH_W) 'test/regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_buffer.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_buffer.Tpo test/$(DEPDIR)/regress-regress_buffer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_buffer.c' object='test/regress-regress_buffer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_buffer.obj `if test -f 'test/regress_buffer.c'; then $(CYGPATH_W) 'test/regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_buffer.c'; fi` test/regress-regress_bufferevent.o: test/regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_bufferevent.o -MD -MP -MF test/$(DEPDIR)/regress-regress_bufferevent.Tpo -c -o test/regress-regress_bufferevent.o `test -f 'test/regress_bufferevent.c' || echo '$(srcdir)/'`test/regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_bufferevent.Tpo test/$(DEPDIR)/regress-regress_bufferevent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_bufferevent.c' object='test/regress-regress_bufferevent.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_bufferevent.o `test -f 'test/regress_bufferevent.c' || echo '$(srcdir)/'`test/regress_bufferevent.c test/regress-regress_bufferevent.obj: test/regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_bufferevent.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_bufferevent.Tpo -c -o test/regress-regress_bufferevent.obj `if test -f 'test/regress_bufferevent.c'; then $(CYGPATH_W) 'test/regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_bufferevent.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_bufferevent.Tpo test/$(DEPDIR)/regress-regress_bufferevent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_bufferevent.c' object='test/regress-regress_bufferevent.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_bufferevent.obj `if test -f 'test/regress_bufferevent.c'; then $(CYGPATH_W) 'test/regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_bufferevent.c'; fi` test/regress-regress_dns.o: test/regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_dns.o -MD -MP -MF test/$(DEPDIR)/regress-regress_dns.Tpo -c -o test/regress-regress_dns.o `test -f 'test/regress_dns.c' || echo '$(srcdir)/'`test/regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_dns.Tpo test/$(DEPDIR)/regress-regress_dns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_dns.c' object='test/regress-regress_dns.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_dns.o `test -f 'test/regress_dns.c' || echo '$(srcdir)/'`test/regress_dns.c test/regress-regress_dns.obj: test/regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_dns.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_dns.Tpo -c -o test/regress-regress_dns.obj `if test -f 'test/regress_dns.c'; then $(CYGPATH_W) 'test/regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_dns.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_dns.Tpo test/$(DEPDIR)/regress-regress_dns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_dns.c' object='test/regress-regress_dns.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_dns.obj `if test -f 'test/regress_dns.c'; then $(CYGPATH_W) 'test/regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_dns.c'; fi` test/regress-regress_et.o: test/regress_et.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_et.o -MD -MP -MF test/$(DEPDIR)/regress-regress_et.Tpo -c -o test/regress-regress_et.o `test -f 'test/regress_et.c' || echo '$(srcdir)/'`test/regress_et.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_et.Tpo test/$(DEPDIR)/regress-regress_et.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_et.c' object='test/regress-regress_et.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_et.o `test -f 'test/regress_et.c' || echo '$(srcdir)/'`test/regress_et.c test/regress-regress_et.obj: test/regress_et.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_et.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_et.Tpo -c -o test/regress-regress_et.obj `if test -f 'test/regress_et.c'; then $(CYGPATH_W) 'test/regress_et.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_et.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_et.Tpo test/$(DEPDIR)/regress-regress_et.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_et.c' object='test/regress-regress_et.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_et.obj `if test -f 'test/regress_et.c'; then $(CYGPATH_W) 'test/regress_et.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_et.c'; fi` test/regress-regress_finalize.o: test/regress_finalize.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_finalize.o -MD -MP -MF test/$(DEPDIR)/regress-regress_finalize.Tpo -c -o test/regress-regress_finalize.o `test -f 'test/regress_finalize.c' || echo '$(srcdir)/'`test/regress_finalize.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_finalize.Tpo test/$(DEPDIR)/regress-regress_finalize.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_finalize.c' object='test/regress-regress_finalize.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_finalize.o `test -f 'test/regress_finalize.c' || echo '$(srcdir)/'`test/regress_finalize.c test/regress-regress_finalize.obj: test/regress_finalize.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_finalize.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_finalize.Tpo -c -o test/regress-regress_finalize.obj `if test -f 'test/regress_finalize.c'; then $(CYGPATH_W) 'test/regress_finalize.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_finalize.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_finalize.Tpo test/$(DEPDIR)/regress-regress_finalize.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_finalize.c' object='test/regress-regress_finalize.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_finalize.obj `if test -f 'test/regress_finalize.c'; then $(CYGPATH_W) 'test/regress_finalize.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_finalize.c'; fi` test/regress-regress_http.o: test/regress_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_http.o -MD -MP -MF test/$(DEPDIR)/regress-regress_http.Tpo -c -o test/regress-regress_http.o `test -f 'test/regress_http.c' || echo '$(srcdir)/'`test/regress_http.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_http.Tpo test/$(DEPDIR)/regress-regress_http.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_http.c' object='test/regress-regress_http.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_http.o `test -f 'test/regress_http.c' || echo '$(srcdir)/'`test/regress_http.c test/regress-regress_http.obj: test/regress_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_http.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_http.Tpo -c -o test/regress-regress_http.obj `if test -f 'test/regress_http.c'; then $(CYGPATH_W) 'test/regress_http.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_http.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_http.Tpo test/$(DEPDIR)/regress-regress_http.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_http.c' object='test/regress-regress_http.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_http.obj `if test -f 'test/regress_http.c'; then $(CYGPATH_W) 'test/regress_http.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_http.c'; fi` test/regress-regress_listener.o: test/regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_listener.o -MD -MP -MF test/$(DEPDIR)/regress-regress_listener.Tpo -c -o test/regress-regress_listener.o `test -f 'test/regress_listener.c' || echo '$(srcdir)/'`test/regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_listener.Tpo test/$(DEPDIR)/regress-regress_listener.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_listener.c' object='test/regress-regress_listener.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_listener.o `test -f 'test/regress_listener.c' || echo '$(srcdir)/'`test/regress_listener.c test/regress-regress_listener.obj: test/regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_listener.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_listener.Tpo -c -o test/regress-regress_listener.obj `if test -f 'test/regress_listener.c'; then $(CYGPATH_W) 'test/regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_listener.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_listener.Tpo test/$(DEPDIR)/regress-regress_listener.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_listener.c' object='test/regress-regress_listener.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_listener.obj `if test -f 'test/regress_listener.c'; then $(CYGPATH_W) 'test/regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_listener.c'; fi` test/regress-regress_main.o: test/regress_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_main.o -MD -MP -MF test/$(DEPDIR)/regress-regress_main.Tpo -c -o test/regress-regress_main.o `test -f 'test/regress_main.c' || echo '$(srcdir)/'`test/regress_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_main.Tpo test/$(DEPDIR)/regress-regress_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_main.c' object='test/regress-regress_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_main.o `test -f 'test/regress_main.c' || echo '$(srcdir)/'`test/regress_main.c test/regress-regress_main.obj: test/regress_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_main.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_main.Tpo -c -o test/regress-regress_main.obj `if test -f 'test/regress_main.c'; then $(CYGPATH_W) 'test/regress_main.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_main.Tpo test/$(DEPDIR)/regress-regress_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_main.c' object='test/regress-regress_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_main.obj `if test -f 'test/regress_main.c'; then $(CYGPATH_W) 'test/regress_main.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_main.c'; fi` test/regress-regress_minheap.o: test/regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_minheap.o -MD -MP -MF test/$(DEPDIR)/regress-regress_minheap.Tpo -c -o test/regress-regress_minheap.o `test -f 'test/regress_minheap.c' || echo '$(srcdir)/'`test/regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_minheap.Tpo test/$(DEPDIR)/regress-regress_minheap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_minheap.c' object='test/regress-regress_minheap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_minheap.o `test -f 'test/regress_minheap.c' || echo '$(srcdir)/'`test/regress_minheap.c test/regress-regress_minheap.obj: test/regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_minheap.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_minheap.Tpo -c -o test/regress-regress_minheap.obj `if test -f 'test/regress_minheap.c'; then $(CYGPATH_W) 'test/regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_minheap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_minheap.Tpo test/$(DEPDIR)/regress-regress_minheap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_minheap.c' object='test/regress-regress_minheap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_minheap.obj `if test -f 'test/regress_minheap.c'; then $(CYGPATH_W) 'test/regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_minheap.c'; fi` test/regress-regress_rpc.o: test/regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_rpc.o -MD -MP -MF test/$(DEPDIR)/regress-regress_rpc.Tpo -c -o test/regress-regress_rpc.o `test -f 'test/regress_rpc.c' || echo '$(srcdir)/'`test/regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_rpc.Tpo test/$(DEPDIR)/regress-regress_rpc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_rpc.c' object='test/regress-regress_rpc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_rpc.o `test -f 'test/regress_rpc.c' || echo '$(srcdir)/'`test/regress_rpc.c test/regress-regress_rpc.obj: test/regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_rpc.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_rpc.Tpo -c -o test/regress-regress_rpc.obj `if test -f 'test/regress_rpc.c'; then $(CYGPATH_W) 'test/regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_rpc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_rpc.Tpo test/$(DEPDIR)/regress-regress_rpc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_rpc.c' object='test/regress-regress_rpc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_rpc.obj `if test -f 'test/regress_rpc.c'; then $(CYGPATH_W) 'test/regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_rpc.c'; fi` test/regress-regress_testutils.o: test/regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_testutils.o -MD -MP -MF test/$(DEPDIR)/regress-regress_testutils.Tpo -c -o test/regress-regress_testutils.o `test -f 'test/regress_testutils.c' || echo '$(srcdir)/'`test/regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_testutils.Tpo test/$(DEPDIR)/regress-regress_testutils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_testutils.c' object='test/regress-regress_testutils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_testutils.o `test -f 'test/regress_testutils.c' || echo '$(srcdir)/'`test/regress_testutils.c test/regress-regress_testutils.obj: test/regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_testutils.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_testutils.Tpo -c -o test/regress-regress_testutils.obj `if test -f 'test/regress_testutils.c'; then $(CYGPATH_W) 'test/regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_testutils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_testutils.Tpo test/$(DEPDIR)/regress-regress_testutils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_testutils.c' object='test/regress-regress_testutils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_testutils.obj `if test -f 'test/regress_testutils.c'; then $(CYGPATH_W) 'test/regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_testutils.c'; fi` test/regress-regress_util.o: test/regress_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_util.o -MD -MP -MF test/$(DEPDIR)/regress-regress_util.Tpo -c -o test/regress-regress_util.o `test -f 'test/regress_util.c' || echo '$(srcdir)/'`test/regress_util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_util.Tpo test/$(DEPDIR)/regress-regress_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_util.c' object='test/regress-regress_util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_util.o `test -f 'test/regress_util.c' || echo '$(srcdir)/'`test/regress_util.c test/regress-regress_util.obj: test/regress_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_util.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_util.Tpo -c -o test/regress-regress_util.obj `if test -f 'test/regress_util.c'; then $(CYGPATH_W) 'test/regress_util.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_util.Tpo test/$(DEPDIR)/regress-regress_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_util.c' object='test/regress-regress_util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_util.obj `if test -f 'test/regress_util.c'; then $(CYGPATH_W) 'test/regress_util.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_util.c'; fi` test/regress-tinytest.o: test/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-tinytest.o -MD -MP -MF test/$(DEPDIR)/regress-tinytest.Tpo -c -o test/regress-tinytest.o `test -f 'test/tinytest.c' || echo '$(srcdir)/'`test/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-tinytest.Tpo test/$(DEPDIR)/regress-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/tinytest.c' object='test/regress-tinytest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-tinytest.o `test -f 'test/tinytest.c' || echo '$(srcdir)/'`test/tinytest.c test/regress-tinytest.obj: test/tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-tinytest.obj -MD -MP -MF test/$(DEPDIR)/regress-tinytest.Tpo -c -o test/regress-tinytest.obj `if test -f 'test/tinytest.c'; then $(CYGPATH_W) 'test/tinytest.c'; else $(CYGPATH_W) '$(srcdir)/test/tinytest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-tinytest.Tpo test/$(DEPDIR)/regress-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/tinytest.c' object='test/regress-tinytest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-tinytest.obj `if test -f 'test/tinytest.c'; then $(CYGPATH_W) 'test/tinytest.c'; else $(CYGPATH_W) '$(srcdir)/test/tinytest.c'; fi` test/regress-regress_thread.o: test/regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_thread.o -MD -MP -MF test/$(DEPDIR)/regress-regress_thread.Tpo -c -o test/regress-regress_thread.o `test -f 'test/regress_thread.c' || echo '$(srcdir)/'`test/regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_thread.Tpo test/$(DEPDIR)/regress-regress_thread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_thread.c' object='test/regress-regress_thread.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_thread.o `test -f 'test/regress_thread.c' || echo '$(srcdir)/'`test/regress_thread.c test/regress-regress_thread.obj: test/regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_thread.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_thread.Tpo -c -o test/regress-regress_thread.obj `if test -f 'test/regress_thread.c'; then $(CYGPATH_W) 'test/regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_thread.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_thread.Tpo test/$(DEPDIR)/regress-regress_thread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_thread.c' object='test/regress-regress_thread.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_thread.obj `if test -f 'test/regress_thread.c'; then $(CYGPATH_W) 'test/regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_thread.c'; fi` test/regress-regress_zlib.o: test/regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_zlib.o -MD -MP -MF test/$(DEPDIR)/regress-regress_zlib.Tpo -c -o test/regress-regress_zlib.o `test -f 'test/regress_zlib.c' || echo '$(srcdir)/'`test/regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_zlib.Tpo test/$(DEPDIR)/regress-regress_zlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_zlib.c' object='test/regress-regress_zlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_zlib.o `test -f 'test/regress_zlib.c' || echo '$(srcdir)/'`test/regress_zlib.c test/regress-regress_zlib.obj: test/regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_zlib.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_zlib.Tpo -c -o test/regress-regress_zlib.obj `if test -f 'test/regress_zlib.c'; then $(CYGPATH_W) 'test/regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_zlib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_zlib.Tpo test/$(DEPDIR)/regress-regress_zlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_zlib.c' object='test/regress-regress_zlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_zlib.obj `if test -f 'test/regress_zlib.c'; then $(CYGPATH_W) 'test/regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_zlib.c'; fi` test/regress-regress_iocp.o: test/regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_iocp.o -MD -MP -MF test/$(DEPDIR)/regress-regress_iocp.Tpo -c -o test/regress-regress_iocp.o `test -f 'test/regress_iocp.c' || echo '$(srcdir)/'`test/regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_iocp.Tpo test/$(DEPDIR)/regress-regress_iocp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_iocp.c' object='test/regress-regress_iocp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_iocp.o `test -f 'test/regress_iocp.c' || echo '$(srcdir)/'`test/regress_iocp.c test/regress-regress_iocp.obj: test/regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_iocp.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_iocp.Tpo -c -o test/regress-regress_iocp.obj `if test -f 'test/regress_iocp.c'; then $(CYGPATH_W) 'test/regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_iocp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_iocp.Tpo test/$(DEPDIR)/regress-regress_iocp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_iocp.c' object='test/regress-regress_iocp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_iocp.obj `if test -f 'test/regress_iocp.c'; then $(CYGPATH_W) 'test/regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_iocp.c'; fi` test/regress-regress_ssl.o: test/regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_ssl.o -MD -MP -MF test/$(DEPDIR)/regress-regress_ssl.Tpo -c -o test/regress-regress_ssl.o `test -f 'test/regress_ssl.c' || echo '$(srcdir)/'`test/regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_ssl.Tpo test/$(DEPDIR)/regress-regress_ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_ssl.c' object='test/regress-regress_ssl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_ssl.o `test -f 'test/regress_ssl.c' || echo '$(srcdir)/'`test/regress_ssl.c test/regress-regress_ssl.obj: test/regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test/regress-regress_ssl.obj -MD -MP -MF test/$(DEPDIR)/regress-regress_ssl.Tpo -c -o test/regress-regress_ssl.obj `if test -f 'test/regress_ssl.c'; then $(CYGPATH_W) 'test/regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_ssl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) test/$(DEPDIR)/regress-regress_ssl.Tpo test/$(DEPDIR)/regress-regress_ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test/regress_ssl.c' object='test/regress-regress_ssl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test/regress-regress_ssl.obj `if test -f 'test/regress_ssl.c'; then $(CYGPATH_W) 'test/regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/test/regress_ssl.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf sample/.libs sample/_libs -rm -rf test/.libs test/_libs distclean-libtool: -rm -f libtool config.lt install-man3: $(man3_MANS) @$(NORMAL_INSTALL) @list1='$(man3_MANS)'; \ list2=''; \ test -n "$(man3dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.3[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ done; } uninstall-man3: @$(NORMAL_UNINSTALL) @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) install-include_event2HEADERS: $(include_event2_HEADERS) @$(NORMAL_INSTALL) @list='$(include_event2_HEADERS)'; test -n "$(include_event2dir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(include_event2dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(include_event2dir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_event2dir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_event2dir)" || exit $$?; \ done uninstall-include_event2HEADERS: @$(NORMAL_UNINSTALL) @list='$(include_event2_HEADERS)'; test -n "$(include_event2dir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(include_event2dir)'; $(am__uninstall_files_from_dir) install-nodist_include_event2HEADERS: $(nodist_include_event2_HEADERS) @$(NORMAL_INSTALL) @list='$(nodist_include_event2_HEADERS)'; test -n "$(include_event2dir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(include_event2dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(include_event2dir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(include_event2dir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(include_event2dir)" || exit $$?; \ done uninstall-nodist_include_event2HEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_include_event2_HEADERS)'; test -n "$(include_event2dir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(include_event2dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? test_runner_epoll.log: test_runner_epoll @p='test_runner_epoll'; \ b='test_runner_epoll'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_select.log: test_runner_select @p='test_runner_select'; \ b='test_runner_select'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_kqueue.log: test_runner_kqueue @p='test_runner_kqueue'; \ b='test_runner_kqueue'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_evport.log: test_runner_evport @p='test_runner_evport'; \ b='test_runner_evport'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_devpoll.log: test_runner_devpoll @p='test_runner_devpoll'; \ b='test_runner_devpoll'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_poll.log: test_runner_poll @p='test_runner_poll'; \ b='test_runner_poll'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_win32.log: test_runner_win32 @p='test_runner_win32'; \ b='test_runner_win32'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_timerfd.log: test_runner_timerfd @p='test_runner_timerfd'; \ b='test_runner_timerfd'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_changelist.log: test_runner_changelist @p='test_runner_changelist'; \ b='test_runner_changelist'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test_runner_timerfd_changelist.log: test_runner_timerfd_changelist @p='test_runner_timerfd_changelist'; \ b='test_runner_timerfd_changelist'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) $(MANS) $(DATA) \ $(HEADERS) config.h evconfig-private.h install-EXTRAPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(include_event2dir)" "$(DESTDIR)$(include_event2dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f sample/$(DEPDIR)/$(am__dirstamp) -rm -f sample/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) @ENABLE_DOXYGEN_FALSE@clean-local: @ENABLE_DOXYGEN_FALSE@install-data-local: @ENABLE_DOXYGEN_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f $(DEPDIR)/epoll_sub.Plo -rm -f ./$(DEPDIR)/buffer.Plo -rm -f ./$(DEPDIR)/buffer_iocp.Plo -rm -f ./$(DEPDIR)/bufferevent.Plo -rm -f ./$(DEPDIR)/bufferevent_async.Plo -rm -f ./$(DEPDIR)/bufferevent_filter.Plo -rm -f ./$(DEPDIR)/bufferevent_pair.Plo -rm -f ./$(DEPDIR)/bufferevent_ratelim.Plo -rm -f ./$(DEPDIR)/bufferevent_sock.Plo -rm -f ./$(DEPDIR)/devpoll.Plo -rm -f ./$(DEPDIR)/epoll.Plo -rm -f ./$(DEPDIR)/evdns.Plo -rm -f ./$(DEPDIR)/event.Plo -rm -f ./$(DEPDIR)/event_iocp.Plo -rm -f ./$(DEPDIR)/event_tagging.Plo -rm -f ./$(DEPDIR)/evmap.Plo -rm -f ./$(DEPDIR)/evport.Plo -rm -f ./$(DEPDIR)/evrpc.Plo -rm -f ./$(DEPDIR)/evthread.Plo -rm -f ./$(DEPDIR)/evthread_pthread.Plo -rm -f ./$(DEPDIR)/evthread_win32.Plo -rm -f ./$(DEPDIR)/evutil.Plo -rm -f ./$(DEPDIR)/evutil_rand.Plo -rm -f ./$(DEPDIR)/evutil_time.Plo -rm -f ./$(DEPDIR)/http.Plo -rm -f ./$(DEPDIR)/kqueue.Plo -rm -f ./$(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Plo -rm -f ./$(DEPDIR)/listener.Plo -rm -f ./$(DEPDIR)/log.Plo -rm -f ./$(DEPDIR)/poll.Plo -rm -f ./$(DEPDIR)/select.Plo -rm -f ./$(DEPDIR)/signal.Plo -rm -f ./$(DEPDIR)/strlcpy.Plo -rm -f ./$(DEPDIR)/win32select.Plo -rm -f sample/$(DEPDIR)/dns-example.Po -rm -f sample/$(DEPDIR)/event-read-fifo.Po -rm -f sample/$(DEPDIR)/hello-world.Po -rm -f sample/$(DEPDIR)/http-connect.Po -rm -f sample/$(DEPDIR)/http-server.Po -rm -f sample/$(DEPDIR)/https_client-hostcheck.Po -rm -f sample/$(DEPDIR)/https_client-https-client.Po -rm -f sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po -rm -f sample/$(DEPDIR)/le_proxy-le-proxy.Po -rm -f sample/$(DEPDIR)/signal-test.Po -rm -f sample/$(DEPDIR)/time-test.Po -rm -f test/$(DEPDIR)/bench.Po -rm -f test/$(DEPDIR)/bench_cascade.Po -rm -f test/$(DEPDIR)/bench_http.Po -rm -f test/$(DEPDIR)/bench_httpclient.Po -rm -f test/$(DEPDIR)/regress-regress.Po -rm -f test/$(DEPDIR)/regress-regress.gen.Po -rm -f test/$(DEPDIR)/regress-regress_buffer.Po -rm -f test/$(DEPDIR)/regress-regress_bufferevent.Po -rm -f test/$(DEPDIR)/regress-regress_dns.Po -rm -f test/$(DEPDIR)/regress-regress_et.Po -rm -f test/$(DEPDIR)/regress-regress_finalize.Po -rm -f test/$(DEPDIR)/regress-regress_http.Po -rm -f test/$(DEPDIR)/regress-regress_iocp.Po -rm -f test/$(DEPDIR)/regress-regress_listener.Po -rm -f test/$(DEPDIR)/regress-regress_main.Po -rm -f test/$(DEPDIR)/regress-regress_minheap.Po -rm -f test/$(DEPDIR)/regress-regress_rpc.Po -rm -f test/$(DEPDIR)/regress-regress_ssl.Po -rm -f test/$(DEPDIR)/regress-regress_testutils.Po -rm -f test/$(DEPDIR)/regress-regress_thread.Po -rm -f test/$(DEPDIR)/regress-regress_util.Po -rm -f test/$(DEPDIR)/regress-regress_zlib.Po -rm -f test/$(DEPDIR)/regress-tinytest.Po -rm -f test/$(DEPDIR)/test-changelist.Po -rm -f test/$(DEPDIR)/test-closed.Po -rm -f test/$(DEPDIR)/test-dumpevents.Po -rm -f test/$(DEPDIR)/test-eof.Po -rm -f test/$(DEPDIR)/test-fdleak.Po -rm -f test/$(DEPDIR)/test-init.Po -rm -f test/$(DEPDIR)/test-ratelim.Po -rm -f test/$(DEPDIR)/test-time.Po -rm -f test/$(DEPDIR)/test-weof.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-includeHEADERS \ install-include_event2HEADERS install-man \ install-nodist_include_event2HEADERS install-pkgconfigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-dist_binSCRIPTS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man3 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f $(DEPDIR)/epoll_sub.Plo -rm -f ./$(DEPDIR)/buffer.Plo -rm -f ./$(DEPDIR)/buffer_iocp.Plo -rm -f ./$(DEPDIR)/bufferevent.Plo -rm -f ./$(DEPDIR)/bufferevent_async.Plo -rm -f ./$(DEPDIR)/bufferevent_filter.Plo -rm -f ./$(DEPDIR)/bufferevent_pair.Plo -rm -f ./$(DEPDIR)/bufferevent_ratelim.Plo -rm -f ./$(DEPDIR)/bufferevent_sock.Plo -rm -f ./$(DEPDIR)/devpoll.Plo -rm -f ./$(DEPDIR)/epoll.Plo -rm -f ./$(DEPDIR)/evdns.Plo -rm -f ./$(DEPDIR)/event.Plo -rm -f ./$(DEPDIR)/event_iocp.Plo -rm -f ./$(DEPDIR)/event_tagging.Plo -rm -f ./$(DEPDIR)/evmap.Plo -rm -f ./$(DEPDIR)/evport.Plo -rm -f ./$(DEPDIR)/evrpc.Plo -rm -f ./$(DEPDIR)/evthread.Plo -rm -f ./$(DEPDIR)/evthread_pthread.Plo -rm -f ./$(DEPDIR)/evthread_win32.Plo -rm -f ./$(DEPDIR)/evutil.Plo -rm -f ./$(DEPDIR)/evutil_rand.Plo -rm -f ./$(DEPDIR)/evutil_time.Plo -rm -f ./$(DEPDIR)/http.Plo -rm -f ./$(DEPDIR)/kqueue.Plo -rm -f ./$(DEPDIR)/libevent_openssl_la-bufferevent_openssl.Plo -rm -f ./$(DEPDIR)/listener.Plo -rm -f ./$(DEPDIR)/log.Plo -rm -f ./$(DEPDIR)/poll.Plo -rm -f ./$(DEPDIR)/select.Plo -rm -f ./$(DEPDIR)/signal.Plo -rm -f ./$(DEPDIR)/strlcpy.Plo -rm -f ./$(DEPDIR)/win32select.Plo -rm -f sample/$(DEPDIR)/dns-example.Po -rm -f sample/$(DEPDIR)/event-read-fifo.Po -rm -f sample/$(DEPDIR)/hello-world.Po -rm -f sample/$(DEPDIR)/http-connect.Po -rm -f sample/$(DEPDIR)/http-server.Po -rm -f sample/$(DEPDIR)/https_client-hostcheck.Po -rm -f sample/$(DEPDIR)/https_client-https-client.Po -rm -f sample/$(DEPDIR)/https_client-openssl_hostname_validation.Po -rm -f sample/$(DEPDIR)/le_proxy-le-proxy.Po -rm -f sample/$(DEPDIR)/signal-test.Po -rm -f sample/$(DEPDIR)/time-test.Po -rm -f test/$(DEPDIR)/bench.Po -rm -f test/$(DEPDIR)/bench_cascade.Po -rm -f test/$(DEPDIR)/bench_http.Po -rm -f test/$(DEPDIR)/bench_httpclient.Po -rm -f test/$(DEPDIR)/regress-regress.Po -rm -f test/$(DEPDIR)/regress-regress.gen.Po -rm -f test/$(DEPDIR)/regress-regress_buffer.Po -rm -f test/$(DEPDIR)/regress-regress_bufferevent.Po -rm -f test/$(DEPDIR)/regress-regress_dns.Po -rm -f test/$(DEPDIR)/regress-regress_et.Po -rm -f test/$(DEPDIR)/regress-regress_finalize.Po -rm -f test/$(DEPDIR)/regress-regress_http.Po -rm -f test/$(DEPDIR)/regress-regress_iocp.Po -rm -f test/$(DEPDIR)/regress-regress_listener.Po -rm -f test/$(DEPDIR)/regress-regress_main.Po -rm -f test/$(DEPDIR)/regress-regress_minheap.Po -rm -f test/$(DEPDIR)/regress-regress_rpc.Po -rm -f test/$(DEPDIR)/regress-regress_ssl.Po -rm -f test/$(DEPDIR)/regress-regress_testutils.Po -rm -f test/$(DEPDIR)/regress-regress_thread.Po -rm -f test/$(DEPDIR)/regress-regress_util.Po -rm -f test/$(DEPDIR)/regress-regress_zlib.Po -rm -f test/$(DEPDIR)/regress-tinytest.Po -rm -f test/$(DEPDIR)/test-changelist.Po -rm -f test/$(DEPDIR)/test-closed.Po -rm -f test/$(DEPDIR)/test-dumpevents.Po -rm -f test/$(DEPDIR)/test-eof.Po -rm -f test/$(DEPDIR)/test-fdleak.Po -rm -f test/$(DEPDIR)/test-init.Po -rm -f test/$(DEPDIR)/test-ratelim.Po -rm -f test/$(DEPDIR)/test-time.Po -rm -f test/$(DEPDIR)/test-weof.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ uninstall-include_event2HEADERS uninstall-libLTLIBRARIES \ uninstall-local uninstall-man \ uninstall-nodist_include_event2HEADERS uninstall-pkgconfigDATA uninstall-man: uninstall-man3 .MAKE: all check check-am install install-am install-exec \ install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \ check-TESTS check-am clean clean-cscope clean-generic \ clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS cscope \ cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ dist-zstd distcheck distclean distclean-compile \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-data-local \ install-dist_binSCRIPTS install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-includeHEADERS install-include_event2HEADERS \ install-info install-info-am install-libLTLIBRARIES \ install-man install-man3 install-nodist_include_event2HEADERS \ install-pdf install-pdf-am install-pkgconfigDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \ uninstall uninstall-am uninstall-dist_binSCRIPTS \ uninstall-includeHEADERS uninstall-include_event2HEADERS \ uninstall-libLTLIBRARIES uninstall-local uninstall-man \ uninstall-man3 uninstall-nodist_include_event2HEADERS \ uninstall-pkgconfigDATA .PRECIOUS: Makefile $(SAMPLES) : libevent.la test_runner_epoll: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b EPOLL test_runner_select: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b SELECT test_runner_kqueue: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b KQUEUE test_runner_evport: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b EVPORT test_runner_devpoll: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b DEVPOLL test_runner_poll: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b POLL test_runner_win32: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b WIN32 test_runner_timerfd: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b "" -t test_runner_changelist: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b "" -c test_runner_timerfd_changelist: $(top_srcdir)/test/test.sh $(top_srcdir)/test/test.sh -b "" -T test/regress.gen.c test/regress.gen.h: test/rpcgen-attempted test/rpcgen-attempted: test/regress.rpc event_rpcgen.py test/rpcgen_wrapper.sh $(AM_V_GEN)date -u > $@ $(AM_V_at)if $(srcdir)/test/rpcgen_wrapper.sh $(srcdir)/test; then \ true; \ else \ echo "No Python installed; stubbing out RPC test." >&2; \ echo " "> test/regress.gen.c; \ echo "#define NO_PYTHON_EXISTS" > test/regress.gen.h; \ fi $(TESTPROGRAMS) : libevent.la include/event2/event-config.h: config.h make-event-config.sed $(AM_V_GEN)test -d include/event2 || $(MKDIR_P) include/event2 $(AM_V_at)$(SED) -f $(srcdir)/make-event-config.sed < config.h > $@T $(AM_V_at)mv -f $@T $@ verify: check # Add all needed rules defined in ax_prog_doxygen.m4 @ENABLE_DOXYGEN_TRUE@@DX_RULES@ # Use 'make clean' to clean docs generated by doxygen. @ENABLE_DOXYGEN_TRUE@clean-local: @ENABLE_DOXYGEN_TRUE@ -rm -rf $(DX_CLEANFILES) @ENABLE_DOXYGEN_TRUE@$(man3_MANS): doxygen-doc # Rules for installing docs generated by doxygen into $(htmldir), # The typical value of $(htmldir) is '/usr/local/share/doc/$(PACKAGE)' @ENABLE_DOXYGEN_TRUE@install-data-local: @ENABLE_DOXYGEN_TRUE@ @if ! test -d "$(DESTDIR)$(htmldir)"; then \ @ENABLE_DOXYGEN_TRUE@ echo "$(mkinstalldirs) '$(DESTDIR)$(htmldir)'"; \ @ENABLE_DOXYGEN_TRUE@ $(mkinstalldirs) '$(DESTDIR)$(htmldir)'; \ @ENABLE_DOXYGEN_TRUE@ fi @ENABLE_DOXYGEN_TRUE@ @for d in $(docdirs); do \ @ENABLE_DOXYGEN_TRUE@ echo "cp -pR $$d '$(DESTDIR)$(htmldir)/'"; \ @ENABLE_DOXYGEN_TRUE@ cp -pR $$d '$(DESTDIR)$(htmldir)/'; \ @ENABLE_DOXYGEN_TRUE@ done # Rules for uninstalling docs generated by doxygen from $(htmldir) @ENABLE_DOXYGEN_TRUE@uninstall-local: @ENABLE_DOXYGEN_TRUE@ @for d in $(docdirs); do \ @ENABLE_DOXYGEN_TRUE@ d=`basename $$d`; \ @ENABLE_DOXYGEN_TRUE@ echo "test ! -d '$(DESTDIR)$(htmldir)/'$$d || \ @ENABLE_DOXYGEN_TRUE@ { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \ @ENABLE_DOXYGEN_TRUE@ rm -rf '$(DESTDIR)$(htmldir)/'$$d; }"; \ @ENABLE_DOXYGEN_TRUE@ test ! -d '$(DESTDIR)$(htmldir)/'$$d || \ @ENABLE_DOXYGEN_TRUE@ { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \ @ENABLE_DOXYGEN_TRUE@ rm -rf '$(DESTDIR)$(htmldir)/'$$d; }; \ @ENABLE_DOXYGEN_TRUE@ done @ENABLE_DOXYGEN_TRUE@ rmdir "$(DESTDIR)$(htmldir)/" || true @ENABLE_DOXYGEN_TRUE@doxygen: doxygen-doc # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: lldpd-1.0.13/libevent/changelist-internal.h0000644000076400001440000001102314111362570021302 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CHANGELIST_INTERNAL_H_INCLUDED_ #define CHANGELIST_INTERNAL_H_INCLUDED_ /* A "changelist" is a list of all the fd status changes that should be made between calls to the backend's dispatch function. There are a few reasons that a backend would want to queue changes like this rather than processing them immediately. 1) Sometimes applications will add and delete the same event more than once between calls to dispatch. Processing these changes immediately is needless, and potentially expensive (especially if we're on a system that makes one syscall per changed event). 2) Sometimes we can coalesce multiple changes on the same fd into a single syscall if we know about them in advance. For example, epoll can do an add and a delete at the same time, but only if we have found out about both of them before we tell epoll. 3) Sometimes adding an event that we immediately delete can cause unintended consequences: in kqueue, this makes pending events get reported spuriously. */ #include "event2/util.h" /** Represents a */ struct event_change { /** The fd or signal whose events are to be changed */ evutil_socket_t fd; /* The events that were enabled on the fd before any of these changes were made. May include EV_READ or EV_WRITE. */ short old_events; /* The changes that we want to make in reading and writing on this fd. * If this is a signal, then read_change has EV_CHANGE_SIGNAL set, * and write_change is unused. */ ev_uint8_t read_change; ev_uint8_t write_change; ev_uint8_t close_change; }; /* Flags for read_change and write_change. */ /* If set, add the event. */ #define EV_CHANGE_ADD 0x01 /* If set, delete the event. Exclusive with EV_CHANGE_ADD */ #define EV_CHANGE_DEL 0x02 /* If set, this event refers a signal, not an fd. */ #define EV_CHANGE_SIGNAL EV_SIGNAL /* Set for persistent events. Currently not used. */ #define EV_CHANGE_PERSIST EV_PERSIST /* Set for adding edge-triggered events. */ #define EV_CHANGE_ET EV_ET /* The value of fdinfo_size that a backend should use if it is letting * changelist handle its add and delete functions. */ #define EVENT_CHANGELIST_FDINFO_SIZE sizeof(int) /** Set up the data fields in a changelist. */ void event_changelist_init_(struct event_changelist *changelist); /** Remove every change in the changelist, and make corresponding changes * in the event maps in the base. This function is generally used right * after making all the changes in the changelist. */ void event_changelist_remove_all_(struct event_changelist *changelist, struct event_base *base); /** Free all memory held in a changelist. */ void event_changelist_freemem_(struct event_changelist *changelist); /** Implementation of eventop_add that queues the event in a changelist. */ int event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events, void *p); /** Implementation of eventop_del that queues the event in a changelist. */ int event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events, void *p); #endif lldpd-1.0.13/libevent/configure.ac0000644000076400001440000006202214111362570017471 0ustar00bernatusers00000000000000dnl Copyright 2000-2007 Niels Provos dnl Copyright 2007-2012 Niels Provos and Nick Mathewson dnl dnl See LICENSE for copying information. dnl dnl Original version Dug Song AC_INIT(libevent,2.1.12-stable) AC_PREREQ(2.67) AC_CONFIG_SRCDIR(event.c) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE dnl AM_SILENT_RULES req. automake 1.11. [no] defaults V=1 AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS(config.h evconfig-private.h:evconfig-private.h.in) AC_DEFINE(NUMERIC_VERSION, 0x02010c00, [Numeric representation of the version]) dnl Initialize prefix. AC_PREFIX_DEFAULT([/usr/local]) dnl Try and get a full POSIX environment on obscure systems AC_USE_SYSTEM_EXTENSIONS AC_CANONICAL_BUILD AC_CANONICAL_HOST dnl the 'build' machine is where we run configure and compile dnl the 'host' machine is where the resulting stuff runs. #case "$host_os" in # # osf5*) # CFLAGS="$CFLAGS -D_OSF_SOURCE" # ;; #esac dnl Checks for programs. AM_PROG_CC_C_O AC_PROG_INSTALL AC_PROG_LN_S # AC_PROG_MKDIR_P - $(MKDIR_P) should be defined by AM_INIT_AUTOMAKE AC_PROG_SED AC_PROG_GCC_TRADITIONAL # We need to test for at least gcc 2.95 here, because older versions don't # have -fno-strict-aliasing AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) #error #endif])], have_gcc295=yes, have_gcc295=no) if test "$GCC" = "yes" ; then # Enable many gcc warnings by default... CFLAGS="$CFLAGS -Wall" # And disable the strict-aliasing optimization, since it breaks # our sockaddr-handling code in strange ways. if test x$have_gcc295 = xyes; then CFLAGS="$CFLAGS -fno-strict-aliasing" fi fi # OS X Lion started deprecating the system openssl. Let's just disable # all deprecation warnings on OS X; but do so only for gcc... if test "$GCC" = "yes" ; then case "$host_os" in darwin*) CFLAGS="$CFLAGS -Wno-deprecated-declarations" ;; esac fi AC_ARG_ENABLE(gcc-warnings, AS_HELP_STRING(--disable-gcc-warnings, disable verbose warnings with GCC)) AC_ARG_ENABLE(gcc-hardening, AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks), [if test x$enableval = xyes; then CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all" CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector" CFLAGS="$CFLAGS --param ssp-buffer-size=1" fi]) AC_ARG_ENABLE(thread-support, AS_HELP_STRING(--disable-thread-support, disable support for threading), [], [enable_thread_support=yes]) AC_ARG_ENABLE(malloc-replacement, AS_HELP_STRING(--disable-malloc-replacement, disable support for replacing the memory mgt functions), [], [enable_malloc_replacement=yes]) AC_ARG_ENABLE(openssl, AS_HELP_STRING(--disable-openssl, disable support for openssl encryption), [], [enable_openssl=yes]) AC_ARG_ENABLE(debug-mode, AS_HELP_STRING(--disable-debug-mode, disable support for running in debug mode), [], [enable_debug_mode=yes]) AC_ARG_ENABLE([libevent-install], AS_HELP_STRING([--disable-libevent-install, disable installation of libevent]), [], [enable_libevent_install=yes]) AC_ARG_ENABLE([libevent-regress], AS_HELP_STRING([--disable-libevent-regress, skip regress in make check]), [], [enable_libevent_regress=yes]) AC_ARG_ENABLE([samples], AS_HELP_STRING([--disable-samples, skip building of sample programs]), [], [enable_samples=yes]) AC_ARG_ENABLE([function-sections], AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]), [], [enable_function_sections=no]) AC_ARG_ENABLE([verbose-debug], AS_HELP_STRING([--enable-verbose-debug, verbose debug logging]), [], [enable_verbose_debug=no]) AC_ARG_ENABLE([clock-gettime], AS_HELP_STRING(--disable-clock-gettime, do not use clock_gettime even if it is available), [], [enable_clock_gettime=yes]) LT_PREREQ([2.4.2]) LT_INIT dnl Uncomment "AC_DISABLE_SHARED" to make shared libraries not get dnl built by default. You can also turn shared libs on and off from dnl the command line with --enable-shared and --disable-shared. dnl AC_DISABLE_SHARED AC_SUBST(LIBTOOL_DEPS) AM_CONDITIONAL([BUILD_SAMPLES], [test "$enable_samples" = "yes"]) AM_CONDITIONAL([BUILD_REGRESS], [test "$enable_libevent_regress" = "yes"]) dnl Checks for libraries. AC_SEARCH_LIBS([inet_ntoa], [nsl]) AC_SEARCH_LIBS([socket], [socket]) AC_SEARCH_LIBS([inet_aton], [resolv]) if test "x$enable_clock_gettime" = "xyes"; then AC_SEARCH_LIBS([clock_gettime], [rt]) AC_CHECK_FUNCS([clock_gettime]) fi AC_SEARCH_LIBS([sendfile], [sendfile]) dnl - check if the macro _WIN32 is defined on this compiler. dnl - (this is how we check for a windows compiler) AC_MSG_CHECKING(for WIN32) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [ #ifndef _WIN32 die horribly #endif ] )], [bwin32=true; AC_MSG_RESULT(yes)], [bwin32=false; AC_MSG_RESULT(no)] ) dnl - check if the macro __midipix__ is defined on this compiler. dnl - (this is how we check for a midipix version of GCC) AC_MSG_CHECKING(for MIDIPIX) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [ #ifndef __midipix__ die horribly #endif ] )], [midipix=true; AC_MSG_RESULT(yes)], [midipix=false; AC_MSG_RESULT(no)] ) dnl - check if the macro __CYGWIN__ is defined on this compiler. dnl - (this is how we check for a cygwin version of GCC) AC_MSG_CHECKING(for CYGWIN) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [ #ifndef __CYGWIN__ die horribly #endif ] )], [cygwin=true; AC_MSG_RESULT(yes)], [cygwin=false; AC_MSG_RESULT(no)] ) AC_CHECK_HEADERS([zlib.h]) if test "x$ac_cv_header_zlib_h" = "xyes"; then dnl Determine if we have zlib for regression tests dnl Don't put this one in LIBS save_LIBS="$LIBS" LIBS="" ZLIB_LIBS="" have_zlib=no AC_SEARCH_LIBS([inflateEnd], [z], [have_zlib=yes ZLIB_LIBS="$LIBS" AC_DEFINE(HAVE_LIBZ, 1, [Define if the system has zlib])]) LIBS="$save_LIBS" AC_SUBST(ZLIB_LIBS) fi AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" = "yes"]) dnl See if we have openssl. This doesn't go in LIBS either. if test "$bwin32" = true; then EV_LIB_WS32=-lws2_32 EV_LIB_GDI=-lgdi32 else EV_LIB_WS32= EV_LIB_GDI= fi AC_SUBST(EV_LIB_WS32) AC_SUBST(EV_LIB_GDI) AC_SUBST(OPENSSL_LIBADD) AC_SYS_LARGEFILE LIBEVENT_OPENSSL dnl Checks for header files. AC_CHECK_HEADERS([ \ arpa/inet.h \ fcntl.h \ ifaddrs.h \ mach/mach_time.h \ mach/mach.h \ netdb.h \ netinet/in.h \ netinet/in6.h \ netinet/tcp.h \ sys/un.h \ poll.h \ port.h \ stdarg.h \ stddef.h \ sys/devpoll.h \ sys/epoll.h \ sys/event.h \ sys/eventfd.h \ sys/ioctl.h \ sys/mman.h \ sys/param.h \ sys/queue.h \ sys/resource.h \ sys/select.h \ sys/sendfile.h \ sys/socket.h \ sys/stat.h \ sys/time.h \ sys/timerfd.h \ sys/uio.h \ sys/wait.h \ sys/random.h \ errno.h \ afunix.h \ ]) case "${host_os}" in linux*) ;; *) AC_CHECK_HEADERS(sys/sysctl.h, [], [], [ #ifdef HAVE_SYS_PARAM_H #include #endif ]) esac if test "x$ac_cv_header_sys_queue_h" = "xyes"; then AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_EGREP_CPP(yes, [ #include #ifdef TAILQ_FOREACH yes #endif ], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_TAILQFOREACH, 1, [Define if TAILQ_FOREACH is defined in ])], AC_MSG_RESULT(no) ) fi if test "x$ac_cv_header_sys_time_h" = "xyes"; then AC_MSG_CHECKING(for timeradd in sys/time.h) AC_EGREP_CPP(yes, [ #include #ifdef timeradd yes #endif ], [ AC_DEFINE(HAVE_TIMERADD, 1, [Define if timeradd is defined in ]) AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) ) fi if test "x$ac_cv_header_sys_time_h" = "xyes"; then AC_MSG_CHECKING(for timercmp in sys/time.h) AC_EGREP_CPP(yes, [ #include #ifdef timercmp yes #endif ], [ AC_DEFINE(HAVE_TIMERCMP, 1, [Define if timercmp is defined in ]) AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) ) fi if test "x$ac_cv_header_sys_time_h" = "xyes"; then AC_MSG_CHECKING(for timerclear in sys/time.h) AC_EGREP_CPP(yes, [ #include #ifdef timerclear yes #endif ], [ AC_DEFINE(HAVE_TIMERCLEAR, 1, [Define if timerclear is defined in ]) AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) ) fi if test "x$ac_cv_header_sys_time_h" = "xyes"; then AC_MSG_CHECKING(for timerisset in sys/time.h) AC_EGREP_CPP(yes, [ #include #ifdef timerisset yes #endif ], [ AC_DEFINE(HAVE_TIMERISSET, 1, [Define if timerisset is defined in ]) AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) ) fi if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then AC_CHECK_DECLS([CTL_KERN, KERN_ARND], [], [], [[#include #include ]] ) fi AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue) AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue) AM_CONDITIONAL(BUILD_MIDIPIX, test x$midipix = xtrue) AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue || test x$midipix = xtrue) if test x$bwin32 = xtrue; then AC_HAVE_LIBRARY([ws2_32]) fi dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_HEADER_TIME dnl Checks for library functions. AC_CHECK_FUNCS([ \ accept4 \ arc4random \ arc4random_buf \ arc4random_addrandom \ eventfd \ epoll_create1 \ fcntl \ getegid \ geteuid \ getifaddrs \ gettimeofday \ issetugid \ mach_absolute_time \ mmap \ nanosleep \ pipe \ pipe2 \ putenv \ sendfile \ setenv \ setrlimit \ sigaction \ signal \ splice \ strlcpy \ strsep \ strtok_r \ strtoll \ sysctl \ timerfd_create \ umask \ unsetenv \ usleep \ vasprintf \ getrandom \ ]) AS_IF([test x$bwin32 = xtrue], AC_CHECK_FUNCS(_gmtime64_s, , [AC_CHECK_FUNCS(_gmtime64)]) ) AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno]) m4_define([funcstochk], [getnameinfo getprotobynumber getservbyname inet_ntop inet_pton] ) AS_IF([test x$bwin32 = xtrue], [AX_CHECK_DECLS_EX([funcstochk getaddrinfo], [#ifdef _WIN32 #include #include #endif])], [AC_CHECK_FUNCS(m4_normalize(funcstochk))] ) m4_undefine([funcstochk]) dnl check getaddrinfo and gethostbyname_r for non-windows AS_IF([test x$bwin32 = xfalse], [ AC_CACHE_CHECK( [for getaddrinfo], [libevent_cv_getaddrinfo], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #ifdef HAVE_NETDB_H #include #endif ]], [[ getaddrinfo; ]] )], [libevent_cv_getaddrinfo=yes], [libevent_cv_getaddrinfo=no] )] ) if test "$libevent_cv_getaddrinfo" = "yes" ; then AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?]) else # Check for gethostbyname_r in all its glorious incompatible versions. # (This is cut-and-pasted from Tor, which based its logic on # Python's configure.in.) AH_TEMPLATE(HAVE_GETHOSTBYNAME_R, [Define this if you have any gethostbyname_r()]) AC_CHECK_FUNC(gethostbyname_r, [ AC_MSG_CHECKING([how many arguments gethostbyname_r() wants]) OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [[ char *cp1, *cp2; struct hostent *h1, *h2; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2); ]])],[ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1, [Define this if gethostbyname_r takes 6 arguments]) AC_MSG_RESULT(6) ], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [ char *cp1, *cp2; struct hostent *h1; int i1, i2; (void)gethostbyname_r(cp1,h1,cp2,i1,&i2); ])], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1, [Define this if gethostbyname_r takes 5 arguments]) AC_MSG_RESULT(5) ], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [ char *cp1; struct hostent *h1; struct hostent_data hd; (void) gethostbyname_r(cp1,h1,&hd); ])], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R) AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1, [Define this if gethostbyname_r takes 3 arguments]) AC_MSG_RESULT(3) ], [ AC_MSG_RESULT(0) ]) ]) ]) CFLAGS=$OLD_CFLAGS ]) fi ]) dnl end of checking getaddrinfo and gethostbyname_r AC_MSG_CHECKING(for F_SETFD in fcntl.h) AC_EGREP_CPP(yes, [ #define _GNU_SOURCE 1 #include #ifdef F_SETFD yes #endif ], [ AC_DEFINE(HAVE_SETFD, 1, [Define if F_SETFD is defined in ]) AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no)) needsignal=no haveselect=no if test x$bwin32 != xtrue; then AC_CHECK_FUNCS(select, [haveselect=yes], ) if test "x$haveselect" = "xyes" ; then needsignal=yes fi fi AM_CONDITIONAL(SELECT_BACKEND, [test "x$haveselect" = "xyes"]) havepoll=no AC_CHECK_FUNCS(poll, [havepoll=yes], ) if test "x$havepoll" = "xyes" ; then needsignal=yes fi AM_CONDITIONAL(POLL_BACKEND, [test "x$havepoll" = "xyes"]) havedevpoll=no if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then AC_DEFINE(HAVE_DEVPOLL, 1, [Define if /dev/poll is available]) fi AM_CONDITIONAL(DEVPOLL_BACKEND, [test "x$ac_cv_header_sys_devpoll_h" = "xyes"]) havekqueue=no if test "x$ac_cv_header_sys_event_h" = "xyes"; then AC_CHECK_FUNCS(kqueue, [havekqueue=yes], ) if test "x$havekqueue" = "xyes" ; then AC_MSG_CHECKING(for working kqueue) AC_RUN_IFELSE( [AC_LANG_PROGRAM([ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include ], [[ int kq; int n; int fd[2]; struct kevent ev; struct timespec ts; char buf[80000]; if (pipe(fd) == -1) return 1; if (fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1) return 1; while ((n = write(fd[1], buf, sizeof(buf))) == sizeof(buf)) ; if ((kq = kqueue()) == -1) return 1; memset(&ev, 0, sizeof(ev)); ev.ident = fd[1]; ev.filter = EVFILT_WRITE; ev.flags = EV_ADD | EV_ENABLE; n = kevent(kq, &ev, 1, NULL, 0, NULL); if (n == -1) return 1; read(fd[0], buf, sizeof(buf)); ts.tv_sec = 0; ts.tv_nsec = 0; n = kevent(kq, NULL, 0, &ev, 1, &ts); if (n == -1 || n == 0) return 1; return 0; ]] )], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_WORKING_KQUEUE, 1, [Define if kqueue works correctly with pipes]) havekqueue=yes ], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(no)] ) fi fi AM_CONDITIONAL(KQUEUE_BACKEND, [test "x$havekqueue" = "xyes"]) haveepollsyscall=no haveepoll=no AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], ) if test "x$haveepoll" = "xyes" ; then AC_DEFINE(HAVE_EPOLL, 1, [Define if your system supports the epoll system calls]) needsignal=yes fi if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then if test "x$haveepoll" = "xno" ; then AC_MSG_CHECKING(for epoll system call) AC_RUN_IFELSE( [AC_LANG_PROGRAM([[ #include #include #include #include #include #include int epoll_create(int size) { return (syscall(__NR_epoll_create, size)); } ]],[[ int epfd; epfd = epoll_create(256); return (epfd == -1 ? 1 : 0); ]] )], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_EPOLL, 1, [Define if your system supports the epoll system calls]) needsignal=yes have_epoll=yes AC_LIBOBJ(epoll_sub) ], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(no)] ) fi fi AM_CONDITIONAL(EPOLL_BACKEND, [test "x$haveepoll" = "xyes"]) haveeventports=no AC_CHECK_FUNCS(port_create, [haveeventports=yes], ) if test "x$haveeventports" = "xyes" ; then AC_DEFINE(HAVE_EVENT_PORTS, 1, [Define if your system supports event ports]) needsignal=yes fi AM_CONDITIONAL(EVPORT_BACKEND, [test "x$haveeventports" = "xyes"]) if test "x$bwin32" = "xtrue"; then needsignal=yes fi AM_CONDITIONAL(SIGNAL_SUPPORT, [test "x$needsignal" = "xyes"]) AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t, uintptr_t], , , [#ifdef HAVE_STDINT_H #include #elif defined(HAVE_INTTYPES_H) #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif]) AC_CHECK_TYPES([fd_mask], , , [#ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif]) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(off_t) AC_CHECK_SIZEOF(time_t) AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, struct sockaddr_un, sa_family_t, struct addrinfo, struct sockaddr_storage], , , [#define _GNU_SOURCE 1 #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef _WIN32 #define WIN32_WINNT 0x400 #define _WIN32_WINNT 0x400 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif ]) AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len, struct sockaddr_storage.ss_family, struct sockaddr_storage.__ss_family], , , [#include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #define WIN32_WINNT 0x400 #define _WIN32_WINNT 0x400 #define WIN32_LEAN_AND_MEAN #if defined(_MSC_VER) && (_MSC_VER < 1300) #include #else #include #include #endif #endif ]) AC_CHECK_TYPES([struct linger],,, [ #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef _WIN32 #include #endif ]) AC_MSG_CHECKING([for socklen_t]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ #include #ifdef _WIN32 #include #else #include #endif ],[socklen_t x;] )], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_DEFINE(socklen_t, unsigned int, [Define to unsigned int if you dont have it])] ) # __func__/__FUNCTION__ is not a macros in general AC_MSG_CHECKING([whether our compiler supports __func__]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [ const char *cp = __func__; ] )], [ AC_DEFINE(HAVE___func__, 1, [Define to 1 if compiler have __func__]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])] ) AC_MSG_CHECKING([whether our compiler supports __FUNCTION__]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [ const char *cp = __FUNCTION__; ] )], [ AC_DEFINE(HAVE___FUNCTION__, 1, [Define to 1 if compiler have __FUNCTION__]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])] ) # check if we can compile with pthreads have_pthreads=no if test x$bwin32 != xtrue && test "$enable_thread_support" != "no"; then ACX_PTHREAD([ AC_DEFINE(HAVE_PTHREADS, 1, [Define if we have pthreads on this system]) have_pthreads=yes]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" AC_CHECK_SIZEOF(pthread_t, , [AC_INCLUDES_DEFAULT() #include ] ) fi AM_CONDITIONAL(THREADS, [test "$enable_thread_support" != "no"]) AM_CONDITIONAL(PTHREADS, [test "$have_pthreads" != "no" && test "$enable_thread_support" != "no"]) # check if we should compile locking into the library if test x$enable_thread_support = xno; then AC_DEFINE(DISABLE_THREAD_SUPPORT, 1, [Define if libevent should not be compiled with thread support]) fi # check if we should hard-code the mm functions. if test x$enable_malloc_replacement = xno; then AC_DEFINE(DISABLE_MM_REPLACEMENT, 1, [Define if libevent should not allow replacing the mm functions]) fi # check if we should hard-code debugging out if test x$enable_debug_mode = xno; then AC_DEFINE(DISABLE_DEBUG_MODE, 1, [Define if libevent should build without support for a debug mode]) fi # check if we should enable verbose debugging if test x$enable_verbose_debug = xyes; then CFLAGS="$CFLAGS -DUSE_DEBUG" fi # check if we have and should use openssl AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"]) # Add some more warnings which we use in development but not in the # released versions. (Some relevant gcc versions can't handle these.) if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) #error #endif])], have_gcc4=yes, have_gcc4=no) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) #error #endif])], have_gcc42=yes, have_gcc42=no) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) #error #endif])], have_gcc45=yes, have_gcc45=no) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ #if !defined(__clang__) #error #endif])], have_clang=yes, have_clang=no) # -W is the same as -Wextra CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wmissing-declarations -Wnested-externs -Wbad-function-cast" if test x$enable_gcc_warnings = xyes; then CFLAGS="$CFLAGS -Werror" fi CFLAGS="$CFLAGS -Wno-unused-parameter -Wstrict-aliasing" if test x$have_gcc4 = xyes ; then # These warnings break gcc 3.3.5 and work on gcc 4.0.2 CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement" #CFLAGS="$CFLAGS -Wold-style-definition" fi if test x$have_gcc42 = xyes ; then # These warnings break gcc 4.0.2 and work on gcc 4.2 CFLAGS="$CFLAGS -Waddress" fi if test x$have_gcc42 = xyes && test x$have_clang = xno; then # These warnings break gcc 4.0.2 and clang, but work on gcc 4.2 CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init" fi if test x$have_gcc45 = xyes ; then # These warnings work on gcc 4.5 CFLAGS="$CFLAGS -Wlogical-op" fi if test x$have_clang = xyes; then # Disable the unused-function warnings, because these trigger # for minheap-internal.h related code. CFLAGS="$CFLAGS -Wno-unused-function" # clang on macosx emits warnings for each directory specified which # isn't "used" generating a lot of build noise (typically 3 warnings # per file case "$host_os" in darwin*) CFLAGS="$CFLAGS -Qunused-arguments" ;; esac fi ##This will break the world on some 64-bit architectures # CFLAGS="$CFLAGS -Winline" fi LIBEVENT_GC_SECTIONS= if test "$GCC" = yes && test "$enable_function_sections" = yes ; then AC_CACHE_CHECK( [if linker supports omitting unused code and data], [libevent_cv_gc_sections_runs], [ dnl NetBSD will link but likely not run with --gc-sections dnl http://bugs.ntp.org/1844 dnl http://gnats.netbsd.org/40401 dnl --gc-sections causes attempt to load as linux elf, with dnl wrong syscalls in place. Test a little gauntlet of dnl simple stdio read code checking for errors, expecting dnl enough syscall differences that the NetBSD code will dnl fail even with Linux emulation working as designed. dnl A shorter test could be refined by someone with access dnl to a NetBSD host with Linux emulation working. origCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wl,--gc-sections" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[ FILE * fpC; char buf[32]; size_t cch; int read_success_once; fpC = fopen("conftest.c", "r"); if (NULL == fpC) exit(1); do { cch = fread(buf, sizeof(buf), 1, fpC); read_success_once |= (0 != cch); } while (0 != cch); if (!read_success_once) exit(2); if (!feof(fpC)) exit(3); if (0 != fclose(fpC)) exit(4); exit(EXIT_SUCCESS); ]] )], [ dnl We have to do this invocation manually so that we can dnl get the output of conftest.err to make sure it doesn't dnl mention gc-sections. if test "X$cross_compiling" = "Xyes" || grep gc-sections conftest.err ; then libevent_cv_gc_sections_runs=no else libevent_cv_gc_sections_runs=no ./conftest >/dev/null 2>&1 && libevent_cv_gc_sections_runs=yes fi ], [libevent_cv_gc_sections_runs=no] ) CFLAGS="$origCFLAGS" AS_UNSET([origCFLAGS]) ] ) case "$libevent_cv_gc_sections_runs" in yes) CFLAGS="-ffunction-sections -fdata-sections $CFLAGS" LIBEVENT_GC_SECTIONS="-Wl,--gc-sections" ;; esac fi AC_SUBST([LIBEVENT_GC_SECTIONS]) AM_CONDITIONAL([INSTALL_LIBEVENT], [test "$enable_libevent_install" = "yes"]) # Doxygen support DX_HTML_FEATURE(ON) DX_MAN_FEATURE(OFF) DX_RTF_FEATURE(OFF) DX_XML_FEATURE(OFF) DX_PDF_FEATURE(OFF) DX_PS_FEATURE(OFF) DX_CHM_FEATURE(OFF) DX_CHI_FEATURE(OFF) DX_INIT_DOXYGEN([libevent], [${top_srcdir}/Doxyfile], [doxygen]) AM_CONDITIONAL([ENABLE_DOXYGEN], [test "$DX_FLAG_doc" = "1"]) AM_CONDITIONAL([ENABLE_DOXYGEN_MAN], [test "$DX_FLAG_man" = "1"]) AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] ) AC_OUTPUT(Makefile) lldpd-1.0.13/libevent/strlcpy-internal.h0000644000076400001440000000064214111362570020666 0ustar00bernatusers00000000000000#ifndef STRLCPY_INTERNAL_H_INCLUDED_ #define STRLCPY_INTERNAL_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.h" #include "event2/visibility.h" #include "evconfig-private.h" #ifndef EVENT__HAVE_STRLCPY #include EVENT2_EXPORT_SYMBOL size_t event_strlcpy_(char *dst, const char *src, size_t siz); #define strlcpy event_strlcpy_ #endif #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/ipv6-internal.h0000644000076400001440000000472214111362570020055 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Internal use only: Fake IPv6 structures and values on platforms that * do not have them */ #ifndef IPV6_INTERNAL_H_INCLUDED_ #define IPV6_INTERNAL_H_INCLUDED_ #include "event2/event-config.h" #include "evconfig-private.h" #include #ifdef EVENT__HAVE_SYS_SOCKET_H #include #endif #include "event2/util.h" #ifdef __cplusplus extern "C" { #endif /** @file ipv6-internal.h * * Replacement types and functions for platforms that don't support ipv6 * properly. */ #ifndef EVENT__HAVE_STRUCT_IN6_ADDR struct in6_addr { ev_uint8_t s6_addr[16]; }; #endif #ifndef EVENT__HAVE_SA_FAMILY_T typedef int sa_family_t; #endif #ifndef EVENT__HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 { /* This will fail if we find a struct sockaddr that doesn't have * sa_family as the first element. */ sa_family_t sin6_family; ev_uint16_t sin6_port; struct in6_addr sin6_addr; }; #endif #ifndef AF_INET6 #define AF_INET6 3333 #endif #ifndef PF_INET6 #define PF_INET6 AF_INET6 #endif #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/WIN32-Code/0000755000076400001440000000000014143730656016664 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/WIN32-Code/tree.h0000644000076400001440000005416614111362571020000 0ustar00bernatusers00000000000000/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-back tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ void name##_RB_INSERT_COLOR(struct name *, struct type *); \ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ struct type *name##_RB_REMOVE(struct name *, struct type *); \ struct type *name##_RB_INSERT(struct name *, struct type *); \ struct type *name##_RB_FIND(struct name *, struct type *); \ struct type *name##_RB_NEXT(struct type *); \ struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #endif /* _SYS_TREE_H_ */ lldpd-1.0.13/libevent/WIN32-Code/getopt.c0000644000076400001440000001020614111362571020321 0ustar00bernatusers00000000000000/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */ /* * Copyright (c) 1987, 1993, 1994, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if 0 static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; #endif #include #include #include #include #define __P(x) x #define _DIAGASSERT(x) assert(x) #ifdef __weak_alias __weak_alias(getopt,_getopt); #endif int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ static char * _progname __P((char *)); int getopt_internal __P((int, char * const *, const char *)); static char * _progname(nargv0) char * nargv0; { char * tmp; _DIAGASSERT(nargv0 != NULL); tmp = strrchr(nargv0, '/'); if (tmp) tmp++; else tmp = nargv0; return(tmp); } #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const nargv[]; const char *ostr; { static char *__progname = 0; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ __progname = __progname?__progname:_progname(*nargv); _DIAGASSERT(nargv != NULL); _DIAGASSERT(ostr != NULL); if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-' /* found "--" */ && place[1] == '\0') { ++optind; place = EMSG; return (-1); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } lldpd-1.0.13/libevent/WIN32-Code/nmake/0000755000076400001440000000000014143730656017757 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/WIN32-Code/nmake/evconfig-private.h0000644000076400001440000000022614111362573023372 0ustar00bernatusers00000000000000#if !defined(EVENT_EVCONFIG__PRIVATE_H_) && !defined(__MINGW32__) #define EVENT_EVCONFIG__PRIVATE_H_ /* Nothing to see here. Move along. */ #endif lldpd-1.0.13/libevent/WIN32-Code/nmake/event2/0000755000076400001440000000000014143730656021162 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/WIN32-Code/nmake/event2/event-config.h0000644000076400001440000002471414111362575023723 0ustar00bernatusers00000000000000/* event2/event-config.h * * This file was generated by autoconf when libevent was built, and post- * processed by Libevent so that its macros would have a uniform prefix. * * DO NOT EDIT THIS FILE. * * Do not rely on macros in this file existing in later versions. */ #ifndef EVENT_CONFIG_H__ #define EVENT_CONFIG_H__ /* config.h. Generated by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define if libevent should not allow replacing the mm functions */ /* #undef EVENT__DISABLE_MM_REPLACEMENT */ /* Define if libevent should not be compiled with thread support */ /* #undef EVENT__DISABLE_THREAD_SUPPORT */ /* Define if clock_gettime is available in libc */ /* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */ /* Define is no secure id variant is available */ /* #define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 */ #define EVENT_DNS_USE_FTIME_FOR_ID_ 1 /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_ARPA_INET_H */ /* Define to 1 if you have the `clock_gettime' function. */ /* #undef EVENT__HAVE_CLOCK_GETTIME */ /* Define if /dev/poll is available */ /* #undef EVENT__HAVE_DEVPOLL */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_DLFCN_H */ /* Define if your system supports the epoll system calls */ /* #undef EVENT__HAVE_EPOLL */ /* Define to 1 if you have the `epoll_ctl' function. */ /* #undef EVENT__HAVE_EPOLL_CTL */ /* Define to 1 if you have the `eventfd' function. */ /* #undef EVENT__HAVE_EVENTFD */ /* Define if your system supports event ports */ /* #undef EVENT__HAVE_EVENT_PORTS */ /* Define to 1 if you have the `fcntl' function. */ /* #undef EVENT__HAVE_FCNTL */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_FCNTL_H 1 /* Define to 1 if you have the `getaddrinfo' function. */ #define EVENT__HAVE_GETADDRINFO 1 /* Define to 1 if you have the `getnameinfo' function. */ #define EVENT__HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getprotobynumber' function. */ #define EVENT__HAVE_GETPROTOBYNUMBER 1 /* Define to 1 if you have the `getservbyname' function. */ #define EVENT__HAVE_GETSERVBYNAME 1 /* Define to 1 if you have the `gettimeofday' function. */ /* #define EVENT__HAVE_GETTIMEOFDAY 1 */ /* Define to 1 if you have the `inet_ntop' function. */ /* #undef EVENT__HAVE_INET_NTOP */ /* Define to 1 if you have the `inet_pton' function. */ /* #undef EVENT__HAVE_INET_PTON */ /* Define to 1 if you have the header file. */ /* #define EVENT__HAVE_INTTYPES_H 1 */ /* Define to 1 if you have the `kqueue' function. */ /* #undef EVENT__HAVE_KQUEUE */ /* Define if the system has zlib */ /* #undef EVENT__HAVE_LIBZ */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_MEMORY_H 1 /* Define to 1 if you have the `mmap' function. */ /* #undef EVENT__HAVE_MMAP */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_NETINET_IN6_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_NETINET_IN_H */ /* Define to 1 if you have the `pipe' function. */ /* #undef EVENT__HAVE_PIPE */ /* Define to 1 if you have the `poll' function. */ /* #undef EVENT__HAVE_POLL */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_POLL_H */ /* Define to 1 if you have the `port_create' function. */ /* #undef EVENT__HAVE_PORT_CREATE */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_PORT_H */ /* Define if you have POSIX threads libraries and header files. */ /* #undef EVENT__HAVE_PTHREAD */ /* Define if we have pthreads on this system */ /* #undef EVENT__HAVE_PTHREADS */ /* Define to 1 if the system has the type `sa_family_t'. */ /* #undef EVENT__HAVE_SA_FAMILY_T */ /* Define to 1 if you have the `select' function. */ /* #undef EVENT__HAVE_SELECT */ /* Define to 1 if you have the `sendfile' function. */ /* #undef EVENT__HAVE_SENDFILE */ /* Define if F_SETFD is defined in */ /* #undef EVENT__HAVE_SETFD */ /* Define to 1 if you have the `sigaction' function. */ /* #undef EVENT__HAVE_SIGACTION */ /* Define to 1 if you have the `signal' function. */ #define EVENT__HAVE_SIGNAL 1 /* Define to 1 if you have the `splice' function. */ /* #undef EVENT__HAVE_SPLICE */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define EVENT__HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ /* #define EVENT__HAVE_STDINT_H 1 */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define EVENT__HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define EVENT__HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ /* #undef EVENT__HAVE_STRLCPY */ /* Define to 1 if you have the `strsep' function. */ /* #undef EVENT__HAVE_STRSEP */ /* Define to 1 if you have the `strtok_r' function. */ /* #undef EVENT__HAVE_STRTOK_R */ /* Define to 1 if you have the `strtoll' function. */ /* #define EVENT__HAVE_STRTOLL 1 */ #define EVENT__HAVE_STRUCT_ADDRINFO 1 /* Define to 1 if the system has the type `struct in6_addr'. */ #define EVENT__HAVE_STRUCT_IN6_ADDR 1 /* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */ #define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1 /* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */ #define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1 /* Define to 1 if the system has the type `struct sockaddr_in6'. */ #define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1 /* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */ /* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */ /* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */ /* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_EPOLL_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_EVENTFD_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_EVENT_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_IOCTL_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_MMAN_H */ /* Define to 1 if you have the header file. */ /* #define EVENT__HAVE_SYS_PARAM_H 1 */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_QUEUE_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_SELECT_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_SENDFILE_H */ /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #define EVENT__HAVE_SYS_TIME_H 1 */ /* Define to 1 if you have the header file. */ #define EVENT__HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef EVENT__HAVE_SYS_UIO_H */ /* Define if TAILQ_FOREACH is defined in */ /* #undef EVENT__HAVE_TAILQFOREACH */ /* Define if timeradd is defined in */ /* #undef EVENT__HAVE_TIMERADD */ /* Define if timerclear is defined in */ #define EVENT__HAVE_TIMERCLEAR 1 /* Define if timercmp is defined in */ #define EVENT__HAVE_TIMERCMP 1 /* Define if timerisset is defined in */ #define EVENT__HAVE_TIMERISSET 1 /* Define to 1 if the system has the type `uint16_t'. */ /* #define EVENT__HAVE_UINT16_T 1 */ /* Define to 1 if the system has the type `uint32_t'. */ /* #define EVENT__HAVE_UINT32_T 1 */ /* Define to 1 if the system has the type `uint64_t'. */ /* #define EVENT__HAVE_UINT64_T 1 */ /* Define to 1 if the system has the type `uint8_t'. */ /* #define EVENT__HAVE_UINT8_T 1 */ /* Define to 1 if you have the header file. */ /* #define EVENT__HAVE_UNISTD_H 1 */ /* Define to 1 if you have the `vasprintf' function. */ /* #undef EVENT__HAVE_VASPRINTF */ /* Define if kqueue works correctly with pipes */ /* #undef EVENT__HAVE_WORKING_KQUEUE */ /* Numeric representation of the version */ #define EVENT__NUMERIC_VERSION 0x02010c00 /* Name of package */ #define EVENT__PACKAGE "libevent" /* Define to the address where bug reports for this package should be sent. */ #define EVENT__PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define EVENT__PACKAGE_NAME "" /* Define to the full name and version of this package. */ #define EVENT__PACKAGE_STRING "" /* Define to the one symbol short name of this package. */ #define EVENT__PACKAGE_TARNAME "" /* Define to the version of this package. */ #define EVENT__PACKAGE_VERSION "" /* Define to necessary symbol if this constant uses a non-standard name on your system. */ /* #undef EVENT__PTHREAD_CREATE_JOINABLE */ /* The size of a `int', as computed by sizeof. */ #define EVENT__SIZEOF_INT 4 /* The size of a `long', as computed by sizeof. */ #define EVENT__SIZEOF_LONG 4 /* The size of a `long long', as computed by sizeof. */ #define EVENT__SIZEOF_LONG_LONG 8 /* The size of a `short', as computed by sizeof. */ #define EVENT__SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ #ifdef _WIN64 #define EVENT__SIZEOF_SIZE_T 8 #else #define EVENT__SIZEOF_SIZE_T 4 #endif /* The size of `void *', as computed by sizeof. */ #ifdef _WIN64 #define EVENT__SIZEOF_VOID_P 8 #else #define EVENT__SIZEOF_VOID_P 4 #endif /* The size of `time_t`, as computed by sizeof. */ #ifdef _WIN64 #define EVENT__SIZEOF_TIME_T 8 #else #define EVENT__SIZEOF_TIME_T 4 #endif /* Define to 1 if you can safely include both and . */ #define EVENT__TIME_WITH_SYS_TIME 1 /* Version number of package */ #define EVENT__VERSION "2.1.12-stable" /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #define EVENT__inline __inline /* Define to `unsigned' if does not define. */ /* #undef EVENT__size_t */ /* Define to unsigned int if you dont have it */ #define EVENT__socklen_t unsigned int /* Define to `int' if does not define. */ #define EVENT__ssize_t SSIZE_T #endif lldpd-1.0.13/libevent/WIN32-Code/getopt_long.c0000644000076400001440000001424014111362571021342 0ustar00bernatusers00000000000000 /* * Copyright (c) 1987, 1993, 1994, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "getopt.h" extern int opterr; /* if error message should be printed */ extern int optind; /* index into parent argv vector */ extern int optopt; /* character checked for validity */ extern int optreset; /* reset getopt */ extern char *optarg; /* argument associated with option */ #define __P(x) x #define _DIAGASSERT(x) assert(x) static char * __progname __P((char *)); int getopt_internal __P((int, char * const *, const char *)); static char * __progname(nargv0) char * nargv0; { char * tmp; _DIAGASSERT(nargv0 != NULL); tmp = strrchr(nargv0, '/'); if (tmp) tmp++; else tmp = nargv0; return(tmp); } #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt_internal(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ _DIAGASSERT(nargv != NULL); _DIAGASSERT(ostr != NULL); if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ /* ++optind; */ place = EMSG; return (-2); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if ((opterr) && (*ostr != ':')) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname(nargv[0]), optopt); return (BADARG); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } #if 0 /* * getopt -- * Parse argc/argv argument vector. */ int getopt2(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { int retval; if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { retval = -1; ++optind; } return(retval); } #endif /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(nargc, nargv, options, long_options, index) int nargc; char ** nargv; const char * options; const struct option * long_options; int * index; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); /* index may be NULL */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv = nargv[optind++] + 2, *has_equal; int i, match = -1; size_t current_argv_len; if (*current_argv == '\0') { return(-1); } if ((has_equal = strchr(current_argv, '=')) != NULL) { current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == current_argv_len) { match = i; break; } if (match == -1) match = i; } if (match != -1) { if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else optarg = nargv[optind++]; } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument, leading : * indicates no error should be generated */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: option requires an argument -- %s\n", __progname(nargv[0]), current_argv); return (BADARG); } } else { /* No matching argument */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); return (BADCH); } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (index) *index = match; } return(retval); } lldpd-1.0.13/libevent/WIN32-Code/getopt.h0000644000076400001440000000126014111362571020326 0ustar00bernatusers00000000000000#ifndef __GETOPT_H__ #define __GETOPT_H__ #ifdef __cplusplus extern "C" { #endif extern int opterr; /* if error message should be printed */ extern int optind; /* index into parent argv vector */ extern int optopt; /* character checked for validity */ extern int optreset; /* reset getopt */ extern char *optarg; /* argument associated with option */ struct option { const char *name; int has_arg; int *flag; int val; }; #define no_argument 0 #define required_argument 1 #define optional_argument 2 int getopt(int, char**, const char*); int getopt_long(int, char**, const char*, const struct option*, int*); #ifdef __cplusplus } #endif #endif /* __GETOPT_H__ */ lldpd-1.0.13/libevent/ratelim-internal.h0000644000076400001440000000777414111362570020640 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef RATELIM_INTERNAL_H_INCLUDED_ #define RATELIM_INTERNAL_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif #include "event2/util.h" /** A token bucket is an internal structure that tracks how many bytes we are * currently willing to read or write on a given bufferevent or group of * bufferevents */ struct ev_token_bucket { /** How many bytes are we willing to read or write right now? These * values are signed so that we can do "defecit spending" */ ev_ssize_t read_limit, write_limit; /** When was this bucket last updated? Measured in abstract 'ticks' * relative to the token bucket configuration. */ ev_uint32_t last_updated; }; /** Configuration info for a token bucket or set of token buckets. */ struct ev_token_bucket_cfg { /** How many bytes are we willing to read on average per tick? */ size_t read_rate; /** How many bytes are we willing to read at most in any one tick? */ size_t read_maximum; /** How many bytes are we willing to write on average per tick? */ size_t write_rate; /** How many bytes are we willing to write at most in any one tick? */ size_t write_maximum; /* How long is a tick? Note that fractions of a millisecond are * ignored. */ struct timeval tick_timeout; /* How long is a tick, in milliseconds? Derived from tick_timeout. */ unsigned msec_per_tick; }; /** The current tick is 'current_tick': add bytes to 'bucket' as specified in * 'cfg'. */ int ev_token_bucket_update_(struct ev_token_bucket *bucket, const struct ev_token_bucket_cfg *cfg, ev_uint32_t current_tick); /** In which tick does 'tv' fall according to 'cfg'? Note that ticks can * overflow easily; your code needs to handle this. */ ev_uint32_t ev_token_bucket_get_tick_(const struct timeval *tv, const struct ev_token_bucket_cfg *cfg); /** Adjust 'bucket' to respect 'cfg', and note that it was last updated in * 'current_tick'. If 'reinitialize' is true, we are changing the * configuration of 'bucket'; otherwise, we are setting it up for the first * time. */ int ev_token_bucket_init_(struct ev_token_bucket *bucket, const struct ev_token_bucket_cfg *cfg, ev_uint32_t current_tick, int reinitialize); int bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev, int unsuspend); /** Decrease the read limit of 'b' by 'n' bytes */ #define ev_token_bucket_decrement_read(b,n) \ do { \ (b)->read_limit -= (n); \ } while (0) /** Decrease the write limit of 'b' by 'n' bytes */ #define ev_token_bucket_decrement_write(b,n) \ do { \ (b)->write_limit -= (n); \ } while (0) #ifdef __cplusplus } #endif #endif lldpd-1.0.13/libevent/evutil_rand.c0000644000076400001440000001233514111362570017665 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This file has our secure PRNG code. On platforms that have arc4random(), * we just use that. Otherwise, we include arc4random.c as a bunch of static * functions, and wrap it lightly. We don't expose the arc4random*() APIs * because A) they aren't in our namespace, and B) it's not nice to name your * APIs after their implementations. We keep them in a separate file * so that other people can rip it out and use it for whatever. */ #include "event2/event-config.h" #include "evconfig-private.h" #include #include "util-internal.h" #include "evthread-internal.h" #ifdef EVENT__HAVE_ARC4RANDOM #include #include int evutil_secure_rng_set_urandom_device_file(char *fname) { (void) fname; return -1; } int evutil_secure_rng_init(void) { /* call arc4random() now to force it to self-initialize */ (void) arc4random(); return 0; } #ifndef EVENT__DISABLE_THREAD_SUPPORT int evutil_secure_rng_global_setup_locks_(const int enable_locks) { return 0; } #endif static void evutil_free_secure_rng_globals_locks(void) { } static void ev_arc4random_buf(void *buf, size_t n) { #if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) arc4random_buf(buf, n); return; #else unsigned char *b = buf; #if defined(EVENT__HAVE_ARC4RANDOM_BUF) /* OSX 10.7 introducd arc4random_buf, so if you build your program * there, you'll get surprised when older versions of OSX fail to run. * To solve this, we can check whether the function pointer is set, * and fall back otherwise. (OSX does this using some linker * trickery.) */ { void (*tptr)(void *,size_t) = (void (*)(void*,size_t))arc4random_buf; if (tptr != NULL) { arc4random_buf(buf, n); return; } } #endif /* Make sure that we start out with b at a 4-byte alignment; plenty * of CPUs care about this for 32-bit access. */ if (n >= 4 && ((ev_uintptr_t)b) & 3) { ev_uint32_t u = arc4random(); int n_bytes = 4 - (((ev_uintptr_t)b) & 3); memcpy(b, &u, n_bytes); b += n_bytes; n -= n_bytes; } while (n >= 4) { *(ev_uint32_t*)b = arc4random(); b += 4; n -= 4; } if (n) { ev_uint32_t u = arc4random(); memcpy(b, &u, n); } #endif } #else /* !EVENT__HAVE_ARC4RANDOM { */ #ifdef EVENT__ssize_t #define ssize_t EVENT__ssize_t #endif #define ARC4RANDOM_EXPORT static #define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0) #define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0) #ifndef EVENT__DISABLE_THREAD_SUPPORT static void *arc4rand_lock; #endif #define ARC4RANDOM_UINT32 ev_uint32_t #define ARC4RANDOM_NOSTIR #define ARC4RANDOM_NORANDOM #define ARC4RANDOM_NOUNIFORM #include "./arc4random.c" #ifndef EVENT__DISABLE_THREAD_SUPPORT int evutil_secure_rng_global_setup_locks_(const int enable_locks) { EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0); return 0; } #endif static void evutil_free_secure_rng_globals_locks(void) { #ifndef EVENT__DISABLE_THREAD_SUPPORT if (arc4rand_lock != NULL) { EVTHREAD_FREE_LOCK(arc4rand_lock, 0); arc4rand_lock = NULL; } #endif return; } int evutil_secure_rng_set_urandom_device_file(char *fname) { #ifdef TRY_SEED_URANDOM ARC4_LOCK_(); arc4random_urandom_filename = fname; ARC4_UNLOCK_(); #endif return 0; } int evutil_secure_rng_init(void) { int val; ARC4_LOCK_(); val = (!arc4_stir()) ? 0 : -1; ARC4_UNLOCK_(); return val; } static void ev_arc4random_buf(void *buf, size_t n) { arc4random_buf(buf, n); } #endif /* } !EVENT__HAVE_ARC4RANDOM */ void evutil_secure_rng_get_bytes(void *buf, size_t n) { ev_arc4random_buf(buf, n); } #if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM) void evutil_secure_rng_add_bytes(const char *buf, size_t n) { arc4random_addrandom((unsigned char*)buf, n>(size_t)INT_MAX ? INT_MAX : (int)n); } #endif void evutil_free_secure_rng_globals_(void) { evutil_free_secure_rng_globals_locks(); } lldpd-1.0.13/libevent/time-internal.h0000644000076400001440000000607614111362570020133 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TIME_INTERNAL_H_INCLUDED_ #define TIME_INTERNAL_H_INCLUDED_ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_MACH_MACH_TIME_H /* For mach_timebase_info */ #include #endif #include #include "event2/util.h" #ifdef __cplusplus extern "C" { #endif #if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) #define HAVE_POSIX_MONOTONIC #elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME) #define HAVE_MACH_MONOTONIC #elif defined(_WIN32) #define HAVE_WIN32_MONOTONIC #else #define HAVE_FALLBACK_MONOTONIC #endif long evutil_tv_to_msec_(const struct timeval *tv); EVENT2_EXPORT_SYMBOL void evutil_usleep_(const struct timeval *tv); #ifdef _WIN32 typedef ULONGLONG (WINAPI *ev_GetTickCount_func)(void); #endif struct evutil_monotonic_timer { #ifdef HAVE_MACH_MONOTONIC struct mach_timebase_info mach_timebase_units; #endif #ifdef HAVE_POSIX_MONOTONIC int monotonic_clock; #endif #ifdef HAVE_WIN32_MONOTONIC ev_GetTickCount_func GetTickCount64_fn; ev_GetTickCount_func GetTickCount_fn; ev_uint64_t last_tick_count; ev_uint64_t adjust_tick_count; ev_uint64_t first_tick; ev_uint64_t first_counter; double usec_per_count; int use_performance_counter; #endif struct timeval adjust_monotonic_clock; struct timeval last_time; }; EVENT2_EXPORT_SYMBOL int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *mt, int flags); EVENT2_EXPORT_SYMBOL int evutil_gettime_monotonic_(struct evutil_monotonic_timer *mt, struct timeval *tv); #ifdef __cplusplus } #endif #endif /* EVENT_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/evmap-internal.h0000644000076400001440000001143514111362570020300 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVMAP_INTERNAL_H_INCLUDED_ #define EVMAP_INTERNAL_H_INCLUDED_ /** @file evmap-internal.h * * An event_map is a utility structure to map each fd or signal to zero or * more events. Functions to manipulate event_maps should only be used from * inside libevent. They generally need to hold the lock on the corresponding * event_base. **/ struct event_base; struct event; /** Initialize an event_map for use. */ void evmap_io_initmap_(struct event_io_map* ctx); void evmap_signal_initmap_(struct event_signal_map* ctx); /** Remove all entries from an event_map. @param ctx the map to clear. */ void evmap_io_clear_(struct event_io_map* ctx); void evmap_signal_clear_(struct event_signal_map* ctx); /** Add an IO event (some combination of EV_READ or EV_WRITE) to an event_base's list of events on a given file descriptor, and tell the underlying eventops about the fd if its state has changed. Requires that ev is not already added. @param base the event_base to operate on. @param fd the file descriptor corresponding to ev. @param ev the event to add. */ int evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev); /** Remove an IO event (some combination of EV_READ or EV_WRITE) to an event_base's list of events on a given file descriptor, and tell the underlying eventops about the fd if its state has changed. @param base the event_base to operate on. @param fd the file descriptor corresponding to ev. @param ev the event to remove. */ int evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev); /** Active the set of events waiting on an event_base for a given fd. @param base the event_base to operate on. @param fd the file descriptor that has become active. @param events a bitmask of EV_READ|EV_WRITE|EV_ET. */ void evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events); /* These functions behave in the same way as evmap_io_*, except they work on * signals rather than fds. signals use a linear map everywhere; fds use * either a linear map or a hashtable. */ int evmap_signal_add_(struct event_base *base, int signum, struct event *ev); int evmap_signal_del_(struct event_base *base, int signum, struct event *ev); void evmap_signal_active_(struct event_base *base, evutil_socket_t signum, int ncalls); /* Return the fdinfo object associated with a given fd. If the fd has no * events associated with it, the result may be NULL. */ void *evmap_io_get_fdinfo_(struct event_io_map *ctx, evutil_socket_t fd); /* Helper for event_reinit(): Tell the backend to re-add every fd and signal * for which we have a pending event. */ int evmap_reinit_(struct event_base *base); /* Helper for event_base_free(): Call event_del() on every pending fd and * signal event. */ void evmap_delete_all_(struct event_base *base); /* Helper for event_base_assert_ok_(): Check referential integrity of the * evmaps. */ void evmap_check_integrity_(struct event_base *base); /* Helper: Call fn on every fd or signal event, passing as its arguments the * provided event_base, the event, and arg. If fn returns 0, process the next * event. If it returns any other value, return that value and process no * more events. */ int evmap_foreach_event_(struct event_base *base, event_base_foreach_event_cb fn, void *arg); #endif /* EVMAP_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/evthread.c0000644000076400001440000003262514111362570017157 0ustar00bernatusers00000000000000/* * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifndef EVENT__DISABLE_THREAD_SUPPORT #include "event2/thread.h" #include #include #include "log-internal.h" #include "mm-internal.h" #include "util-internal.h" #include "evthread-internal.h" #ifdef EVTHREAD_EXPOSE_STRUCTS #define GLOBAL #else #define GLOBAL static #endif #ifndef EVENT__DISABLE_DEBUG_MODE extern int event_debug_created_threadable_ctx_; extern int event_debug_mode_on_; #endif /* globals */ GLOBAL int evthread_lock_debugging_enabled_ = 0; GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { 0, 0, NULL, NULL, NULL, NULL }; GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL; GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = { 0, NULL, NULL, NULL, NULL }; /* Used for debugging */ static struct evthread_lock_callbacks original_lock_fns_ = { 0, 0, NULL, NULL, NULL, NULL }; static struct evthread_condition_callbacks original_cond_fns_ = { 0, NULL, NULL, NULL, NULL }; void evthread_set_id_callback(unsigned long (*id_fn)(void)) { evthread_id_fn_ = id_fn; } struct evthread_lock_callbacks *evthread_get_lock_callbacks() { return evthread_lock_debugging_enabled_ ? &original_lock_fns_ : &evthread_lock_fns_; } struct evthread_condition_callbacks *evthread_get_condition_callbacks() { return evthread_lock_debugging_enabled_ ? &original_cond_fns_ : &evthread_cond_fns_; } void evthreadimpl_disable_lock_debugging_(void) { evthread_lock_debugging_enabled_ = 0; } int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) { struct evthread_lock_callbacks *target = evthread_get_lock_callbacks(); #ifndef EVENT__DISABLE_DEBUG_MODE if (event_debug_mode_on_) { if (event_debug_created_threadable_ctx_) { event_errx(1, "evthread initialization must be called BEFORE anything else!"); } } #endif if (!cbs) { if (target->alloc) event_warnx("Trying to disable lock functions after " "they have been set up will probaby not work."); memset(target, 0, sizeof(evthread_lock_fns_)); return 0; } if (target->alloc) { /* Uh oh; we already had locking callbacks set up.*/ if (target->lock_api_version == cbs->lock_api_version && target->supported_locktypes == cbs->supported_locktypes && target->alloc == cbs->alloc && target->free == cbs->free && target->lock == cbs->lock && target->unlock == cbs->unlock) { /* no change -- allow this. */ return 0; } event_warnx("Can't change lock callbacks once they have been " "initialized."); return -1; } if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) { memcpy(target, cbs, sizeof(evthread_lock_fns_)); return event_global_setup_locks_(1); } else { return -1; } } int evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) { struct evthread_condition_callbacks *target = evthread_get_condition_callbacks(); #ifndef EVENT__DISABLE_DEBUG_MODE if (event_debug_mode_on_) { if (event_debug_created_threadable_ctx_) { event_errx(1, "evthread initialization must be called BEFORE anything else!"); } } #endif if (!cbs) { if (target->alloc_condition) event_warnx("Trying to disable condition functions " "after they have been set up will probaby not " "work."); memset(target, 0, sizeof(evthread_cond_fns_)); return 0; } if (target->alloc_condition) { /* Uh oh; we already had condition callbacks set up.*/ if (target->condition_api_version == cbs->condition_api_version && target->alloc_condition == cbs->alloc_condition && target->free_condition == cbs->free_condition && target->signal_condition == cbs->signal_condition && target->wait_condition == cbs->wait_condition) { /* no change -- allow this. */ return 0; } event_warnx("Can't change condition callbacks once they " "have been initialized."); return -1; } if (cbs->alloc_condition && cbs->free_condition && cbs->signal_condition && cbs->wait_condition) { memcpy(target, cbs, sizeof(evthread_cond_fns_)); } if (evthread_lock_debugging_enabled_) { evthread_cond_fns_.alloc_condition = cbs->alloc_condition; evthread_cond_fns_.free_condition = cbs->free_condition; evthread_cond_fns_.signal_condition = cbs->signal_condition; } return 0; } #define DEBUG_LOCK_SIG 0xdeb0b10c struct debug_lock { unsigned signature; unsigned locktype; unsigned long held_by; /* XXXX if we ever use read-write locks, we will need a separate * lock to protect count. */ int count; void *lock; }; static void * debug_lock_alloc(unsigned locktype) { struct debug_lock *result = mm_malloc(sizeof(struct debug_lock)); if (!result) return NULL; if (original_lock_fns_.alloc) { if (!(result->lock = original_lock_fns_.alloc( locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) { mm_free(result); return NULL; } } else { result->lock = NULL; } result->signature = DEBUG_LOCK_SIG; result->locktype = locktype; result->count = 0; result->held_by = 0; return result; } static void debug_lock_free(void *lock_, unsigned locktype) { struct debug_lock *lock = lock_; EVUTIL_ASSERT(lock->count == 0); EVUTIL_ASSERT(locktype == lock->locktype); EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); if (original_lock_fns_.free) { original_lock_fns_.free(lock->lock, lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); } lock->lock = NULL; lock->count = -100; lock->signature = 0x12300fda; mm_free(lock); } static void evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) { EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); ++lock->count; if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) EVUTIL_ASSERT(lock->count == 1); if (evthread_id_fn_) { unsigned long me; me = evthread_id_fn_(); if (lock->count > 1) EVUTIL_ASSERT(lock->held_by == me); lock->held_by = me; } } static int debug_lock_lock(unsigned mode, void *lock_) { struct debug_lock *lock = lock_; int res = 0; if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); else EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); if (original_lock_fns_.lock) res = original_lock_fns_.lock(mode, lock->lock); if (!res) { evthread_debug_lock_mark_locked(mode, lock); } return res; } static void evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock) { EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); else EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); if (evthread_id_fn_) { unsigned long me; me = evthread_id_fn_(); EVUTIL_ASSERT(lock->held_by == me); if (lock->count == 1) lock->held_by = 0; } --lock->count; EVUTIL_ASSERT(lock->count >= 0); } static int debug_lock_unlock(unsigned mode, void *lock_) { struct debug_lock *lock = lock_; int res = 0; evthread_debug_lock_mark_unlocked(mode, lock); if (original_lock_fns_.unlock) res = original_lock_fns_.unlock(mode, lock->lock); return res; } static int debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv) { int r; struct debug_lock *lock = lock_; EVUTIL_ASSERT(lock); EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); EVLOCK_ASSERT_LOCKED(lock_); evthread_debug_lock_mark_unlocked(0, lock); r = original_cond_fns_.wait_condition(cond_, lock->lock, tv); evthread_debug_lock_mark_locked(0, lock); return r; } /* misspelled version for backward compatibility */ void evthread_enable_lock_debuging(void) { evthread_enable_lock_debugging(); } void evthread_enable_lock_debugging(void) { struct evthread_lock_callbacks cbs = { EVTHREAD_LOCK_API_VERSION, EVTHREAD_LOCKTYPE_RECURSIVE, debug_lock_alloc, debug_lock_free, debug_lock_lock, debug_lock_unlock }; if (evthread_lock_debugging_enabled_) return; memcpy(&original_lock_fns_, &evthread_lock_fns_, sizeof(struct evthread_lock_callbacks)); memcpy(&evthread_lock_fns_, &cbs, sizeof(struct evthread_lock_callbacks)); memcpy(&original_cond_fns_, &evthread_cond_fns_, sizeof(struct evthread_condition_callbacks)); evthread_cond_fns_.wait_condition = debug_cond_wait; evthread_lock_debugging_enabled_ = 1; /* XXX return value should get checked. */ event_global_setup_locks_(0); } int evthread_is_debug_lock_held_(void *lock_) { struct debug_lock *lock = lock_; if (! lock->count) return 0; if (evthread_id_fn_) { unsigned long me = evthread_id_fn_(); if (lock->held_by != me) return 0; } return 1; } void * evthread_debug_get_real_lock_(void *lock_) { struct debug_lock *lock = lock_; return lock->lock; } void * evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks) { /* there are four cases here: 1) we're turning on debugging; locking is not on. 2) we're turning on debugging; locking is on. 3) we're turning on locking; debugging is not on. 4) we're turning on locking; debugging is on. */ if (!enable_locks && original_lock_fns_.alloc == NULL) { /* Case 1: allocate a debug lock. */ EVUTIL_ASSERT(lock_ == NULL); return debug_lock_alloc(locktype); } else if (!enable_locks && original_lock_fns_.alloc != NULL) { /* Case 2: wrap the lock in a debug lock. */ struct debug_lock *lock; EVUTIL_ASSERT(lock_ != NULL); if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) { /* We can't wrap it: We need a recursive lock */ original_lock_fns_.free(lock_, locktype); return debug_lock_alloc(locktype); } lock = mm_malloc(sizeof(struct debug_lock)); if (!lock) { original_lock_fns_.free(lock_, locktype); return NULL; } lock->lock = lock_; lock->locktype = locktype; lock->count = 0; lock->held_by = 0; return lock; } else if (enable_locks && ! evthread_lock_debugging_enabled_) { /* Case 3: allocate a regular lock */ EVUTIL_ASSERT(lock_ == NULL); return evthread_lock_fns_.alloc(locktype); } else { /* Case 4: Fill in a debug lock with a real lock */ struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype); EVUTIL_ASSERT(enable_locks && evthread_lock_debugging_enabled_); EVUTIL_ASSERT(lock->locktype == locktype); if (!lock->lock) { lock->lock = original_lock_fns_.alloc( locktype|EVTHREAD_LOCKTYPE_RECURSIVE); if (!lock->lock) { lock->count = -200; mm_free(lock); return NULL; } } return lock; } } #ifndef EVTHREAD_EXPOSE_STRUCTS unsigned long evthreadimpl_get_id_() { return evthread_id_fn_ ? evthread_id_fn_() : 1; } void * evthreadimpl_lock_alloc_(unsigned locktype) { #ifndef EVENT__DISABLE_DEBUG_MODE if (event_debug_mode_on_) { event_debug_created_threadable_ctx_ = 1; } #endif return evthread_lock_fns_.alloc ? evthread_lock_fns_.alloc(locktype) : NULL; } void evthreadimpl_lock_free_(void *lock, unsigned locktype) { if (evthread_lock_fns_.free) evthread_lock_fns_.free(lock, locktype); } int evthreadimpl_lock_lock_(unsigned mode, void *lock) { if (evthread_lock_fns_.lock) return evthread_lock_fns_.lock(mode, lock); else return 0; } int evthreadimpl_lock_unlock_(unsigned mode, void *lock) { if (evthread_lock_fns_.unlock) return evthread_lock_fns_.unlock(mode, lock); else return 0; } void * evthreadimpl_cond_alloc_(unsigned condtype) { #ifndef EVENT__DISABLE_DEBUG_MODE if (event_debug_mode_on_) { event_debug_created_threadable_ctx_ = 1; } #endif return evthread_cond_fns_.alloc_condition ? evthread_cond_fns_.alloc_condition(condtype) : NULL; } void evthreadimpl_cond_free_(void *cond) { if (evthread_cond_fns_.free_condition) evthread_cond_fns_.free_condition(cond); } int evthreadimpl_cond_signal_(void *cond, int broadcast) { if (evthread_cond_fns_.signal_condition) return evthread_cond_fns_.signal_condition(cond, broadcast); else return 0; } int evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv) { if (evthread_cond_fns_.wait_condition) return evthread_cond_fns_.wait_condition(cond, lock, tv); else return 0; } int evthreadimpl_is_lock_debugging_enabled_(void) { return evthread_lock_debugging_enabled_; } int evthreadimpl_locking_enabled_(void) { return evthread_lock_fns_.lock != NULL; } #endif #endif lldpd-1.0.13/libevent/m4/0000755000076400001440000000000014143730656015532 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/m4/ltoptions.m40000644000076400001440000003426214143730637020035 0ustar00bernatusers00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) lldpd-1.0.13/libevent/m4/libevent_openssl.m40000644000076400001440000000334614111362571021345 0ustar00bernatusers00000000000000dnl ###################################################################### dnl OpenSSL support AC_DEFUN([LIBEVENT_OPENSSL], [ AC_REQUIRE([NTP_PKG_CONFIG])dnl case "$enable_openssl" in yes) have_openssl=no case "$PKG_CONFIG" in '') ;; *) OPENSSL_LIBS=`$PKG_CONFIG --libs openssl 2>/dev/null` case "$OPENSSL_LIBS" in '') ;; *) OPENSSL_LIBS="$OPENSSL_LIBS $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD" have_openssl=yes ;; esac OPENSSL_INCS=`$PKG_CONFIG --cflags openssl 2>/dev/null` ;; esac case "$have_openssl" in yes) ;; *) save_LIBS="$LIBS" LIBS="" OPENSSL_LIBS="" for lib in crypto eay32; do # clear cache unset ac_cv_search_SSL_new AC_SEARCH_LIBS([SSL_new], [ssl ssl32], [have_openssl=yes OPENSSL_LIBS="$LIBS -l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD"], [have_openssl=no], [-l$lib $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD]) LIBS="$save_LIBS" test "$have_openssl" = "yes" && break done ;; esac CPPFLAGS_SAVE=$CPPFLAGS CPPFLAGS="$CPPFLAGS $OPENSSL_INCS" AC_CHECK_HEADERS([openssl/ssl.h], [], [have_openssl=no]) CPPFLAGS=$CPPFLAGS_SAVE AC_SUBST(OPENSSL_INCS) AC_SUBST(OPENSSL_LIBS) case "$have_openssl" in yes) AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl]) ;; *) AC_MSG_ERROR([openssl is a must but can not be found. You should add the \ directory containing `openssl.pc' to the `PKG_CONFIG_PATH' environment variable, \ or set `CFLAGS' and `LDFLAGS' directly for openssl, or use `--disable-openssl' \ to disable support for openssl encryption]) ;; esac ;; esac # check if we have and should use openssl AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"]) ]) lldpd-1.0.13/libevent/m4/ltsugar.m40000644000076400001440000001044014143730637017453 0ustar00bernatusers00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) lldpd-1.0.13/libevent/m4/ntp_pkg_config.m40000644000076400001440000000124114111362571020751 0ustar00bernatusers00000000000000dnl NTP_PKG_CONFIG -*- Autoconf -*- dnl dnl Look for pkg-config, which must be at least dnl $ntp_pkgconfig_min_version. dnl AC_DEFUN([NTP_PKG_CONFIG], [ dnl lower the minimum version if you find an earlier one works ntp_pkgconfig_min_version='0.15.0' AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) AS_UNSET([ac_cv_path_PKG_CONFIG]) AS_UNSET([ac_cv_path_ac_pt_PKG_CONFIG]) case "$PKG_CONFIG" in /*) AC_MSG_CHECKING([if pkg-config is at least version $ntp_pkgconfig_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $ntp_pkgconfig_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi ;; esac ]) dnl NTP_PKG_CONFIG lldpd-1.0.13/libevent/m4/ltversion.m40000644000076400001440000000127314143730637020023 0ustar00bernatusers00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) lldpd-1.0.13/libevent/m4/ax_check_funcs_ex.m40000644000076400001440000000124014111362571021420 0ustar00bernatusers00000000000000# Check if the function is available. # HAVE_XXX will be defined if yes. # $1: the name of function # $2: the headers in where the function declared AC_DEFUN([AX_CHECK_DECL_EX], [dnl AS_IF([test "x$2" = "x"], [AC_MSG_ERROR([header not privided])]) AS_VAR_PUSHDEF([have_func_var], [HAVE_[]m4_toupper($1)]) AC_CHECK_DECL([$1],dnl [AC_DEFINE([have_func_var], [1], [Define to 1 if you have the `$1' function.])],,dnl [$2]dnl ) AS_VAR_POPDEF([have_func_var])dnl ]) AC_DEFUN([AX_CHECK_DECLS_EX], [dnl AS_IF([test "x$2" = "x"], [AC_MSG_ERROR([header not privided])]) m4_foreach([decl],dnl m4_split(m4_normalize($1)),dnl [AX_CHECK_DECL_EX([decl], [$2])]dnl ) ]) lldpd-1.0.13/libevent/m4/lt~obsolete.m40000644000076400001440000001377414143730637020361 0ustar00bernatusers00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) lldpd-1.0.13/libevent/m4/libtool.m40000644000076400001440000112677114143730637017456 0ustar00bernatusers00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*|11.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cr} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS lldpd-1.0.13/libevent/m4/ax_prog_doxygen.m40000644000076400001440000005052414111362571021166 0ustar00bernatusers00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html # =========================================================================== # # SYNOPSIS # # DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...) # DX_DOXYGEN_FEATURE(ON|OFF) # DX_DOT_FEATURE(ON|OFF) # DX_HTML_FEATURE(ON|OFF) # DX_CHM_FEATURE(ON|OFF) # DX_CHI_FEATURE(ON|OFF) # DX_MAN_FEATURE(ON|OFF) # DX_RTF_FEATURE(ON|OFF) # DX_XML_FEATURE(ON|OFF) # DX_PDF_FEATURE(ON|OFF) # DX_PS_FEATURE(ON|OFF) # # DESCRIPTION # # The DX_*_FEATURE macros control the default setting for the given # Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for # generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML # help (for MS users), 'CHI' for generating a separate .chi file by the # .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate # output formats. The environment variable DOXYGEN_PAPER_SIZE may be # specified to override the default 'a4wide' paper size. # # By default, HTML, PDF and PS documentation is generated as this seems to # be the most popular and portable combination. MAN pages created by # Doxygen are usually problematic, though by picking an appropriate subset # and doing some massaging they might be better than nothing. CHM and RTF # are specific for MS (note that you can't generate both HTML and CHM at # the same time). The XML is rather useless unless you apply specialized # post-processing to it. # # The macros mainly control the default state of the feature. The use can # override the default by specifying --enable or --disable. The macros # ensure that contradictory flags are not given (e.g., # --enable-doxygen-html and --enable-doxygen-chm, # --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each # feature will be automatically disabled (with a warning) if the required # programs are missing. # # Once all the feature defaults have been specified, call DX_INIT_DOXYGEN # with the following parameters: a one-word name for the project for use # as a filename base etc., an optional configuration file name (the # default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an # optional output directory name (the default is 'doxygen-doc'). To run # doxygen multiple times for different configuration files and output # directories provide more parameters: the second, forth, sixth, etc # parameter are configuration file names and the third, fifth, seventh, # etc parameter are output directories. No checking is done to catch # duplicates. # # Automake Support # # The DX_RULES substitution can be used to add all needed rules to the # Makefile. Note that this is a substitution without being a variable: # only the @DX_RULES@ syntax will work. # # The provided targets are: # # doxygen-doc: Generate all doxygen documentation. # # doxygen-run: Run doxygen, which will generate some of the # documentation (HTML, CHM, CHI, MAN, RTF, XML) # but will not do the post processing required # for the rest of it (PS, PDF). # # doxygen-ps: Generate doxygen PostScript documentation. # # doxygen-pdf: Generate doxygen PDF documentation. # # Note that by default these are not integrated into the automake targets. # If doxygen is used to generate man pages, you can achieve this # integration by setting man3_MANS to the list of man pages generated and # then adding the dependency: # # $(man3_MANS): doxygen-doc # # This will cause make to run doxygen and generate all the documentation. # # The following variable is intended for use in Makefile.am: # # DX_CLEANFILES = everything to clean. # # Then add this variable to MOSTLYCLEANFILES. # # LICENSE # # Copyright (c) 2009 Oren Ben-Kiki # Copyright (c) 2015 Olaf Mandel # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 24 ## ----------## ## Defaults. ## ## ----------## DX_ENV="" AC_DEFUN([DX_FEATURE_doc], OFF) AC_DEFUN([DX_FEATURE_dot], OFF) AC_DEFUN([DX_FEATURE_man], OFF) AC_DEFUN([DX_FEATURE_html], ON) AC_DEFUN([DX_FEATURE_chm], OFF) AC_DEFUN([DX_FEATURE_chi], OFF) AC_DEFUN([DX_FEATURE_rtf], OFF) AC_DEFUN([DX_FEATURE_xml], OFF) AC_DEFUN([DX_FEATURE_pdf], ON) AC_DEFUN([DX_FEATURE_ps], ON) ## --------------- ## ## Private macros. ## ## --------------- ## # DX_ENV_APPEND(VARIABLE, VALUE) # ------------------------------ # Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it # as a substitution (but not a Makefile variable). The substitution # is skipped if the variable name is VERSION. AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl AM_SUBST_NOTMAKE([$1])])dnl ]) # DX_DIRNAME_EXPR # --------------- # Expand into a shell expression prints the directory part of a path. AC_DEFUN([DX_DIRNAME_EXPR], [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) # DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) # ------------------------------------- # Expands according to the M4 (static) status of the feature. AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) # DX_REQUIRE_PROG(VARIABLE, PROGRAM) # ---------------------------------- # Require the specified program to be found for the DX_CURRENT_FEATURE to work. AC_DEFUN([DX_REQUIRE_PROG], [ AC_PATH_TOOL([$1], [$2]) if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then if test "x$2" = "xdoxygen"; then AC_MSG_ERROR([$2 not found - will not DX_CURRENT_DESCRIPTION]) else AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) fi AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) fi ]) # DX_TEST_FEATURE(FEATURE) # ------------------------ # Expand to a shell expression testing whether the feature is active. AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) # DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) # ------------------------------------------------- # Verify that a required features has the right state before trying to turn on # the DX_CURRENT_FEATURE. AC_DEFUN([DX_CHECK_DEPEND], [ test "$DX_FLAG_$1" = "$2" \ || AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, requires, contradicts) doxygen-$1]) ]) # DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) # ---------------------------------------------------------- # Turn off the DX_CURRENT_FEATURE if the required feature is off. AC_DEFUN([DX_CLEAR_DEPEND], [ test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0) ]) # DX_FEATURE_ARG(FEATURE, DESCRIPTION, # CHECK_DEPEND, CLEAR_DEPEND, # REQUIRE, DO-IF-ON, DO-IF-OFF) # -------------------------------------------- # Parse the command-line option controlling a feature. CHECK_DEPEND is called # if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), # otherwise CLEAR_DEPEND is called to turn off the default state if a required # feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional # requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and # DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. AC_DEFUN([DX_ARG_ABLE], [ AC_DEFUN([DX_CURRENT_FEATURE], [$1]) AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) AC_ARG_ENABLE(doxygen-$1, [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], [--enable-doxygen-$1]), DX_IF_FEATURE([$1], [don't $2], [$2]))], [ case "$enableval" in #( y|Y|yes|Yes|YES) AC_SUBST([DX_FLAG_$1], 1) $3 ;; #( n|N|no|No|NO) AC_SUBST([DX_FLAG_$1], 0) ;; #( *) AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) ;; esac ], [ AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) $4 ]) if DX_TEST_FEATURE([$1]); then $5 : fi if DX_TEST_FEATURE([$1]); then $6 : else $7 : fi ]) ## -------------- ## ## Public macros. ## ## -------------- ## # DX_XXX_FEATURE(DEFAULT_STATE) # ----------------------------- AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])]) AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) # DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...) # -------------------------------------------------------------- # PROJECT also serves as the base name for the documentation files. # The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is # "doxygen-doc". # More arguments are interpreted as interleaved CONFIG-FILE and # OUTPUT-DOC-DIR values. AC_DEFUN([DX_INIT_DOXYGEN], [ # Files: AC_SUBST([DX_PROJECT], [$1]) AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])']) AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])']) m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2, [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]), 'm4_default_nblank_quoted(m4_argn(DX_i, $@), [$(srcdir)/Doxyfile])')])])dnl m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2, [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]), 'm4_default_nblank_quoted(m4_argn(DX_i, $@), [doxygen-doc])')])])dnl m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])], [])))dnl # Environment variables used inside doxygen.cfg: DX_ENV_APPEND(SRCDIR, $srcdir) DX_ENV_APPEND(PROJECT, $DX_PROJECT) DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) # Doxygen itself: DX_ARG_ABLE(doc, [generate any doxygen documentation], [], [], [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) DX_REQUIRE_PROG([DX_PERL], perl)], [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) # Dot for graphics: DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_DOT], dot)], [DX_ENV_APPEND(HAVE_DOT, YES) DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], [DX_ENV_APPEND(HAVE_DOT, NO)]) # Man pages generation: DX_ARG_ABLE(man, [generate doxygen manual pages], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_MAN, YES)], [DX_ENV_APPEND(GENERATE_MAN, NO)]) # RTF file generation: DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_RTF, YES)], [DX_ENV_APPEND(GENERATE_RTF, NO)]) # XML file generation: DX_ARG_ABLE(xml, [generate doxygen XML documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [], [DX_ENV_APPEND(GENERATE_XML, YES)], [DX_ENV_APPEND(GENERATE_XML, NO)]) # (Compressed) HTML help generation: DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_HHC], hhc)], [DX_ENV_APPEND(HHC_PATH, $DX_HHC) DX_ENV_APPEND(GENERATE_HTML, YES) DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) # Separate CHI file generation. DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file], [DX_CHECK_DEPEND(chm, 1)], [DX_CLEAR_DEPEND(chm, 1)], [], [DX_ENV_APPEND(GENERATE_CHI, YES)], [DX_ENV_APPEND(GENERATE_CHI, NO)]) # Plain HTML pages generation: DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], [], [DX_ENV_APPEND(GENERATE_HTML, YES)], [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) # PostScript file generation: DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_LATEX], latex) DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) DX_REQUIRE_PROG([DX_DVIPS], dvips) DX_REQUIRE_PROG([DX_EGREP], egrep)]) # PDF file generation: DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], [DX_CHECK_DEPEND(doc, 1)], [DX_CLEAR_DEPEND(doc, 1)], [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) DX_REQUIRE_PROG([DX_EGREP], egrep)]) # LaTeX generation for PS and/or PDF: if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then DX_ENV_APPEND(GENERATE_LATEX, YES) else DX_ENV_APPEND(GENERATE_LATEX, NO) fi # Paper size for PS and/or PDF: AC_ARG_VAR(DOXYGEN_PAPER_SIZE, [a4wide (default), a4, letter, legal or executive]) case "$DOXYGEN_PAPER_SIZE" in #( "") AC_SUBST(DOXYGEN_PAPER_SIZE, "") ;; #( a4wide|a4|letter|legal|executive) DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) ;; #( *) AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) ;; esac # Rules: AS_IF([[test $DX_FLAG_html -eq 1]], [[DX_SNIPPET_html="## ------------------------------- ## ## Rules specific for HTML output. ## ## ------------------------------- ## DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/html]])[ "]], [[DX_SNIPPET_html=""]]) AS_IF([[test $DX_FLAG_chi -eq 1]], [[DX_SNIPPET_chi=" DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]], [[DX_SNIPPET_chi=""]]) AS_IF([[test $DX_FLAG_chm -eq 1]], [[DX_SNIPPET_chm="## ------------------------------ ## ## Rules specific for CHM output. ## ## ------------------------------ ## DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/chm]])[\ ${DX_SNIPPET_chi} "]], [[DX_SNIPPET_chm=""]]) AS_IF([[test $DX_FLAG_man -eq 1]], [[DX_SNIPPET_man="## ------------------------------ ## ## Rules specific for MAN output. ## ## ------------------------------ ## DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/man]])[ "]], [[DX_SNIPPET_man=""]]) AS_IF([[test $DX_FLAG_rtf -eq 1]], [[DX_SNIPPET_rtf="## ------------------------------ ## ## Rules specific for RTF output. ## ## ------------------------------ ## DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/rtf]])[ "]], [[DX_SNIPPET_rtf=""]]) AS_IF([[test $DX_FLAG_xml -eq 1]], [[DX_SNIPPET_xml="## ------------------------------ ## ## Rules specific for XML output. ## ## ------------------------------ ## DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/xml]])[ "]], [[DX_SNIPPET_xml=""]]) AS_IF([[test $DX_FLAG_ps -eq 1]], [[DX_SNIPPET_ps="## ----------------------------- ## ## Rules specific for PS output. ## ## ----------------------------- ## DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[ DX_PS_GOAL = doxygen-ps doxygen-ps: \$(DX_CLEAN_PS) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_LATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_LATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_LATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ \$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi ]])["]], [[DX_SNIPPET_ps=""]]) AS_IF([[test $DX_FLAG_pdf -eq 1]], [[DX_SNIPPET_pdf="## ------------------------------ ## ## Rules specific for PDF output. ## ## ------------------------------ ## DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[ DX_PDF_GOAL = doxygen-pdf doxygen-pdf: \$(DX_CLEAN_PDF) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\ rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\ \$(DX_PDFLATEX) refman.tex; \\ \$(DX_MAKEINDEX) refman.idx; \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=5; \\ while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\ refman.log > /dev/null 2>&1 \\ && test \$\$countdown -gt 0; do \\ \$(DX_PDFLATEX) refman.tex; \\ countdown=\`expr \$\$countdown - 1\`; \\ done; \\ mv refman.pdf ../\$(PACKAGE).pdf ]])["]], [[DX_SNIPPET_pdf=""]]) AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]], [[DX_SNIPPET_latex="## ------------------------------------------------- ## ## Rules specific for LaTeX (shared for PS and PDF). ## ## ------------------------------------------------- ## DX_V_LATEX = \$(_DX_v_LATEX_\$(V)) _DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY)) _DX_v_LATEX_0 = @echo \" LATEX \" \$][@; DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\ \$(DX_DOCDIR]DX_i[)/latex]])[ "]], [[DX_SNIPPET_latex=""]]) AS_IF([[test $DX_FLAG_doc -eq 1]], [[DX_SNIPPET_doc="## --------------------------------- ## ## Format-independent Doxygen rules. ## ## --------------------------------- ## ${DX_SNIPPET_html}\ ${DX_SNIPPET_chm}\ ${DX_SNIPPET_man}\ ${DX_SNIPPET_rtf}\ ${DX_SNIPPET_xml}\ ${DX_SNIPPET_ps}\ ${DX_SNIPPET_pdf}\ ${DX_SNIPPET_latex}\ DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V)) _DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY)) _DX_v_DXGEN_0 = @echo \" DXGEN \" \$<; .PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL) .INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) doxygen-run:]m4_foreach([DX_i], [DX_loop], [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[ doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL) ]m4_foreach([DX_i], [DX_loop], [[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS) \$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[) \$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[) \$(A""M_V_at)echo Timestamp >\$][@ ]])dnl [DX_CLEANFILES = \\] m4_foreach([DX_i], [DX_loop], [[ \$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\ ]])dnl [ -r \\ \$(DX_CLEAN_HTML) \\ \$(DX_CLEAN_CHM) \\ \$(DX_CLEAN_CHI) \\ \$(DX_CLEAN_MAN) \\ \$(DX_CLEAN_RTF) \\ \$(DX_CLEAN_XML) \\ \$(DX_CLEAN_PS) \\ \$(DX_CLEAN_PDF) \\ \$(DX_CLEAN_LATEX) DX_INSTALL_DOCS = \\ \$(DX_CLEAN_HTML) \\ \$(DX_CLEAN_CHM) \\ \$(DX_CLEAN_CHI) \\ \$(DX_CLEAN_RTF) \\ \$(DX_CLEAN_XML) \\ \$(DX_CLEAN_PS) \\ \$(DX_CLEAN_PDF) \\ \$(DX_CLEAN_LATEX) "]], [[DX_SNIPPET_doc=""]]) AC_SUBST([DX_RULES], ["${DX_SNIPPET_doc}"])dnl AM_SUBST_NOTMAKE([DX_RULES]) #For debugging: #echo DX_FLAG_doc=$DX_FLAG_doc #echo DX_FLAG_dot=$DX_FLAG_dot #echo DX_FLAG_man=$DX_FLAG_man #echo DX_FLAG_html=$DX_FLAG_html #echo DX_FLAG_chm=$DX_FLAG_chm #echo DX_FLAG_chi=$DX_FLAG_chi #echo DX_FLAG_rtf=$DX_FLAG_rtf #echo DX_FLAG_xml=$DX_FLAG_xml #echo DX_FLAG_pdf=$DX_FLAG_pdf #echo DX_FLAG_ps=$DX_FLAG_ps #echo DX_ENV=$DX_ENV ]) lldpd-1.0.13/libevent/m4/acx_pthread.m40000644000076400001440000002526014111362571020253 0ustar00bernatusers00000000000000##### http://autoconf-archive.cryp.to/acx_pthread.html # # SYNOPSIS # # ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. # It sets the PTHREAD_LIBS output variable to the threads library and # linker flags, and the PTHREAD_CFLAGS output variable to any special # C compiler flags that are needed. (The user can also force certain # compiler flags/libs to be tested by setting these environment # variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). # (This is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these # flags, but also link it with them as well. e.g. you should link # with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS # $LIBS # # If you are only building threads programs, you may wish to use # these variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute # constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # ACTION-IF-FOUND is a list of shell commands to run if a threads # library is found, and ACTION-IF-NOT-FOUND is a list of commands to # run it if it is not found. If ACTION-IF-FOUND is not specified, the # default action will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or # if you have any other suggestions or comments. This macro was based # on work by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) # (with help from M. Frigo), as well as ac_pthread and hb_pthread # macros posted by Alejandro Forero Cuervo to the autoconf macro # repository. We are also grateful for the helpful feedback of # numerous users. # # LAST MODIFICATION # # 2007-07-29 # # COPYLEFT # # Copyright (c) 2007 Steven G. Johnson # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # . # # As a special exception, the respective Autoconf Macro's copyright # owner gives unlimited permission to copy, distribute and modify the # configure scripts that are the output of Autoconf when processing # the Macro. You need not follow the terms of the GNU General Public # License when using or distributing such scripts, even though # portions of the text of the Macro appear in them. The GNU General # Public License (GPL) does govern all other use of the material that # constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the # Autoconf Macro released by the Autoconf Macro Archive. When you # make and distribute a modified version of the Autoconf Macro, you # may extend this special exception to the GPL to apply to your # modified version as well. AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD lldpd-1.0.13/libevent/m4/ac_backport_259_ssizet.m40000644000076400001440000000015014111362571022230 0ustar00bernatusers00000000000000AN_IDENTIFIER([ssize_t], [AC_TYPE_SSIZE_T]) AC_DEFUN([AC_TYPE_SSIZE_T], [AC_CHECK_TYPE(ssize_t, int)]) lldpd-1.0.13/libevent/README.md0000644000076400001440000002550214111362570016464 0ustar00bernatusers00000000000000

libevent logo

[![Appveyor Win32 Build Status](https://ci.appveyor.com/api/projects/status/ng3jg0uhy44mp7ik?svg=true)](https://ci.appveyor.com/project/libevent/libevent) [![Travis Build Status](https://travis-ci.org/libevent/libevent.svg?branch=master)](https://travis-ci.org/libevent/libevent) [![Coverage Status](https://coveralls.io/repos/github/libevent/libevent/badge.svg)](https://coveralls.io/github/libevent/libevent) [![Join the chat at https://gitter.im/libevent/libevent](https://badges.gitter.im/libevent/libevent.svg)](https://gitter.im/libevent/libevent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) # 0. BUILDING AND INSTALLATION (Briefly) ## Autoconf $ ./configure $ make $ make verify # (optional) $ sudo make install ## CMake (General) The following Libevent specific CMake variables are as follows (the values being the default). ``` # Type of the library to build (SHARED or STATIC) # Default is: SHARED for MSVC, otherwise BOTH EVENT__LIBRARY_TYPE:STRING=DEFAULT # Installation directory for CMake files EVENT_INSTALL_CMAKE_DIR:PATH=lib/cmake/libevent # Enable running gcov to get a test coverage report (only works with # GCC/CLang). Make sure to enable -DCMAKE_BUILD_TYPE=Debug as well. EVENT__COVERAGE:BOOL=OFF # Defines if Libevent should build without the benchmark executables EVENT__DISABLE_BENCHMARK:BOOL=OFF # Define if Libevent should build without support for a debug mode EVENT__DISABLE_DEBUG_MODE:BOOL=OFF # Define if Libevent should not allow replacing the mm functions EVENT__DISABLE_MM_REPLACEMENT:BOOL=OFF # Define if Libevent should build without support for OpenSSL encryption EVENT__DISABLE_OPENSSL:BOOL=OFF # Disable the regress tests EVENT__DISABLE_REGRESS:BOOL=OFF # Disable sample files EVENT__DISABLE_SAMPLES:BOOL=OFF # If tests should be compiled or not EVENT__DISABLE_TESTS:BOOL=OFF # Define if Libevent should not be compiled with thread support EVENT__DISABLE_THREAD_SUPPORT:BOOL=OFF # Enables verbose debugging EVENT__ENABLE_VERBOSE_DEBUG:BOOL=OFF # When cross compiling, forces running a test program that verifies that Kqueue # works with pipes. Note that this requires you to manually run the test program # on the the cross compilation target to verify that it works. See CMake # documentation for try_run for more details EVENT__FORCE_KQUEUE_CHECK:BOOL=OFF ``` __More variables can be found by running `cmake -LAH `__ ## CMake (Windows) Install CMake: $ md build && cd build $ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list. $ start libevent.sln ## CMake (Unix) $ mkdir build && cd build $ cmake .. # Default to Unix Makefiles. $ make $ make verify # (optional) # 1. BUILDING AND INSTALLATION (In Depth) ## Autoconf To build Libevent, type $ ./configure && make (If you got Libevent from the git repository, you will first need to run the included "autogen.sh" script in order to generate the configure script.) You can run the regression tests by running $ make verify Install as root via $ make install Before reporting any problems, please run the regression tests. To enable low-level tracing, build the library as: $ CFLAGS=-DUSE_DEBUG ./configure [...] Standard configure flags should work. In particular, see: --disable-shared Only build static libraries. --prefix Install all files relative to this directory. The configure script also supports the following flags: --enable-gcc-warnings Enable extra compiler checking with GCC. --disable-malloc-replacement Don't let applications replace our memory management functions. --disable-openssl Disable support for OpenSSL encryption. --disable-thread-support Don't support multithreaded environments. ## CMake (Windows) (Note that autoconf is currently the most mature and supported build environment for Libevent; the CMake instructions here are new and experimental, though they _should_ be solid. We hope that CMake will still be supported in future versions of Libevent, and will try to make sure that happens.) First of all install . To build Libevent using Microsoft Visual studio open the "Visual Studio Command prompt" and type: ``` $ cd $ mkdir build && cd build $ cmake -G "Visual Studio 10" .. # Or whatever generator you want to use cmake --help for a list. $ start libevent.sln ``` In the above, the ".." refers to the dir containing the Libevent source code. You can build multiple versions (with different compile time settings) from the same source tree by creating other build directories. It is highly recommended to build "out of source" when using CMake instead of "in source" like the normal behaviour of autoconf for this reason. The "NMake Makefiles" CMake generator can be used to build entirely via the command line. To get a list of settings available for the project you can type: ``` $ cmake -LH .. ``` ### GUI CMake also provides a GUI that lets you specify the source directory and output (binary) directory that the build should be placed in. # 2. USEFUL LINKS: For the latest released version of Libevent, see the official website at . There's a pretty good work-in-progress manual up at . For the latest development versions of Libevent, access our Git repository via ``` $ git clone https://github.com/libevent/libevent.git ``` You can browse the git repository online at: To report bugs, issues, or ask for new features: __Patches__: https://github.com/libevent/libevent/pulls > OK, those are not really _patches_. You fork, modify, and hit the "Create Pull Request" button. > You can still submit normal git patches via the mailing list. __Bugs, Features [RFC], and Issues__: https://github.com/libevent/libevent/issues > Or you can do it via the mailing list. There's also a libevent-users mailing list for talking about Libevent use and development: # 3. ACKNOWLEDGMENTS The following people have helped with suggestions, ideas, code or fixing bugs: * Samy Al Bahra * Antony Antony * Jacob Appelbaum * Arno Bakker * Weston Andros Adamson * William Ahern * Ivan Andropov * Sergey Avseyev * Avi Bab * Joachim Bauch * Andrey Belobrov * Gilad Benjamini * Stas Bekman * Denis Bilenko * Julien Blache * Kevin Bowling * Tomash Brechko * Kelly Brock * Ralph Castain * Adrian Chadd * Lawnstein Chan * Shuo Chen * Ka-Hing Cheung * Andrew Cox * Paul Croome * George Danchev * Andrew Danforth * Ed Day * Christopher Davis * Mike Davis * Frank Denis * Antony Dovgal * Mihai Draghicioiu * Alexander Drozdov * Mark Ellzey * Shie Erlich * Leonid Evdokimov * Juan Pablo Fernandez * Christophe Fillot * Mike Frysinger * Remi Gacogne * Artem Germanov * Alexander von Gernler * Diego Giagio * Artur Grabowski * Diwaker Gupta * Kuldeep Gupta * Sebastian Hahn * Dave Hart * Greg Hazel * Nicholas Heath * Michael Herf * Savg He * Mark Heily * Maxime Henrion * Michael Herf * Greg Hewgill * Andrew Hochhaus * Aaron Hopkins * Tani Hosokawa * Jamie Iles * Xiuqiang Jiang * Claudio Jeker * Evan Jones * Marcin Juszkiewicz * George Kadianakis * Makoto Kato * Phua Keat * Azat Khuzhin * Alexander Klauer * Kevin Ko * Brian Koehmstedt * Marko Kreen * Ondřej Kuzník * Valery Kyholodov * Ross Lagerwall * Scott Lamb * Christopher Layne * Adam Langley * Graham Leggett * Volker Lendecke * Philip Lewis * Zhou Li * David Libenzi * Yan Lin * Moshe Litvin * Simon Liu * Mitchell Livingston * Hagne Mahre * Lubomir Marinov * Abilio Marques * Nicolas Martyanoff * Abel Mathew * Nick Mathewson * James Mansion * Nicholas Marriott * Andrey Matveev * Caitlin Mercer * Dagobert Michelsen * Andrea Montefusco * Mansour Moufid * Mina Naguib * Felix Nawothnig * Trond Norbye * Linus Nordberg * Richard Nyberg * Jon Oberheide * John Ohl * Phil Oleson * Alexey Ozeritsky * Dave Pacheco * Derrick Pallas * Tassilo von Parseval * Catalin Patulea * Patrick Pelletier * Simon Perreault * Dan Petro * Pierre Phaneuf * Amarin Phaosawasdi * Ryan Phillips * Dimitre Piskyulev * Pavel Plesov * Jon Poland * Roman Puls * Nate R * Robert Ransom * Balint Reczey * Bert JW Regeer * Nate Rosenblum * Peter Rosin * Maseeb Abdul Qadir * Wang Qin * Alex S * Gyepi Sam * Hanna Schroeter * Ralf Schmitt * Mike Smellie * Steve Snyder * Nir Soffer * Dug Song * Dongsheng Song * Hannes Sowa * Joakim Soderberg * Joseph Spadavecchia * Kevin Springborn * Harlan Stenn * Andrew Sweeney * Ferenc Szalai * Brodie Thiesfield * Jason Toffaletti * Brian Utterback * Gisle Vanem * Bas Verhoeven * Constantine Verutin * Colin Watt * Zack Weinberg * Jardel Weyrich * Jay R. Wren * Zack Weinberg * Mobai Zhang * Alejo * Alex * Taral * propanbutan * masksqwe * mmadia * yangacer * Andrey Skriabin * basavesh.as * billsegall * Bill Vaughan * Christopher Wiley * David Paschich * Ed Schouten * Eduardo Panisset * Jan Heylen * jer-gentoo * Joakim Söderberg * kirillDanshin * lzmths * Marcus Sundberg * Mark Mentovai * Mattes D * Matyas Dolak * Neeraj Badlani * Nick Mathewson * Rainer Keller * Seungmo Koo * Thomas Bernard * Xiao Bao Clark * zeliard * Zonr Chang * Kurt Roeckx * Seven * Simone Basso * Vlad Shcherban * Tim Hentenaar * Breaker * johnsonlee * Philip Prindeville * Vis Virial * Andreas Gustafsson * Andrey Okoshkin * an-tao * baixiangcpp * Bernard Spil * Bogdan Harjoc * Carlo Marcelo Arenas Belón * David Benjamin * David Disseldorp * Dmitry Alimov * Dominic Chen * dpayne * ejurgensen * Fredrik Strupe * Gonçalo Ribeiro * James Synge * Jan Beich * Jesse Fang * Jiri Luznicky * José Luis Millán * Kiyoshi Aman * Leo Zhang * lightningkay * Luke Dashjr * Marcin Szewczyk * Maximilian Brunner * Maya Rashish * Murat Demirten * Nathan French * Nikolay Edigaryev * Philip Herron * Redfoxmoon * stenn * SuckShit * The Gitter Badger * tim-le * Vincent JARDIN * Xiang Zhang * Xiaozhou Liu * yongqing.jiao * Enji Cooper * linxiaohui * Seong-Joong Kim * Tobias Stoeckmann * Yury Korzhetsky * zhuizhuhaomeng * Pierce Lopez * yuangongji * Keith Smiley * jeremyerb * Fabrice Fontaine * wenyg * Aleksandr-Melnikov * ayuseleznev * chenguolong * Dimo Markov * dota17 * fanquake * Jan Kasiak * Kamil Rytarowski * Mario Emmenlauer * Michael Davidsaver * mohuang * Nick Grifka * Nicolas J. Bouliane * Paul Osborne * Philip Homburg * Wataru Ashihara * William A Rowe Jr * yangyongsheng If we have forgotten your name, please contact us. lldpd-1.0.13/libevent/evthread_pthread.c0000644000076400001440000001153514111362570020663 0ustar00bernatusers00000000000000/* * Copyright 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" /* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE. * This comes from evconfig-private.h */ #include struct event_base; #include "event2/thread.h" #include #include #include "mm-internal.h" #include "evthread-internal.h" static pthread_mutexattr_t attr_recursive; static void * evthread_posix_lock_alloc(unsigned locktype) { pthread_mutexattr_t *attr = NULL; pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t)); if (!lock) return NULL; if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE) attr = &attr_recursive; if (pthread_mutex_init(lock, attr)) { mm_free(lock); return NULL; } return lock; } static void evthread_posix_lock_free(void *lock_, unsigned locktype) { pthread_mutex_t *lock = lock_; pthread_mutex_destroy(lock); mm_free(lock); } static int evthread_posix_lock(unsigned mode, void *lock_) { pthread_mutex_t *lock = lock_; if (mode & EVTHREAD_TRY) return pthread_mutex_trylock(lock); else return pthread_mutex_lock(lock); } static int evthread_posix_unlock(unsigned mode, void *lock_) { pthread_mutex_t *lock = lock_; return pthread_mutex_unlock(lock); } static unsigned long evthread_posix_get_id(void) { union { pthread_t thr; #if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG ev_uint64_t id; #else unsigned long id; #endif } r; #if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG memset(&r, 0, sizeof(r)); #endif r.thr = pthread_self(); return (unsigned long)r.id; } static void * evthread_posix_cond_alloc(unsigned condflags) { pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t)); if (!cond) return NULL; if (pthread_cond_init(cond, NULL)) { mm_free(cond); return NULL; } return cond; } static void evthread_posix_cond_free(void *cond_) { pthread_cond_t *cond = cond_; pthread_cond_destroy(cond); mm_free(cond); } static int evthread_posix_cond_signal(void *cond_, int broadcast) { pthread_cond_t *cond = cond_; int r; if (broadcast) r = pthread_cond_broadcast(cond); else r = pthread_cond_signal(cond); return r ? -1 : 0; } static int evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv) { int r; pthread_cond_t *cond = cond_; pthread_mutex_t *lock = lock_; if (tv) { struct timeval now, abstime; struct timespec ts; evutil_gettimeofday(&now, NULL); evutil_timeradd(&now, tv, &abstime); ts.tv_sec = abstime.tv_sec; ts.tv_nsec = abstime.tv_usec*1000; r = pthread_cond_timedwait(cond, lock, &ts); if (r == ETIMEDOUT) return 1; else if (r) return -1; else return 0; } else { r = pthread_cond_wait(cond, lock); return r ? -1 : 0; } } int evthread_use_pthreads(void) { struct evthread_lock_callbacks cbs = { EVTHREAD_LOCK_API_VERSION, EVTHREAD_LOCKTYPE_RECURSIVE, evthread_posix_lock_alloc, evthread_posix_lock_free, evthread_posix_lock, evthread_posix_unlock }; struct evthread_condition_callbacks cond_cbs = { EVTHREAD_CONDITION_API_VERSION, evthread_posix_cond_alloc, evthread_posix_cond_free, evthread_posix_cond_signal, evthread_posix_cond_wait }; /* Set ourselves up to get recursive locks. */ if (pthread_mutexattr_init(&attr_recursive)) return -1; if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE)) return -1; evthread_set_lock_callbacks(&cbs); evthread_set_condition_callbacks(&cond_cbs); evthread_set_id_callback(evthread_posix_get_id); return 0; } lldpd-1.0.13/libevent/log-internal.h0000644000076400001440000000647714111362570017763 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LOG_INTERNAL_H_INCLUDED_ #define LOG_INTERNAL_H_INCLUDED_ #include "event2/util.h" #ifdef __cplusplus extern "C" { #endif #ifdef __GNUC__ #define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b))) #define EV_NORETURN __attribute__((noreturn)) #else #define EV_CHECK_FMT(a,b) #define EV_NORETURN #endif #define EVENT_ERR_ABORT_ ((int)0xdeaddead) #if !defined(EVENT__DISABLE_DEBUG_MODE) || defined(USE_DEBUG) #define EVENT_DEBUG_LOGGING_ENABLED #endif #ifdef EVENT_DEBUG_LOGGING_ENABLED EVENT2_CORE_EXPORT_SYMBOL extern ev_uint32_t event_debug_logging_mask_; #define event_debug_get_logging_mask_() (event_debug_logging_mask_) #else #define event_debug_get_logging_mask_() (0) #endif EVENT2_EXPORT_SYMBOL void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN; EVENT2_EXPORT_SYMBOL void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2); EVENT2_EXPORT_SYMBOL void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN; EVENT2_EXPORT_SYMBOL void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(2,3); EVENT2_EXPORT_SYMBOL void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN; EVENT2_EXPORT_SYMBOL void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2); EVENT2_EXPORT_SYMBOL void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2); EVENT2_EXPORT_SYMBOL void event_debugx_(const char *fmt, ...) EV_CHECK_FMT(1,2); EVENT2_EXPORT_SYMBOL void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap) EV_CHECK_FMT(3,0); #ifdef EVENT_DEBUG_LOGGING_ENABLED #define event_debug(x) do { \ if (event_debug_get_logging_mask_()) { \ event_debugx_ x; \ } \ } while (0) #else #define event_debug(x) ((void)0) #endif #undef EV_CHECK_FMT #ifdef __cplusplus } #endif #endif /* LOG_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/evmap.c0000644000076400001440000007052314111362570016464 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef _WIN32 #include #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #endif #include #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H) #include #endif #include #include #include #ifndef _WIN32 #include #endif #include #include #include #include #include #include "event-internal.h" #include "evmap-internal.h" #include "mm-internal.h" #include "changelist-internal.h" /** An entry for an evmap_io list: notes all the events that want to read or write on a given fd, and the number of each. */ struct evmap_io { struct event_dlist events; ev_uint16_t nread; ev_uint16_t nwrite; ev_uint16_t nclose; }; /* An entry for an evmap_signal list: notes all the events that want to know when a signal triggers. */ struct evmap_signal { struct event_dlist events; }; /* On some platforms, fds start at 0 and increment by 1 as they are allocated, and old numbers get used. For these platforms, we implement io maps just like signal maps: as an array of pointers to struct evmap_io. But on other platforms (windows), sockets are not 0-indexed, not necessarily consecutive, and not necessarily reused. There, we use a hashtable to implement evmap_io. */ #ifdef EVMAP_USE_HT struct event_map_entry { HT_ENTRY(event_map_entry) map_node; evutil_socket_t fd; union { /* This is a union in case we need to make more things that can be in the hashtable. */ struct evmap_io evmap_io; } ent; }; /* Helper used by the event_io_map hashtable code; tries to return a good hash * of the fd in e->fd. */ static inline unsigned hashsocket(struct event_map_entry *e) { /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to * matter. Our hashtable implementation really likes low-order bits, * though, so let's do the rotate-and-add trick. */ unsigned h = (unsigned) e->fd; h += (h >> 2) | (h << 30); return h; } /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2 * have the same e->fd. */ static inline int eqsocket(struct event_map_entry *e1, struct event_map_entry *e2) { return e1->fd == e2->fd; } HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket) HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket, 0.5, mm_malloc, mm_realloc, mm_free) #define GET_IO_SLOT(x, map, slot, type) \ do { \ struct event_map_entry key_, *ent_; \ key_.fd = slot; \ ent_ = HT_FIND(event_io_map, map, &key_); \ (x) = ent_ ? &ent_->ent.type : NULL; \ } while (0); #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ do { \ struct event_map_entry key_, *ent_; \ key_.fd = slot; \ HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \ event_map_entry, &key_, ptr, \ { \ ent_ = *ptr; \ }, \ { \ ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \ if (EVUTIL_UNLIKELY(ent_ == NULL)) \ return (-1); \ ent_->fd = slot; \ (ctor)(&ent_->ent.type); \ HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \ }); \ (x) = &ent_->ent.type; \ } while (0) void evmap_io_initmap_(struct event_io_map *ctx) { HT_INIT(event_io_map, ctx); } void evmap_io_clear_(struct event_io_map *ctx) { struct event_map_entry **ent, **next, *this; for (ent = HT_START(event_io_map, ctx); ent; ent = next) { this = *ent; next = HT_NEXT_RMV(event_io_map, ctx, ent); mm_free(this); } HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */ } #endif /* Set the variable 'x' to the field in event_map 'map' with fields of type 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL if there are no entries for 'slot'. Does no bounds-checking. */ #define GET_SIGNAL_SLOT(x, map, slot, type) \ (x) = (struct type *)((map)->entries[slot]) /* As GET_SLOT, but construct the entry for 'slot' if it is not present, by allocating enough memory for a 'struct type', and initializing the new value by calling the function 'ctor' on it. Makes the function return -1 on allocation failure. */ #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ do { \ if ((map)->entries[slot] == NULL) { \ (map)->entries[slot] = \ mm_calloc(1,sizeof(struct type)+fdinfo_len); \ if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \ return (-1); \ (ctor)((struct type *)(map)->entries[slot]); \ } \ (x) = (struct type *)((map)->entries[slot]); \ } while (0) /* If we aren't using hashtables, then define the IO_SLOT macros and functions as thin aliases over the SIGNAL_SLOT versions. */ #ifndef EVMAP_USE_HT #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type) #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \ GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) #define FDINFO_OFFSET sizeof(struct evmap_io) void evmap_io_initmap_(struct event_io_map* ctx) { evmap_signal_initmap_(ctx); } void evmap_io_clear_(struct event_io_map* ctx) { evmap_signal_clear_(ctx); } #endif /** Expand 'map' with new entries of width 'msize' until it is big enough to store a value in 'slot'. */ static int evmap_make_space(struct event_signal_map *map, int slot, int msize) { if (map->nentries <= slot) { int nentries = map->nentries ? map->nentries : 32; void **tmp; if (slot > INT_MAX / 2) return (-1); while (nentries <= slot) nentries <<= 1; if (nentries > INT_MAX / msize) return (-1); tmp = (void **)mm_realloc(map->entries, nentries * msize); if (tmp == NULL) return (-1); memset(&tmp[map->nentries], 0, (nentries - map->nentries) * msize); map->nentries = nentries; map->entries = tmp; } return (0); } void evmap_signal_initmap_(struct event_signal_map *ctx) { ctx->nentries = 0; ctx->entries = NULL; } void evmap_signal_clear_(struct event_signal_map *ctx) { if (ctx->entries != NULL) { int i; for (i = 0; i < ctx->nentries; ++i) { if (ctx->entries[i] != NULL) mm_free(ctx->entries[i]); } mm_free(ctx->entries); ctx->entries = NULL; } ctx->nentries = 0; } /* code specific to file descriptors */ /** Constructor for struct evmap_io */ static void evmap_io_init(struct evmap_io *entry) { LIST_INIT(&entry->events); entry->nread = 0; entry->nwrite = 0; entry->nclose = 0; } /* return -1 on error, 0 on success if nothing changed in the event backend, * and 1 on success if something did. */ int evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev) { const struct eventop *evsel = base->evsel; struct event_io_map *io = &base->io; struct evmap_io *ctx = NULL; int nread, nwrite, nclose, retval = 0; short res = 0, old = 0; struct event *old_ev; EVUTIL_ASSERT(fd == ev->ev_fd); if (fd < 0) return 0; #ifndef EVMAP_USE_HT if (fd >= io->nentries) { if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1) return (-1); } #endif GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init, evsel->fdinfo_len); nread = ctx->nread; nwrite = ctx->nwrite; nclose = ctx->nclose; if (nread) old |= EV_READ; if (nwrite) old |= EV_WRITE; if (nclose) old |= EV_CLOSED; if (ev->ev_events & EV_READ) { if (++nread == 1) res |= EV_READ; } if (ev->ev_events & EV_WRITE) { if (++nwrite == 1) res |= EV_WRITE; } if (ev->ev_events & EV_CLOSED) { if (++nclose == 1) res |= EV_CLOSED; } if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) { event_warnx("Too many events reading or writing on fd %d", (int)fd); return -1; } if (EVENT_DEBUG_MODE_IS_ON() && (old_ev = LIST_FIRST(&ctx->events)) && (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) { event_warnx("Tried to mix edge-triggered and non-edge-triggered" " events on fd %d", (int)fd); return -1; } if (res) { void *extra = ((char*)ctx) + sizeof(struct evmap_io); /* XXX(niels): we cannot mix edge-triggered and * level-triggered, we should probably assert on * this. */ if (evsel->add(base, ev->ev_fd, old, (ev->ev_events & EV_ET) | res, extra) == -1) return (-1); retval = 1; } ctx->nread = (ev_uint16_t) nread; ctx->nwrite = (ev_uint16_t) nwrite; ctx->nclose = (ev_uint16_t) nclose; LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next); return (retval); } /* return -1 on error, 0 on success if nothing changed in the event backend, * and 1 on success if something did. */ int evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev) { const struct eventop *evsel = base->evsel; struct event_io_map *io = &base->io; struct evmap_io *ctx; int nread, nwrite, nclose, retval = 0; short res = 0, old = 0; if (fd < 0) return 0; EVUTIL_ASSERT(fd == ev->ev_fd); #ifndef EVMAP_USE_HT if (fd >= io->nentries) return (-1); #endif GET_IO_SLOT(ctx, io, fd, evmap_io); nread = ctx->nread; nwrite = ctx->nwrite; nclose = ctx->nclose; if (nread) old |= EV_READ; if (nwrite) old |= EV_WRITE; if (nclose) old |= EV_CLOSED; if (ev->ev_events & EV_READ) { if (--nread == 0) res |= EV_READ; EVUTIL_ASSERT(nread >= 0); } if (ev->ev_events & EV_WRITE) { if (--nwrite == 0) res |= EV_WRITE; EVUTIL_ASSERT(nwrite >= 0); } if (ev->ev_events & EV_CLOSED) { if (--nclose == 0) res |= EV_CLOSED; EVUTIL_ASSERT(nclose >= 0); } if (res) { void *extra = ((char*)ctx) + sizeof(struct evmap_io); if (evsel->del(base, ev->ev_fd, old, (ev->ev_events & EV_ET) | res, extra) == -1) { retval = -1; } else { retval = 1; } } ctx->nread = nread; ctx->nwrite = nwrite; ctx->nclose = nclose; LIST_REMOVE(ev, ev_io_next); return (retval); } void evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events) { struct event_io_map *io = &base->io; struct evmap_io *ctx; struct event *ev; #ifndef EVMAP_USE_HT if (fd < 0 || fd >= io->nentries) return; #endif GET_IO_SLOT(ctx, io, fd, evmap_io); if (NULL == ctx) return; LIST_FOREACH(ev, &ctx->events, ev_io_next) { if (ev->ev_events & (events & ~EV_ET)) event_active_nolock_(ev, ev->ev_events & events, 1); } } /* code specific to signals */ static void evmap_signal_init(struct evmap_signal *entry) { LIST_INIT(&entry->events); } int evmap_signal_add_(struct event_base *base, int sig, struct event *ev) { const struct eventop *evsel = base->evsigsel; struct event_signal_map *map = &base->sigmap; struct evmap_signal *ctx = NULL; if (sig < 0 || sig >= NSIG) return (-1); if (sig >= map->nentries) { if (evmap_make_space( map, sig, sizeof(struct evmap_signal *)) == -1) return (-1); } GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init, base->evsigsel->fdinfo_len); if (LIST_EMPTY(&ctx->events)) { if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next); return (1); } int evmap_signal_del_(struct event_base *base, int sig, struct event *ev) { const struct eventop *evsel = base->evsigsel; struct event_signal_map *map = &base->sigmap; struct evmap_signal *ctx; if (sig < 0 || sig >= map->nentries) return (-1); GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); LIST_REMOVE(ev, ev_signal_next); if (LIST_FIRST(&ctx->events) == NULL) { if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } return (1); } void evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls) { struct event_signal_map *map = &base->sigmap; struct evmap_signal *ctx; struct event *ev; if (sig < 0 || sig >= map->nentries) return; GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); if (!ctx) return; LIST_FOREACH(ev, &ctx->events, ev_signal_next) event_active_nolock_(ev, EV_SIGNAL, ncalls); } void * evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd) { struct evmap_io *ctx; GET_IO_SLOT(ctx, map, fd, evmap_io); if (ctx) return ((char*)ctx) + sizeof(struct evmap_io); else return NULL; } /* Callback type for evmap_io_foreach_fd */ typedef int (*evmap_io_foreach_fd_cb)( struct event_base *, evutil_socket_t, struct evmap_io *, void *); /* Multipurpose helper function: Iterate over every file descriptor event_base * for which we could have EV_READ or EV_WRITE events. For each such fd, call * fn(base, signum, evmap_io, arg), where fn is the user-provided * function, base is the event_base, signum is the signal number, evmap_io * is an evmap_io structure containing a list of events pending on the * file descriptor, and arg is the user-supplied argument. * * If fn returns 0, continue on to the next signal. Otherwise, return the same * value that fn returned. * * Note that there is no guarantee that the file descriptors will be processed * in any particular order. */ static int evmap_io_foreach_fd(struct event_base *base, evmap_io_foreach_fd_cb fn, void *arg) { evutil_socket_t fd; struct event_io_map *iomap = &base->io; int r = 0; #ifdef EVMAP_USE_HT struct event_map_entry **mapent; HT_FOREACH(mapent, event_io_map, iomap) { struct evmap_io *ctx = &(*mapent)->ent.evmap_io; fd = (*mapent)->fd; #else for (fd = 0; fd < iomap->nentries; ++fd) { struct evmap_io *ctx = iomap->entries[fd]; if (!ctx) continue; #endif if ((r = fn(base, fd, ctx, arg))) break; } return r; } /* Callback type for evmap_signal_foreach_signal */ typedef int (*evmap_signal_foreach_signal_cb)( struct event_base *, int, struct evmap_signal *, void *); /* Multipurpose helper function: Iterate over every signal number in the * event_base for which we could have signal events. For each such signal, * call fn(base, signum, evmap_signal, arg), where fn is the user-provided * function, base is the event_base, signum is the signal number, evmap_signal * is an evmap_signal structure containing a list of events pending on the * signal, and arg is the user-supplied argument. * * If fn returns 0, continue on to the next signal. Otherwise, return the same * value that fn returned. */ static int evmap_signal_foreach_signal(struct event_base *base, evmap_signal_foreach_signal_cb fn, void *arg) { struct event_signal_map *sigmap = &base->sigmap; int r = 0; int signum; for (signum = 0; signum < sigmap->nentries; ++signum) { struct evmap_signal *ctx = sigmap->entries[signum]; if (!ctx) continue; if ((r = fn(base, signum, ctx, arg))) break; } return r; } /* Helper for evmap_reinit_: tell the backend to add every fd for which we have * pending events, with the appropriate combination of EV_READ, EV_WRITE, and * EV_ET. */ static int evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *ctx, void *arg) { const struct eventop *evsel = base->evsel; void *extra; int *result = arg; short events = 0; struct event *ev; EVUTIL_ASSERT(ctx); extra = ((char*)ctx) + sizeof(struct evmap_io); if (ctx->nread) events |= EV_READ; if (ctx->nwrite) events |= EV_WRITE; if (ctx->nclose) events |= EV_CLOSED; if (evsel->fdinfo_len) memset(extra, 0, evsel->fdinfo_len); if (events && (ev = LIST_FIRST(&ctx->events)) && (ev->ev_events & EV_ET)) events |= EV_ET; if (evsel->add(base, fd, 0, events, extra) == -1) *result = -1; return 0; } /* Helper for evmap_reinit_: tell the backend to add every signal for which we * have pending events. */ static int evmap_signal_reinit_iter_fn(struct event_base *base, int signum, struct evmap_signal *ctx, void *arg) { const struct eventop *evsel = base->evsigsel; int *result = arg; if (!LIST_EMPTY(&ctx->events)) { if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1) *result = -1; } return 0; } int evmap_reinit_(struct event_base *base) { int result = 0; evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result); if (result < 0) return -1; evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result); if (result < 0) return -1; return 0; } /* Helper for evmap_delete_all_: delete every event in an event_dlist. */ static int delete_all_in_dlist(struct event_dlist *dlist) { struct event *ev; while ((ev = LIST_FIRST(dlist))) event_del(ev); return 0; } /* Helper for evmap_delete_all_: delete every event pending on an fd. */ static int evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg) { return delete_all_in_dlist(&io_info->events); } /* Helper for evmap_delete_all_: delete every event pending on a signal. */ static int evmap_signal_delete_all_iter_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg) { return delete_all_in_dlist(&sig_info->events); } void evmap_delete_all_(struct event_base *base) { evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL); evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL); } /** Per-fd structure for use with changelists. It keeps track, for each fd or * signal using the changelist, of where its entry in the changelist is. */ struct event_changelist_fdinfo { int idxplus1; /* this is the index +1, so that memset(0) will make it * a no-such-element */ }; void event_changelist_init_(struct event_changelist *changelist) { changelist->changes = NULL; changelist->changes_size = 0; changelist->n_changes = 0; } /** Helper: return the changelist_fdinfo corresponding to a given change. */ static inline struct event_changelist_fdinfo * event_change_get_fdinfo(struct event_base *base, const struct event_change *change) { char *ptr; if (change->read_change & EV_CHANGE_SIGNAL) { struct evmap_signal *ctx; GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal); ptr = ((char*)ctx) + sizeof(struct evmap_signal); } else { struct evmap_io *ctx; GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io); ptr = ((char*)ctx) + sizeof(struct evmap_io); } return (void*)ptr; } /** Callback helper for event_changelist_assert_ok */ static int event_changelist_assert_ok_foreach_iter_fn( struct event_base *base, evutil_socket_t fd, struct evmap_io *io, void *arg) { struct event_changelist *changelist = &base->changelist; struct event_changelist_fdinfo *f; f = (void*) ( ((char*)io) + sizeof(struct evmap_io) ); if (f->idxplus1) { struct event_change *c = &changelist->changes[f->idxplus1 - 1]; EVUTIL_ASSERT(c->fd == fd); } return 0; } /** Make sure that the changelist is consistent with the evmap structures. */ static void event_changelist_assert_ok(struct event_base *base) { int i; struct event_changelist *changelist = &base->changelist; EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes); for (i = 0; i < changelist->n_changes; ++i) { struct event_change *c = &changelist->changes[i]; struct event_changelist_fdinfo *f; EVUTIL_ASSERT(c->fd >= 0); f = event_change_get_fdinfo(base, c); EVUTIL_ASSERT(f); EVUTIL_ASSERT(f->idxplus1 == i + 1); } evmap_io_foreach_fd(base, event_changelist_assert_ok_foreach_iter_fn, NULL); } #ifdef DEBUG_CHANGELIST #define event_changelist_check(base) event_changelist_assert_ok((base)) #else #define event_changelist_check(base) ((void)0) #endif void event_changelist_remove_all_(struct event_changelist *changelist, struct event_base *base) { int i; event_changelist_check(base); for (i = 0; i < changelist->n_changes; ++i) { struct event_change *ch = &changelist->changes[i]; struct event_changelist_fdinfo *fdinfo = event_change_get_fdinfo(base, ch); EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1); fdinfo->idxplus1 = 0; } changelist->n_changes = 0; event_changelist_check(base); } void event_changelist_freemem_(struct event_changelist *changelist) { if (changelist->changes) mm_free(changelist->changes); event_changelist_init_(changelist); /* zero it all out. */ } /** Increase the size of 'changelist' to hold more changes. */ static int event_changelist_grow(struct event_changelist *changelist) { int new_size; struct event_change *new_changes; if (changelist->changes_size < 64) new_size = 64; else new_size = changelist->changes_size * 2; new_changes = mm_realloc(changelist->changes, new_size * sizeof(struct event_change)); if (EVUTIL_UNLIKELY(new_changes == NULL)) return (-1); changelist->changes = new_changes; changelist->changes_size = new_size; return (0); } /** Return a pointer to the changelist entry for the file descriptor or signal * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its * old_events field to old_events. */ static struct event_change * event_changelist_get_or_construct(struct event_changelist *changelist, evutil_socket_t fd, short old_events, struct event_changelist_fdinfo *fdinfo) { struct event_change *change; if (fdinfo->idxplus1 == 0) { int idx; EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size); if (changelist->n_changes == changelist->changes_size) { if (event_changelist_grow(changelist) < 0) return NULL; } idx = changelist->n_changes++; change = &changelist->changes[idx]; fdinfo->idxplus1 = idx + 1; memset(change, 0, sizeof(struct event_change)); change->fd = fd; change->old_events = old_events; } else { change = &changelist->changes[fdinfo->idxplus1 - 1]; EVUTIL_ASSERT(change->fd == fd); } return change; } int event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events, void *p) { struct event_changelist *changelist = &base->changelist; struct event_changelist_fdinfo *fdinfo = p; struct event_change *change; ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); event_changelist_check(base); change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); if (!change) return -1; /* An add replaces any previous delete, but doesn't result in a no-op, * since the delete might fail (because the fd had been closed since * the last add, for instance. */ if (events & (EV_READ|EV_SIGNAL)) change->read_change = evchange; if (events & EV_WRITE) change->write_change = evchange; if (events & EV_CLOSED) change->close_change = evchange; event_changelist_check(base); return (0); } int event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events, void *p) { struct event_changelist *changelist = &base->changelist; struct event_changelist_fdinfo *fdinfo = p; struct event_change *change; ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET); event_changelist_check(base); change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); event_changelist_check(base); if (!change) return -1; /* A delete on an event set that doesn't contain the event to be deleted produces a no-op. This effectively emoves any previous uncommitted add, rather than replacing it: on those platforms where "add, delete, dispatch" is not the same as "no-op, dispatch", we want the no-op behavior. If we have a no-op item, we could remove it it from the list entirely, but really there's not much point: skipping the no-op change when we do the dispatch later is far cheaper than rejuggling the array now. As this stands, it also lets through deletions of events that are not currently set. */ if (events & (EV_READ|EV_SIGNAL)) { if (!(change->old_events & (EV_READ | EV_SIGNAL))) change->read_change = 0; else change->read_change = del; } if (events & EV_WRITE) { if (!(change->old_events & EV_WRITE)) change->write_change = 0; else change->write_change = del; } if (events & EV_CLOSED) { if (!(change->old_events & EV_CLOSED)) change->close_change = 0; else change->close_change = del; } event_changelist_check(base); return (0); } /* Helper for evmap_check_integrity_: verify that all of the events pending on * given fd are set up correctly, and that the nread and nwrite counts on that * fd are correct. */ static int evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg) { struct event *ev; int n_read = 0, n_write = 0, n_close = 0; /* First, make sure the list itself isn't corrupt. Otherwise, * running LIST_FOREACH could be an exciting adventure. */ EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next); LIST_FOREACH(ev, &io_info->events, ev_io_next) { EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED); EVUTIL_ASSERT(ev->ev_fd == fd); EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL)); EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))); if (ev->ev_events & EV_READ) ++n_read; if (ev->ev_events & EV_WRITE) ++n_write; if (ev->ev_events & EV_CLOSED) ++n_close; } EVUTIL_ASSERT(n_read == io_info->nread); EVUTIL_ASSERT(n_write == io_info->nwrite); EVUTIL_ASSERT(n_close == io_info->nclose); return 0; } /* Helper for evmap_check_integrity_: verify that all of the events pending * on given signal are set up correctly. */ static int evmap_signal_check_integrity_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg) { struct event *ev; /* First, make sure the list itself isn't corrupt. */ EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next); LIST_FOREACH(ev, &sig_info->events, ev_io_next) { EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED); EVUTIL_ASSERT(ev->ev_fd == signum); EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL)); EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))); } return 0; } void evmap_check_integrity_(struct event_base *base) { evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL); evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL); if (base->evsel->add == event_changelist_add_) event_changelist_assert_ok(base); } /* Helper type for evmap_foreach_event_: Bundles a function to call on every * event, and the user-provided void* to use as its third argument. */ struct evmap_foreach_event_helper { event_base_foreach_event_cb fn; void *arg; }; /* Helper for evmap_foreach_event_: calls a provided function on every event * pending on a given fd. */ static int evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg) { struct evmap_foreach_event_helper *h = arg; struct event *ev; int r; LIST_FOREACH(ev, &io_info->events, ev_io_next) { if ((r = h->fn(base, ev, h->arg))) return r; } return 0; } /* Helper for evmap_foreach_event_: calls a provided function on every event * pending on a given signal. */ static int evmap_signal_foreach_event_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg) { struct event *ev; struct evmap_foreach_event_helper *h = arg; int r; LIST_FOREACH(ev, &sig_info->events, ev_signal_next) { if ((r = h->fn(base, ev, h->arg))) return r; } return 0; } int evmap_foreach_event_(struct event_base *base, event_base_foreach_event_cb fn, void *arg) { struct evmap_foreach_event_helper h; int r; h.fn = fn; h.arg = arg; if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h))) return r; return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h); } lldpd-1.0.13/libevent/http.c0000644000076400001440000036574614111362570016351 0ustar00bernatusers00000000000000/* * Copyright (c) 2002-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_SYS_PARAM_H #include #endif #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_IOCCOM_H #include #endif #ifdef EVENT__HAVE_SYS_RESOURCE_H #include #endif #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #ifdef EVENT__HAVE_SYS_WAIT_H #include #endif #ifndef _WIN32 #include #include #else /* _WIN32 */ #include #include #endif /* _WIN32 */ #ifdef EVENT__HAVE_SYS_UN_H #include #endif #ifdef EVENT__HAVE_AFUNIX_H #include #endif #include #ifdef EVENT__HAVE_NETINET_IN_H #include #endif #ifdef EVENT__HAVE_ARPA_INET_H #include #endif #ifdef EVENT__HAVE_NETDB_H #include #endif #ifdef _WIN32 #include #endif #include #include #include #include #ifndef _WIN32 #include #endif /* !_WIN32 */ #include #ifdef EVENT__HAVE_UNISTD_H #include #endif #ifdef EVENT__HAVE_FCNTL_H #include #endif #undef timeout_pending #undef timeout_initialized #include "strlcpy-internal.h" #include "event2/http.h" #include "event2/event.h" #include "event2/buffer.h" #include "event2/bufferevent.h" #include "event2/http_struct.h" #include "event2/http_compat.h" #include "event2/util.h" #include "event2/listener.h" #include "log-internal.h" #include "util-internal.h" #include "http-internal.h" #include "mm-internal.h" #include "bufferevent-internal.h" #ifndef EVENT__HAVE_GETNAMEINFO #define NI_MAXSERV 32 #define NI_MAXHOST 1025 #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 1 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 2 #endif static int fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; if (serv != NULL) { char tmpserv[16]; evutil_snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); if (strlcpy(serv, tmpserv, servlen) >= servlen) return (-1); } if (host != NULL) { if (flags & NI_NUMERICHOST) { if (strlcpy(host, inet_ntoa(sin->sin_addr), hostlen) >= hostlen) return (-1); else return (0); } else { struct hostent *hp; hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); if (hp == NULL) return (-2); if (strlcpy(host, hp->h_name, hostlen) >= hostlen) return (-1); else return (0); } } return (0); } #endif #define REQ_VERSION_BEFORE(req, major_v, minor_v) \ ((req)->major < (major_v) || \ ((req)->major == (major_v) && (req)->minor < (minor_v))) #define REQ_VERSION_ATLEAST(req, major_v, minor_v) \ ((req)->major > (major_v) || \ ((req)->major == (major_v) && (req)->minor >= (minor_v))) #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif extern int debug; static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse); static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri); static int evhttp_associate_new_request_with_connection( struct evhttp_connection *evcon); static void evhttp_connection_start_detectclose( struct evhttp_connection *evcon); static void evhttp_connection_stop_detectclose( struct evhttp_connection *evcon); static void evhttp_request_dispatch(struct evhttp_connection* evcon); static void evhttp_read_firstline(struct evhttp_connection *evcon, struct evhttp_request *req); static void evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req); static int evhttp_add_header_internal(struct evkeyvalq *headers, const char *key, const char *value); static const char *evhttp_response_phrase_internal(int code); static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t); static void evhttp_write_buffer(struct evhttp_connection *, void (*)(struct evhttp_connection *, void *), void *); static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); /* callbacks for bufferevent */ static void evhttp_read_cb(struct bufferevent *, void *); static void evhttp_write_cb(struct bufferevent *, void *); static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg); static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, const char *hostname); #ifndef EVENT__HAVE_STRSEP /* strsep replacement for platforms that lack it. Only works if * del is one character long. */ static char * strsep(char **s, const char *del) { char *d, *tok; EVUTIL_ASSERT(strlen(del) == 1); if (!s || !*s) return NULL; tok = *s; d = strstr(tok, del); if (d) { *d = '\0'; *s = d + 1; } else *s = NULL; return tok; } #endif static size_t html_replace(const char ch, const char **escaped) { switch (ch) { case '<': *escaped = "<"; return 4; case '>': *escaped = ">"; return 4; case '"': *escaped = """; return 6; case '\'': *escaped = "'"; return 6; case '&': *escaped = "&"; return 5; default: break; } return 1; } /* * Replaces <, >, ", ' and & with <, >, ", * ' and & correspondingly. * * The returned string needs to be freed by the caller. */ char * evhttp_htmlescape(const char *html) { size_t i; size_t new_size = 0, old_size = 0; char *escaped_html, *p; if (html == NULL) return (NULL); old_size = strlen(html); for (i = 0; i < old_size; ++i) { const char *replaced = NULL; const size_t replace_size = html_replace(html[i], &replaced); if (replace_size > EV_SIZE_MAX - new_size) { event_warn("%s: html_replace overflow", __func__); return (NULL); } new_size += replace_size; } if (new_size == EV_SIZE_MAX) return (NULL); p = escaped_html = mm_malloc(new_size + 1); if (escaped_html == NULL) { event_warn("%s: malloc(%lu)", __func__, (unsigned long)(new_size + 1)); return (NULL); } for (i = 0; i < old_size; ++i) { const char *replaced = &html[i]; const size_t len = html_replace(html[i], &replaced); memcpy(p, replaced, len); p += len; } *p = '\0'; return (escaped_html); } /** Given an evhttp_cmd_type, returns a constant string containing the * equivalent HTTP command, or NULL if the evhttp_command_type is * unrecognized. */ static const char * evhttp_method(enum evhttp_cmd_type type) { const char *method; switch (type) { case EVHTTP_REQ_GET: method = "GET"; break; case EVHTTP_REQ_POST: method = "POST"; break; case EVHTTP_REQ_HEAD: method = "HEAD"; break; case EVHTTP_REQ_PUT: method = "PUT"; break; case EVHTTP_REQ_DELETE: method = "DELETE"; break; case EVHTTP_REQ_OPTIONS: method = "OPTIONS"; break; case EVHTTP_REQ_TRACE: method = "TRACE"; break; case EVHTTP_REQ_CONNECT: method = "CONNECT"; break; case EVHTTP_REQ_PATCH: method = "PATCH"; break; default: method = NULL; break; } return (method); } /** * Determines if a response should have a body. * Follows the rules in RFC 2616 section 4.3. * @return 1 if the response MUST have a body; 0 if the response MUST NOT have * a body. */ static int evhttp_response_needs_body(struct evhttp_request *req) { return (req->response_code != HTTP_NOCONTENT && req->response_code != HTTP_NOTMODIFIED && (req->response_code < 100 || req->response_code >= 200) && req->type != EVHTTP_REQ_CONNECT && req->type != EVHTTP_REQ_HEAD); } /** Helper: called after we've added some data to an evcon's bufferevent's * output buffer. Sets the evconn's writing-is-done callback, and puts * the bufferevent into writing mode. */ static void evhttp_write_buffer(struct evhttp_connection *evcon, void (*cb)(struct evhttp_connection *, void *), void *arg) { event_debug(("%s: preparing to write buffer\n", __func__)); /* Set call back */ evcon->cb = cb; evcon->cb_arg = arg; /* Disable the read callback: we don't actually care about data; * we only care about close detection. (We don't disable reading -- * EV_READ, since we *do* want to learn about any close events.) */ bufferevent_setcb(evcon->bufev, NULL, /*read*/ evhttp_write_cb, evhttp_error_cb, evcon); bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE); } static void evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) { bufferevent_disable(evcon->bufev, EV_WRITE); } static void evhttp_send_continue(struct evhttp_connection *evcon, struct evhttp_request *req) { bufferevent_enable(evcon->bufev, EV_WRITE); evbuffer_add_printf(bufferevent_get_output(evcon->bufev), "HTTP/%d.%d 100 Continue\r\n\r\n", req->major, req->minor); evcon->cb = evhttp_send_continue_done; evcon->cb_arg = NULL; bufferevent_setcb(evcon->bufev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); } /** Helper: returns true iff evconn is in any connected state. */ static int evhttp_connected(struct evhttp_connection *evcon) { switch (evcon->state) { case EVCON_DISCONNECTED: case EVCON_CONNECTING: return (0); case EVCON_IDLE: case EVCON_READING_FIRSTLINE: case EVCON_READING_HEADERS: case EVCON_READING_BODY: case EVCON_READING_TRAILER: case EVCON_WRITING: default: return (1); } } /* Create the headers needed for an outgoing HTTP request, adds them to * the request's header list, and writes the request line to the * connection's output buffer. */ static void evhttp_make_header_request(struct evhttp_connection *evcon, struct evhttp_request *req) { const char *method; evhttp_remove_header(req->output_headers, "Proxy-Connection"); /* Generate request line */ if (!(method = evhttp_method(req->type))) { method = "NULL"; } evbuffer_add_printf(bufferevent_get_output(evcon->bufev), "%s %s HTTP/%d.%d\r\n", method, req->uri, req->major, req->minor); /* Add the content length on a post or put request if missing */ if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) && evhttp_find_header(req->output_headers, "Content-Length") == NULL){ char size[22]; evutil_snprintf(size, sizeof(size), EV_SIZE_FMT, EV_SIZE_ARG(evbuffer_get_length(req->output_buffer))); evhttp_add_header(req->output_headers, "Content-Length", size); } } /** Return true if the list of headers in 'headers', intepreted with respect * to flags, means that we should send a "connection: close" when the request * is done. */ static int evhttp_is_connection_close(int flags, struct evkeyvalq* headers) { if (flags & EVHTTP_PROXY_REQUEST) { /* proxy connection */ const char *connection = evhttp_find_header(headers, "Proxy-Connection"); return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0); } else { const char *connection = evhttp_find_header(headers, "Connection"); return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0); } } static int evhttp_is_request_connection_close(struct evhttp_request *req) { if (req->type == EVHTTP_REQ_CONNECT) return 0; return evhttp_is_connection_close(req->flags, req->input_headers) || evhttp_is_connection_close(req->flags, req->output_headers); } /* Return true iff 'headers' contains 'Connection: keep-alive' */ static int evhttp_is_connection_keepalive(struct evkeyvalq* headers) { const char *connection = evhttp_find_header(headers, "Connection"); return (connection != NULL && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0); } /* Add a correct "Date" header to headers, unless it already has one. */ static void evhttp_maybe_add_date_header(struct evkeyvalq *headers) { if (evhttp_find_header(headers, "Date") == NULL) { char date[50]; if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) { evhttp_add_header(headers, "Date", date); } } } /* Add a "Content-Length" header with value 'content_length' to headers, * unless it already has a content-length or transfer-encoding header. */ static void evhttp_maybe_add_content_length_header(struct evkeyvalq *headers, size_t content_length) { if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && evhttp_find_header(headers, "Content-Length") == NULL) { char len[22]; evutil_snprintf(len, sizeof(len), EV_SIZE_FMT, EV_SIZE_ARG(content_length)); evhttp_add_header(headers, "Content-Length", len); } } /* * Create the headers needed for an HTTP reply in req->output_headers, * and write the first HTTP response for req line to evcon. */ static void evhttp_make_header_response(struct evhttp_connection *evcon, struct evhttp_request *req) { int is_keepalive = evhttp_is_connection_keepalive(req->input_headers); evbuffer_add_printf(bufferevent_get_output(evcon->bufev), "HTTP/%d.%d %d %s\r\n", req->major, req->minor, req->response_code, req->response_code_line); if (req->major == 1) { if (req->minor >= 1) evhttp_maybe_add_date_header(req->output_headers); /* * if the protocol is 1.0; and the connection was keep-alive * we need to add a keep-alive header, too. */ if (req->minor == 0 && is_keepalive) evhttp_add_header(req->output_headers, "Connection", "keep-alive"); if ((req->minor >= 1 || is_keepalive) && evhttp_response_needs_body(req)) { /* * we need to add the content length if the * user did not give it, this is required for * persistent connections to work. */ evhttp_maybe_add_content_length_header( req->output_headers, evbuffer_get_length(req->output_buffer)); } } /* Potentially add headers for unidentified content. */ if (evhttp_response_needs_body(req)) { if (evhttp_find_header(req->output_headers, "Content-Type") == NULL && evcon->http_server->default_content_type) { evhttp_add_header(req->output_headers, "Content-Type", evcon->http_server->default_content_type); } } /* if the request asked for a close, we send a close, too */ if (evhttp_is_connection_close(req->flags, req->input_headers)) { evhttp_remove_header(req->output_headers, "Connection"); if (!(req->flags & EVHTTP_PROXY_REQUEST)) evhttp_add_header(req->output_headers, "Connection", "close"); evhttp_remove_header(req->output_headers, "Proxy-Connection"); } } enum expect { NO, CONTINUE, OTHER }; static enum expect evhttp_have_expect(struct evhttp_request *req, int input) { const char *expect; struct evkeyvalq *h = input ? req->input_headers : req->output_headers; if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1)) return NO; expect = evhttp_find_header(h, "Expect"); if (!expect) return NO; return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER; } /** Generate all headers appropriate for sending the http request in req (or * the response, if we're sending a response), and write them to evcon's * bufferevent. Also writes all data from req->output_buffer */ static void evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) { struct evkeyval *header; struct evbuffer *output = bufferevent_get_output(evcon->bufev); /* * Depending if this is a HTTP request or response, we might need to * add some new headers or remove existing headers. */ if (req->kind == EVHTTP_REQUEST) { evhttp_make_header_request(evcon, req); } else { evhttp_make_header_response(evcon, req); } TAILQ_FOREACH(header, req->output_headers, next) { evbuffer_add_printf(output, "%s: %s\r\n", header->key, header->value); } evbuffer_add(output, "\r\n", 2); if (evhttp_have_expect(req, 0) != CONTINUE && evbuffer_get_length(req->output_buffer)) { /* * For a request, we add the POST data, for a reply, this * is the regular data. */ evbuffer_add_buffer(output, req->output_buffer); } } void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, ev_ssize_t new_max_headers_size) { if (new_max_headers_size<0) evcon->max_headers_size = EV_SIZE_MAX; else evcon->max_headers_size = new_max_headers_size; } void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, ev_ssize_t new_max_body_size) { if (new_max_body_size<0) evcon->max_body_size = EV_UINT64_MAX; else evcon->max_body_size = new_max_body_size; } static int evhttp_connection_incoming_fail(struct evhttp_request *req, enum evhttp_request_error error) { switch (error) { case EVREQ_HTTP_DATA_TOO_LONG: req->response_code = HTTP_ENTITYTOOLARGE; break; default: req->response_code = HTTP_BADREQUEST; } switch (error) { case EVREQ_HTTP_TIMEOUT: case EVREQ_HTTP_EOF: /* * these are cases in which we probably should just * close the connection and not send a reply. this * case may happen when a browser keeps a persistent * connection open and we timeout on the read. when * the request is still being used for sending, we * need to disassociated it from the connection here. */ if (!req->userdone) { /* remove it so that it will not be freed */ TAILQ_REMOVE(&req->evcon->requests, req, next); /* indicate that this request no longer has a * connection object */ req->evcon = NULL; } return (-1); case EVREQ_HTTP_INVALID_HEADER: case EVREQ_HTTP_BUFFER_ERROR: case EVREQ_HTTP_REQUEST_CANCEL: case EVREQ_HTTP_DATA_TOO_LONG: default: /* xxx: probably should just error on default */ /* the callback looks at the uri to determine errors */ if (req->uri) { mm_free(req->uri); req->uri = NULL; } if (req->uri_elems) { evhttp_uri_free(req->uri_elems); req->uri_elems = NULL; } /* * the callback needs to send a reply, once the reply has * been send, the connection should get freed. */ (*req->cb)(req, req->cb_arg); } return (0); } /* Free connection ownership of which can be acquired by user using * evhttp_request_own(). */ static inline void evhttp_request_free_auto(struct evhttp_request *req) { if (!(req->flags & EVHTTP_USER_OWNED)) evhttp_request_free(req); } static void evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req) { TAILQ_REMOVE(&evcon->requests, req, next); evhttp_request_free_auto(req); } /* Called when evcon has experienced a (non-recoverable? -NM) error, as * given in error. If it's an outgoing connection, reset the connection, * retry any pending requests, and inform the user. If it's incoming, * delegates to evhttp_connection_incoming_fail(). */ void evhttp_connection_fail_(struct evhttp_connection *evcon, enum evhttp_request_error error) { const int errsave = EVUTIL_SOCKET_ERROR(); struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); void (*cb)(struct evhttp_request *, void *); void *cb_arg; void (*error_cb)(enum evhttp_request_error, void *); void *error_cb_arg; EVUTIL_ASSERT(req != NULL); bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); if (evcon->flags & EVHTTP_CON_INCOMING) { /* * for incoming requests, there are two different * failure cases. it's either a network level error * or an http layer error. for problems on the network * layer like timeouts we just drop the connections. * For HTTP problems, we might have to send back a * reply before the connection can be freed. */ if (evhttp_connection_incoming_fail(req, error) == -1) evhttp_connection_free(evcon); return; } error_cb = req->error_cb; error_cb_arg = req->cb_arg; /* when the request was canceled, the callback is not executed */ if (error != EVREQ_HTTP_REQUEST_CANCEL) { /* save the callback for later; the cb might free our object */ cb = req->cb; cb_arg = req->cb_arg; } else { cb = NULL; cb_arg = NULL; } /* do not fail all requests; the next request is going to get * send over a new connection. when a user cancels a request, * all other pending requests should be processed as normal */ evhttp_request_free_(evcon, req); /* reset the connection */ evhttp_connection_reset_(evcon); /* We are trying the next request that was queued on us */ if (TAILQ_FIRST(&evcon->requests) != NULL) evhttp_connection_connect_(evcon); else if ((evcon->flags & EVHTTP_CON_OUTGOING) && (evcon->flags & EVHTTP_CON_AUTOFREE)) { evhttp_connection_free(evcon); } /* The call to evhttp_connection_reset_ overwrote errno. * Let's restore the original errno, so that the user's * callback can have a better idea of what the error was. */ EVUTIL_SET_SOCKET_ERROR(errsave); /* inform the user */ if (error_cb != NULL) error_cb(error, error_cb_arg); if (cb != NULL) (*cb)(NULL, cb_arg); } /* Bufferevent callback: invoked when any data has been written from an * http connection's bufferevent */ static void evhttp_write_cb(struct bufferevent *bufev, void *arg) { struct evhttp_connection *evcon = arg; /* Activate our call back */ if (evcon->cb != NULL) (*evcon->cb)(evcon, evcon->cb_arg); } /** * Advance the connection state. * - If this is an outgoing connection, we've just processed the response; * idle or close the connection. * - If this is an incoming connection, we've just processed the request; * respond. */ static void evhttp_connection_done(struct evhttp_connection *evcon) { struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; int free_evcon = 0; if (con_outgoing) { /* idle or close the connection */ int need_close = evhttp_is_request_connection_close(req); TAILQ_REMOVE(&evcon->requests, req, next); req->evcon = NULL; evcon->state = EVCON_IDLE; /* check if we got asked to close the connection */ if (need_close) evhttp_connection_reset_(evcon); if (TAILQ_FIRST(&evcon->requests) != NULL) { /* * We have more requests; reset the connection * and deal with the next request. */ if (!evhttp_connected(evcon)) evhttp_connection_connect_(evcon); else evhttp_request_dispatch(evcon); } else if (!need_close) { /* * The connection is going to be persistent, but we * need to detect if the other side closes it. */ evhttp_connection_start_detectclose(evcon); } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) { /* * If we have no more requests that need completion * and we're not waiting for the connection to close */ free_evcon = 1; } } else { /* * incoming connection - we need to leave the request on the * connection so that we can reply to it. */ evcon->state = EVCON_WRITING; } /* notify the user of the request */ (*req->cb)(req, req->cb_arg); /* if this was an outgoing request, we own and it's done. so free it. */ if (con_outgoing) { evhttp_request_free_auto(req); } /* If this was the last request of an outgoing connection and we're * not waiting to receive a connection close event and we want to * automatically free the connection. We check to ensure our request * list is empty one last time just in case our callback added a * new request. */ if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) { evhttp_connection_free(evcon); } } /* * Handles reading from a chunked request. * return ALL_DATA_READ: * all data has been read * return MORE_DATA_EXPECTED: * more data is expected * return DATA_CORRUPTED: * data is corrupted * return REQUEST_CANCELED: * request was canceled by the user calling evhttp_cancel_request * return DATA_TOO_LONG: * ran over the maximum limit */ static enum message_read_status evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) { if (req == NULL || buf == NULL) { return DATA_CORRUPTED; } while (1) { size_t buflen; if ((buflen = evbuffer_get_length(buf)) == 0) { break; } /* evbuffer_get_length returns size_t, but len variable is ssize_t, * check for overflow conditions */ if (buflen > EV_SSIZE_MAX) { return DATA_CORRUPTED; } if (req->ntoread < 0) { /* Read chunk size */ ev_int64_t ntoread; char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); char *endp; int error; if (p == NULL) break; /* the last chunk is on a new line? */ if (strlen(p) == 0) { mm_free(p); continue; } ntoread = evutil_strtoll(p, &endp, 16); error = (*p == '\0' || (*endp != '\0' && *endp != ' ') || ntoread < 0); mm_free(p); if (error) { /* could not get chunk size */ return (DATA_CORRUPTED); } /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { return DATA_CORRUPTED; } if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { /* failed body length test */ event_debug(("Request body is too long")); return (DATA_TOO_LONG); } req->body_size += (size_t)ntoread; req->ntoread = ntoread; if (req->ntoread == 0) { /* Last chunk */ return (ALL_DATA_READ); } continue; } /* req->ntoread is signed int64, len is ssize_t, based on arch, * ssize_t could only be 32b, check for these conditions */ if (req->ntoread > EV_SSIZE_MAX) { return DATA_CORRUPTED; } /* don't have enough to complete a chunk; wait for more */ if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) return (MORE_DATA_EXPECTED); /* Completed chunk */ evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); req->ntoread = -1; if (req->chunk_cb != NULL) { req->flags |= EVHTTP_REQ_DEFER_FREE; (*req->chunk_cb)(req, req->cb_arg); evbuffer_drain(req->input_buffer, evbuffer_get_length(req->input_buffer)); req->flags &= ~EVHTTP_REQ_DEFER_FREE; if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { return (REQUEST_CANCELED); } } } return (MORE_DATA_EXPECTED); } static void evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) { struct evbuffer *buf = bufferevent_get_input(evcon->bufev); switch (evhttp_parse_headers_(req, buf)) { case DATA_CORRUPTED: case DATA_TOO_LONG: evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); break; case ALL_DATA_READ: bufferevent_disable(evcon->bufev, EV_READ); evhttp_connection_done(evcon); break; case MORE_DATA_EXPECTED: case REQUEST_CANCELED: /* ??? */ default: break; } } static void evhttp_lingering_close(struct evhttp_connection *evcon, struct evhttp_request *req) { struct evbuffer *buf = bufferevent_get_input(evcon->bufev); size_t n = evbuffer_get_length(buf); if (n > (size_t) req->ntoread) n = (size_t) req->ntoread; req->ntoread -= n; req->body_size += n; event_debug(("Request body is too long, left " EV_I64_FMT, EV_I64_ARG(req->ntoread))); evbuffer_drain(buf, n); if (!req->ntoread) evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); } static void evhttp_lingering_fail(struct evhttp_connection *evcon, struct evhttp_request *req) { if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE) evhttp_lingering_close(evcon, req); else evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); } static void evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) { struct evbuffer *buf = bufferevent_get_input(evcon->bufev); if (req->chunked) { switch (evhttp_handle_chunked_read(req, buf)) { case ALL_DATA_READ: /* finished last chunk */ evcon->state = EVCON_READING_TRAILER; evhttp_read_trailer(evcon, req); return; case DATA_CORRUPTED: case DATA_TOO_LONG: /* corrupted data */ evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); return; case REQUEST_CANCELED: /* request canceled */ evhttp_request_free_auto(req); return; case MORE_DATA_EXPECTED: default: break; } } else if (req->ntoread < 0) { /* Read until connection close. */ if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); return; } req->body_size += evbuffer_get_length(buf); evbuffer_add_buffer(req->input_buffer, buf); } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ /* We've postponed moving the data until now, but we're * about to use it. */ size_t n = evbuffer_get_length(buf); if (n > (size_t) req->ntoread) n = (size_t) req->ntoread; req->ntoread -= n; req->body_size += n; evbuffer_remove_buffer(buf, req->input_buffer, n); } if (req->body_size > req->evcon->max_body_size || (!req->chunked && req->ntoread >= 0 && (size_t)req->ntoread > req->evcon->max_body_size)) { /* XXX: The above casted comparison must checked for overflow */ /* failed body length test */ evhttp_lingering_fail(evcon, req); return; } if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) { req->flags |= EVHTTP_REQ_DEFER_FREE; (*req->chunk_cb)(req, req->cb_arg); req->flags &= ~EVHTTP_REQ_DEFER_FREE; evbuffer_drain(req->input_buffer, evbuffer_get_length(req->input_buffer)); if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { evhttp_request_free_auto(req); return; } } if (!req->ntoread) { bufferevent_disable(evcon->bufev, EV_READ); /* Completed content length */ evhttp_connection_done(evcon); return; } } #define get_deferred_queue(evcon) \ ((evcon)->base) /* * Gets called when more data becomes available */ static void evhttp_read_cb(struct bufferevent *bufev, void *arg) { struct evhttp_connection *evcon = arg; struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); /* Cancel if it's pending. */ event_deferred_cb_cancel_(get_deferred_queue(evcon), &evcon->read_more_deferred_cb); switch (evcon->state) { case EVCON_READING_FIRSTLINE: evhttp_read_firstline(evcon, req); /* note the request may have been freed in * evhttp_read_body */ break; case EVCON_READING_HEADERS: evhttp_read_header(evcon, req); /* note the request may have been freed in * evhttp_read_body */ break; case EVCON_READING_BODY: evhttp_read_body(evcon, req); /* note the request may have been freed in * evhttp_read_body */ break; case EVCON_READING_TRAILER: evhttp_read_trailer(evcon, req); break; case EVCON_IDLE: { #ifdef USE_DEBUG struct evbuffer *input; size_t total_len; input = bufferevent_get_input(evcon->bufev); total_len = evbuffer_get_length(input); event_debug(("%s: read "EV_SIZE_FMT " bytes in EVCON_IDLE state," " resetting connection", __func__, EV_SIZE_ARG(total_len))); #endif evhttp_connection_reset_(evcon); } break; case EVCON_DISCONNECTED: case EVCON_CONNECTING: case EVCON_WRITING: default: event_errx(1, "%s: illegal connection state %d", __func__, evcon->state); } } static void evhttp_deferred_read_cb(struct event_callback *cb, void *data) { struct evhttp_connection *evcon = data; struct bufferevent *bev = evcon->bufev; if (bev->readcb) (bev->readcb)(evcon->bufev, evcon); } static void evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) { /* This is after writing the request to the server */ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); struct evbuffer *output = bufferevent_get_output(evcon->bufev); EVUTIL_ASSERT(req != NULL); EVUTIL_ASSERT(evcon->state == EVCON_WRITING); /* We need to wait until we've written all of our output data before we can * continue */ if (evbuffer_get_length(output) > 0) return; /* We are done writing our header and are now expecting the response */ req->kind = EVHTTP_RESPONSE; evhttp_start_read_(evcon); } /* * Clean up a connection object */ void evhttp_connection_free(struct evhttp_connection *evcon) { struct evhttp_request *req; int need_close = 0; /* notify interested parties that this connection is going down */ if (evcon->fd != -1) { if (evhttp_connected(evcon) && evcon->closecb != NULL) (*evcon->closecb)(evcon, evcon->closecb_arg); } /* remove all requests that might be queued on this * connection. for server connections, this should be empty. * because it gets dequeued either in evhttp_connection_done or * evhttp_connection_fail_. */ while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { evhttp_request_free_(evcon, req); } if (evcon->http_server != NULL) { struct evhttp *http = evcon->http_server; TAILQ_REMOVE(&http->connections, evcon, next); } if (event_initialized(&evcon->retry_ev)) { event_del(&evcon->retry_ev); event_debug_unassign(&evcon->retry_ev); } event_deferred_cb_cancel_(get_deferred_queue(evcon), &evcon->read_more_deferred_cb); if (evcon->bufev != NULL) { need_close = !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE); if (evcon->fd == -1) evcon->fd = bufferevent_getfd(evcon->bufev); bufferevent_free(evcon->bufev); } if (evcon->fd != -1) { shutdown(evcon->fd, EVUTIL_SHUT_WR); if (need_close) evutil_closesocket(evcon->fd); } if (evcon->bind_address != NULL) mm_free(evcon->bind_address); if (evcon->address != NULL) mm_free(evcon->address); mm_free(evcon); } void evhttp_connection_free_on_completion(struct evhttp_connection *evcon) { evcon->flags |= EVHTTP_CON_AUTOFREE; } void evhttp_connection_set_local_address(struct evhttp_connection *evcon, const char *address) { EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); if (evcon->bind_address) mm_free(evcon->bind_address); if ((evcon->bind_address = mm_strdup(address)) == NULL) event_warn("%s: strdup", __func__); } void evhttp_connection_set_local_port(struct evhttp_connection *evcon, ev_uint16_t port) { EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); evcon->bind_port = port; } static void evhttp_request_dispatch(struct evhttp_connection* evcon) { struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); /* this should not usually happy but it's possible */ if (req == NULL) return; EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST); /* delete possible close detection events */ evhttp_connection_stop_detectclose(evcon); /* we assume that the connection is connected already */ EVUTIL_ASSERT(evcon->state == EVCON_IDLE); evcon->state = EVCON_WRITING; /* Create the header from the store arguments */ evhttp_make_header(evcon, req); evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); } /* Reset our connection state: disables reading/writing, closes our fd (if * any), clears out buffers, and puts us in state DISCONNECTED. */ void evhttp_connection_reset_(struct evhttp_connection *evcon) { struct evbuffer *tmp; int err; bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); /* XXXX This is not actually an optimal fix. Instead we ought to have an API for "stop connecting", or use bufferevent_setfd to turn off connecting. But for Libevent 2.0, this seems like a minimal change least likely to disrupt the rest of the bufferevent and http code. Why is this here? If the fd is set in the bufferevent, and the bufferevent is connecting, then you can't actually stop the bufferevent from trying to connect with bufferevent_disable(). The connect will never trigger, since we close the fd, but the timeout might. That caused an assertion failure in evhttp_connection_fail_. */ bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); if (evcon->fd == -1) evcon->fd = bufferevent_getfd(evcon->bufev); if (evcon->fd != -1) { /* inform interested parties about connection close */ if (evhttp_connected(evcon) && evcon->closecb != NULL) (*evcon->closecb)(evcon, evcon->closecb_arg); shutdown(evcon->fd, EVUTIL_SHUT_WR); evutil_closesocket(evcon->fd); evcon->fd = -1; } err = bufferevent_setfd(evcon->bufev, -1); EVUTIL_ASSERT(!err && "setfd"); /* we need to clean up any buffered data */ tmp = bufferevent_get_output(evcon->bufev); err = evbuffer_drain(tmp, -1); EVUTIL_ASSERT(!err && "drain output"); tmp = bufferevent_get_input(evcon->bufev); err = evbuffer_drain(tmp, -1); EVUTIL_ASSERT(!err && "drain input"); evcon->flags &= ~EVHTTP_CON_READING_ERROR; evcon->state = EVCON_DISCONNECTED; } static void evhttp_connection_start_detectclose(struct evhttp_connection *evcon) { evcon->flags |= EVHTTP_CON_CLOSEDETECT; bufferevent_enable(evcon->bufev, EV_READ); } static void evhttp_connection_stop_detectclose(struct evhttp_connection *evcon) { evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; bufferevent_disable(evcon->bufev, EV_READ); } static void evhttp_connection_retry(evutil_socket_t fd, short what, void *arg) { struct evhttp_connection *evcon = arg; evcon->state = EVCON_DISCONNECTED; evhttp_connection_connect_(evcon); } static void evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) { struct evcon_requestq requests; evhttp_connection_reset_(evcon); if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { struct timeval tv_retry = evcon->initial_retry_timeout; int i; evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); /* XXXX handle failure from evhttp_add_event */ for (i=0; i < evcon->retry_cnt; ++i) { tv_retry.tv_usec *= 2; if (tv_retry.tv_usec > 1000000) { tv_retry.tv_usec -= 1000000; tv_retry.tv_sec += 1; } tv_retry.tv_sec *= 2; if (tv_retry.tv_sec > 3600) { tv_retry.tv_sec = 3600; tv_retry.tv_usec = 0; } } event_add(&evcon->retry_ev, &tv_retry); evcon->retry_cnt++; return; } /* * User callback can do evhttp_make_request() on the same * evcon so new request will be added to evcon->requests. To * avoid freeing it prematurely we iterate over the copy of * the queue. */ TAILQ_INIT(&requests); while (TAILQ_FIRST(&evcon->requests) != NULL) { struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); TAILQ_REMOVE(&evcon->requests, request, next); TAILQ_INSERT_TAIL(&requests, request, next); } /* for now, we just signal all requests by executing their callbacks */ while (TAILQ_FIRST(&requests) != NULL) { struct evhttp_request *request = TAILQ_FIRST(&requests); TAILQ_REMOVE(&requests, request, next); request->evcon = NULL; /* we might want to set an error here */ request->cb(request, request->cb_arg); evhttp_request_free_auto(request); } } static void evhttp_connection_read_on_write_error(struct evhttp_connection *evcon, struct evhttp_request *req) { struct evbuffer *buf; /** Second time, we can't read anything */ if (evcon->flags & EVHTTP_CON_READING_ERROR) { evcon->flags &= ~EVHTTP_CON_READING_ERROR; evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); return; } req->kind = EVHTTP_RESPONSE; buf = bufferevent_get_output(evcon->bufev); evbuffer_unfreeze(buf, 1); evbuffer_drain(buf, evbuffer_get_length(buf)); evbuffer_freeze(buf, 1); evhttp_start_read_(evcon); evcon->flags |= EVHTTP_CON_READING_ERROR; } static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) { struct evhttp_connection *evcon = arg; struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); if (evcon->fd == -1) evcon->fd = bufferevent_getfd(bufev); switch (evcon->state) { case EVCON_CONNECTING: if (what & BEV_EVENT_TIMEOUT) { event_debug(("%s: connection timeout for \"%s:%d\" on " EV_SOCK_FMT, __func__, evcon->address, evcon->port, EV_SOCK_ARG(evcon->fd))); evhttp_connection_cb_cleanup(evcon); return; } break; case EVCON_READING_BODY: if (!req->chunked && req->ntoread < 0 && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) { /* EOF on read can be benign */ evhttp_connection_done(evcon); return; } break; case EVCON_DISCONNECTED: case EVCON_IDLE: case EVCON_READING_FIRSTLINE: case EVCON_READING_HEADERS: case EVCON_READING_TRAILER: case EVCON_WRITING: default: break; } /* when we are in close detect mode, a read error means that * the other side closed their connection. */ if (evcon->flags & EVHTTP_CON_CLOSEDETECT) { evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; EVUTIL_ASSERT(evcon->http_server == NULL); /* For connections from the client, we just * reset the connection so that it becomes * disconnected. */ EVUTIL_ASSERT(evcon->state == EVCON_IDLE); evhttp_connection_reset_(evcon); /* * If we have no more requests that need completion * and we want to auto-free the connection when all * requests have been completed. */ if (TAILQ_FIRST(&evcon->requests) == NULL && (evcon->flags & EVHTTP_CON_OUTGOING) && (evcon->flags & EVHTTP_CON_AUTOFREE)) { evhttp_connection_free(evcon); } return; } if (what & BEV_EVENT_TIMEOUT) { evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { if (what & BEV_EVENT_WRITING && evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) { evhttp_connection_read_on_write_error(evcon, req); return; } if (what & BEV_EVENT_READING && evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR && evbuffer_get_length(bufferevent_get_input(bufev))) { event_deferred_cb_schedule_(get_deferred_queue(evcon), &evcon->read_more_deferred_cb); return; } evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); } else if (what == BEV_EVENT_CONNECTED) { } else { evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR); } } /* * Event callback for asynchronous connection attempt. */ static void evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) { struct evhttp_connection *evcon = arg; int error; ev_socklen_t errsz = sizeof(error); if (evcon->fd == -1) evcon->fd = bufferevent_getfd(bufev); if (!(what & BEV_EVENT_CONNECTED)) { /* some operating systems return ECONNREFUSED immediately * when connecting to a local address. the cleanup is going * to reschedule this function call. */ #ifndef _WIN32 if (errno == ECONNREFUSED) goto cleanup; #endif evhttp_error_cb(bufev, what, arg); return; } if (evcon->fd == -1) { event_debug(("%s: bufferevent_getfd returned -1", __func__)); goto cleanup; } /* Check if the connection completed */ if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &errsz) == -1) { event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT, __func__, evcon->address, evcon->port, EV_SOCK_ARG(evcon->fd))); goto cleanup; } if (error) { event_debug(("%s: connect failed for \"%s:%d\" on " EV_SOCK_FMT": %s", __func__, evcon->address, evcon->port, EV_SOCK_ARG(evcon->fd), evutil_socket_error_to_string(error))); goto cleanup; } /* We are connected to the server now */ event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n", __func__, evcon->address, evcon->port, EV_SOCK_ARG(evcon->fd))); /* Reset the retry count as we were successful in connecting */ evcon->retry_cnt = 0; evcon->state = EVCON_IDLE; /* reset the bufferevent cbs */ bufferevent_setcb(evcon->bufev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); if (!evutil_timerisset(&evcon->timeout)) { const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); } else { bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); } /* try to start requests that have queued up on this connection */ evhttp_request_dispatch(evcon); return; cleanup: evhttp_connection_cb_cleanup(evcon); } /* * Check if we got a valid response code. */ static int evhttp_valid_response_code(int code) { if (code == 0) return (0); return (1); } static int evhttp_parse_http_version(const char *version, struct evhttp_request *req) { int major, minor; char ch; int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch); if (n != 2 || major > 1) { event_debug(("%s: bad version %s on message %p from %s", __func__, version, req, req->remote_host)); return (-1); } req->major = major; req->minor = minor; return (0); } /* Parses the status line of a web server */ static int evhttp_parse_response_line(struct evhttp_request *req, char *line) { char *protocol; char *number; const char *readable = ""; protocol = strsep(&line, " "); if (line == NULL) return (-1); number = strsep(&line, " "); if (line != NULL) readable = line; if (evhttp_parse_http_version(protocol, req) < 0) return (-1); req->response_code = atoi(number); if (!evhttp_valid_response_code(req->response_code)) { event_debug(("%s: bad response code \"%s\"", __func__, number)); return (-1); } if (req->response_code_line != NULL) mm_free(req->response_code_line); if ((req->response_code_line = mm_strdup(readable)) == NULL) { event_warn("%s: strdup", __func__); return (-1); } return (0); } /* Parse the first line of a HTTP request */ static int evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len) { char *eos = line + len; char *method; char *uri; char *version; const char *hostname; const char *scheme; size_t method_len; enum evhttp_cmd_type type; while (eos > line && *(eos-1) == ' ') { *(eos-1) = '\0'; --eos; --len; } if (len < strlen("GET / HTTP/1.0")) return -1; /* Parse the request line */ method = strsep(&line, " "); if (!line) return -1; uri = line; version = strrchr(uri, ' '); if (!version || uri == version) return -1; *version = '\0'; version++; method_len = (uri - method) - 1; type = EVHTTP_REQ_UNKNOWN_; /* First line */ switch (method_len) { case 3: /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */ /* Since both GET and PUT share the same character 'T' at the end, * if the string doesn't have 'T', we can immediately determine this * is an invalid HTTP method */ if (method[2] != 'T') { break; } switch (*method) { case 'G': /* This first byte is 'G', so make sure the next byte is * 'E', if it isn't then this isn't a valid method */ if (method[1] == 'E') { type = EVHTTP_REQ_GET; } break; case 'P': /* First byte is P, check second byte for 'U', if not, * we know it's an invalid method */ if (method[1] == 'U') { type = EVHTTP_REQ_PUT; } break; default: break; } break; case 4: /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */ switch (*method) { case 'P': if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') { type = EVHTTP_REQ_POST; } break; case 'H': if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') { type = EVHTTP_REQ_HEAD; } break; default: break; } break; case 5: /* Method length is 5 bytes, which can only encompass PATCH and TRACE */ switch (*method) { case 'P': if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') { type = EVHTTP_REQ_PATCH; } break; case 'T': if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') { type = EVHTTP_REQ_TRACE; } break; default: break; } break; case 6: /* Method length is 6, only valid method 6 bytes in length is DELEte */ /* If the first byte isn't 'D' then it's invalid */ if (*method != 'D') { break; } if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') { type = EVHTTP_REQ_DELETE; } break; case 7: /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */ switch (*method) { case 'O': if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' && method[3] == 'I' && method[2] == 'T' && method[1] == 'P') { type = EVHTTP_REQ_OPTIONS; } break; case 'C': if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' && method[3] == 'N' && method[2] == 'N' && method[1] == 'O') { type = EVHTTP_REQ_CONNECT; } break; default: break; } break; } /* switch */ if ((int)type == EVHTTP_REQ_UNKNOWN_) { event_debug(("%s: bad method %s on request %p from %s", __func__, method, req, req->remote_host)); /* No error yet; we'll give a better error later when * we see that req->type is unsupported. */ } req->type = type; if (evhttp_parse_http_version(version, req) < 0) return -1; if ((req->uri = mm_strdup(uri)) == NULL) { event_debug(("%s: mm_strdup", __func__)); return -1; } if (type == EVHTTP_REQ_CONNECT) { if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) { return -1; } } else { if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, EVHTTP_URI_NONCONFORMANT)) == NULL) { return -1; } } /* If we have an absolute-URI, check to see if it is an http request for a known vhost or server alias. If we don't know about this host, we consider it a proxy request. */ scheme = evhttp_uri_get_scheme(req->uri_elems); hostname = evhttp_uri_get_host(req->uri_elems); if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") || !evutil_ascii_strcasecmp(scheme, "https")) && hostname && !evhttp_find_vhost(req->evcon->http_server, NULL, hostname)) req->flags |= EVHTTP_PROXY_REQUEST; return 0; } const char * evhttp_find_header(const struct evkeyvalq *headers, const char *key) { struct evkeyval *header; TAILQ_FOREACH(header, headers, next) { if (evutil_ascii_strcasecmp(header->key, key) == 0) return (header->value); } return (NULL); } void evhttp_clear_headers(struct evkeyvalq *headers) { struct evkeyval *header; for (header = TAILQ_FIRST(headers); header != NULL; header = TAILQ_FIRST(headers)) { TAILQ_REMOVE(headers, header, next); mm_free(header->key); mm_free(header->value); mm_free(header); } } /* * Returns 0, if the header was successfully removed. * Returns -1, if the header could not be found. */ int evhttp_remove_header(struct evkeyvalq *headers, const char *key) { struct evkeyval *header; TAILQ_FOREACH(header, headers, next) { if (evutil_ascii_strcasecmp(header->key, key) == 0) break; } if (header == NULL) return (-1); /* Free and remove the header that we found */ TAILQ_REMOVE(headers, header, next); mm_free(header->key); mm_free(header->value); mm_free(header); return (0); } static int evhttp_header_is_valid_value(const char *value) { const char *p = value; while ((p = strpbrk(p, "\r\n")) != NULL) { /* we really expect only one new line */ p += strspn(p, "\r\n"); /* we expect a space or tab for continuation */ if (*p != ' ' && *p != '\t') return (0); } return (1); } int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value) { event_debug(("%s: key: %s val: %s\n", __func__, key, value)); if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { /* drop illegal headers */ event_debug(("%s: dropping illegal header key\n", __func__)); return (-1); } if (!evhttp_header_is_valid_value(value)) { event_debug(("%s: dropping illegal header value\n", __func__)); return (-1); } return (evhttp_add_header_internal(headers, key, value)); } static int evhttp_add_header_internal(struct evkeyvalq *headers, const char *key, const char *value) { struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval)); if (header == NULL) { event_warn("%s: calloc", __func__); return (-1); } if ((header->key = mm_strdup(key)) == NULL) { mm_free(header); event_warn("%s: strdup", __func__); return (-1); } if ((header->value = mm_strdup(value)) == NULL) { mm_free(header->key); mm_free(header); event_warn("%s: strdup", __func__); return (-1); } TAILQ_INSERT_TAIL(headers, header, next); return (0); } /* * Parses header lines from a request or a response into the specified * request object given an event buffer. * * Returns * DATA_CORRUPTED on error * MORE_DATA_EXPECTED when we need to read more headers * ALL_DATA_READ when all headers have been read. */ enum message_read_status evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer) { char *line; enum message_read_status status = ALL_DATA_READ; size_t len; /* XXX try */ line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF); if (line == NULL) { if (req->evcon != NULL && evbuffer_get_length(buffer) > req->evcon->max_headers_size) return (DATA_TOO_LONG); else return (MORE_DATA_EXPECTED); } if (req->evcon != NULL && len > req->evcon->max_headers_size) { mm_free(line); return (DATA_TOO_LONG); } req->headers_size = len; switch (req->kind) { case EVHTTP_REQUEST: if (evhttp_parse_request_line(req, line, len) == -1) status = DATA_CORRUPTED; break; case EVHTTP_RESPONSE: if (evhttp_parse_response_line(req, line) == -1) status = DATA_CORRUPTED; break; default: status = DATA_CORRUPTED; } mm_free(line); return (status); } static int evhttp_append_to_last_header(struct evkeyvalq *headers, char *line) { struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); char *newval; size_t old_len, line_len; if (header == NULL) return (-1); old_len = strlen(header->value); /* Strip space from start and end of line. */ while (*line == ' ' || *line == '\t') ++line; evutil_rtrim_lws_(line); line_len = strlen(line); newval = mm_realloc(header->value, old_len + line_len + 2); if (newval == NULL) return (-1); newval[old_len] = ' '; memcpy(newval + old_len + 1, line, line_len + 1); header->value = newval; return (0); } enum message_read_status evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer) { enum message_read_status errcode = DATA_CORRUPTED; char *line; enum message_read_status status = MORE_DATA_EXPECTED; struct evkeyvalq* headers = req->input_headers; size_t len; while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF)) != NULL) { char *skey, *svalue; req->headers_size += len; if (req->evcon != NULL && req->headers_size > req->evcon->max_headers_size) { errcode = DATA_TOO_LONG; goto error; } if (*line == '\0') { /* Last header - Done */ status = ALL_DATA_READ; mm_free(line); break; } /* Check if this is a continuation line */ if (*line == ' ' || *line == '\t') { if (evhttp_append_to_last_header(headers, line) == -1) goto error; mm_free(line); continue; } /* Processing of header lines */ svalue = line; skey = strsep(&svalue, ":"); if (svalue == NULL) goto error; svalue += strspn(svalue, " "); evutil_rtrim_lws_(svalue); if (evhttp_add_header(headers, skey, svalue) == -1) goto error; mm_free(line); } if (status == MORE_DATA_EXPECTED) { if (req->evcon != NULL && req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) return (DATA_TOO_LONG); } return (status); error: mm_free(line); return (errcode); } static int evhttp_get_body_length(struct evhttp_request *req) { struct evkeyvalq *headers = req->input_headers; const char *content_length; const char *connection; content_length = evhttp_find_header(headers, "Content-Length"); connection = evhttp_find_header(headers, "Connection"); if (content_length == NULL && connection == NULL) req->ntoread = -1; else if (content_length == NULL && evutil_ascii_strcasecmp(connection, "Close") != 0) { req->ntoread = 0; } else if (content_length == NULL) { req->ntoread = -1; } else { char *endp; ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10); if (*content_length == '\0' || *endp != '\0' || ntoread < 0) { event_debug(("%s: illegal content length: %s", __func__, content_length)); return (-1); } req->ntoread = ntoread; } event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n", __func__, EV_I64_ARG(req->ntoread), EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev))))); return (0); } static int evhttp_method_may_have_body(enum evhttp_cmd_type type) { switch (type) { case EVHTTP_REQ_POST: case EVHTTP_REQ_PUT: case EVHTTP_REQ_PATCH: case EVHTTP_REQ_GET: case EVHTTP_REQ_DELETE: case EVHTTP_REQ_OPTIONS: case EVHTTP_REQ_CONNECT: return 1; case EVHTTP_REQ_TRACE: case EVHTTP_REQ_HEAD: default: return 0; } } static void evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) { const char *xfer_enc; /* If this is a request without a body, then we are done */ if (req->kind == EVHTTP_REQUEST && !evhttp_method_may_have_body(req->type)) { evhttp_connection_done(evcon); return; } evcon->state = EVCON_READING_BODY; xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { req->chunked = 1; req->ntoread = -1; } else { if (evhttp_get_body_length(req) == -1) { evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); return; } if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) { /* An incoming request with no content-length and no * transfer-encoding has no body. */ evhttp_connection_done(evcon); return; } } /* Should we send a 100 Continue status line? */ switch (evhttp_have_expect(req, 1)) { case CONTINUE: /* XXX It would be nice to do some sanity checking here. Does the resource exist? Should the resource accept post requests? If no, we should respond with an error. For now, just optimistically tell the client to send their message body. */ if (req->ntoread > 0) { /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { evhttp_lingering_fail(evcon, req); return; } } if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) evhttp_send_continue(evcon, req); break; case OTHER: evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL); return; case NO: break; } evhttp_read_body(evcon, req); /* note the request may have been freed in evhttp_read_body */ } static void evhttp_read_firstline(struct evhttp_connection *evcon, struct evhttp_request *req) { enum message_read_status res; res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev)); if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { /* Error while reading, terminate */ event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", __func__, EV_SOCK_ARG(evcon->fd))); evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); return; } else if (res == MORE_DATA_EXPECTED) { /* Need more header lines */ return; } evcon->state = EVCON_READING_HEADERS; evhttp_read_header(evcon, req); } static void evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req) { enum message_read_status res; evutil_socket_t fd = evcon->fd; res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev)); if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { /* Error while reading, terminate */ event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", __func__, EV_SOCK_ARG(fd))); evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); return; } else if (res == MORE_DATA_EXPECTED) { /* Need more header lines */ return; } /* Callback can shut down connection with negative return value */ if (req->header_cb != NULL) { if ((*req->header_cb)(req, req->cb_arg) < 0) { evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); return; } } /* Done reading headers, do the real work */ switch (req->kind) { case EVHTTP_REQUEST: event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n", __func__, EV_SOCK_ARG(fd))); evhttp_get_body(evcon, req); /* note the request may have been freed in evhttp_get_body */ break; case EVHTTP_RESPONSE: /* Start over if we got a 100 Continue response. */ if (req->response_code == 100) { struct evbuffer *output = bufferevent_get_output(evcon->bufev); evbuffer_add_buffer(output, req->output_buffer); evhttp_start_write_(evcon); return; } if (!evhttp_response_needs_body(req)) { event_debug(("%s: skipping body for code %d\n", __func__, req->response_code)); evhttp_connection_done(evcon); } else { event_debug(("%s: start of read body for %s on " EV_SOCK_FMT"\n", __func__, req->remote_host, EV_SOCK_ARG(fd))); evhttp_get_body(evcon, req); /* note the request may have been freed in * evhttp_get_body */ } break; default: event_warnx("%s: bad header on "EV_SOCK_FMT, __func__, EV_SOCK_ARG(fd)); evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); break; } /* request may have been freed above */ } /* * Creates a TCP connection to the specified port and executes a callback * when finished. Failure or success is indicate by the passed connection * object. * * Although this interface accepts a hostname, it is intended to take * only numeric hostnames so that non-blocking DNS resolution can * happen elsewhere. */ struct evhttp_connection * evhttp_connection_new(const char *address, ev_uint16_t port) { return (evhttp_connection_base_new(NULL, NULL, address, port)); } struct evhttp_connection * evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port) { struct evhttp_connection *evcon = NULL; event_debug(("Attempting connection to %s:%d\n", address, port)); if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) { event_warn("%s: calloc failed", __func__); goto error; } evcon->fd = -1; evcon->port = port; evcon->max_headers_size = EV_SIZE_MAX; evcon->max_body_size = EV_SIZE_MAX; evutil_timerclear(&evcon->timeout); evcon->retry_cnt = evcon->retry_max = 0; if ((evcon->address = mm_strdup(address)) == NULL) { event_warn("%s: strdup failed", __func__); goto error; } if (bev == NULL) { if (!(bev = bufferevent_socket_new(base, -1, 0))) { event_warn("%s: bufferevent_socket_new failed", __func__); goto error; } } bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); evcon->bufev = bev; evcon->state = EVCON_DISCONNECTED; TAILQ_INIT(&evcon->requests); evcon->initial_retry_timeout.tv_sec = 2; evcon->initial_retry_timeout.tv_usec = 0; if (base != NULL) { evcon->base = base; if (bufferevent_get_base(bev) != base) bufferevent_base_set(base, evcon->bufev); } event_deferred_cb_init_( &evcon->read_more_deferred_cb, bufferevent_get_priority(bev), evhttp_deferred_read_cb, evcon); evcon->dns_base = dnsbase; evcon->ai_family = AF_UNSPEC; return (evcon); error: if (evcon != NULL) evhttp_connection_free(evcon); return (NULL); } struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon) { return evcon->bufev; } struct evhttp * evhttp_connection_get_server(struct evhttp_connection *evcon) { return evcon->http_server; } struct evhttp_connection * evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, const char *address, ev_uint16_t port) { return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port); } void evhttp_connection_set_family(struct evhttp_connection *evcon, int family) { evcon->ai_family = family; } int evhttp_connection_set_flags(struct evhttp_connection *evcon, int flags) { int avail_flags = 0; avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR; avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR; if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END) return 1; evcon->flags &= ~avail_flags; evcon->flags |= flags; return 0; } void evhttp_connection_set_base(struct evhttp_connection *evcon, struct event_base *base) { EVUTIL_ASSERT(evcon->base == NULL); EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); evcon->base = base; bufferevent_base_set(base, evcon->bufev); } void evhttp_connection_set_timeout(struct evhttp_connection *evcon, int timeout_in_secs) { if (timeout_in_secs == -1) evhttp_connection_set_timeout_tv(evcon, NULL); else { struct timeval tv; tv.tv_sec = timeout_in_secs; tv.tv_usec = 0; evhttp_connection_set_timeout_tv(evcon, &tv); } } void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, const struct timeval* tv) { if (tv) { evcon->timeout = *tv; bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); } else { const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; evutil_timerclear(&evcon->timeout); bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); } } void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, const struct timeval *tv) { if (tv) { evcon->initial_retry_timeout = *tv; } else { evutil_timerclear(&evcon->initial_retry_timeout); evcon->initial_retry_timeout.tv_sec = 2; } } void evhttp_connection_set_retries(struct evhttp_connection *evcon, int retry_max) { evcon->retry_max = retry_max; } void evhttp_connection_set_closecb(struct evhttp_connection *evcon, void (*cb)(struct evhttp_connection *, void *), void *cbarg) { evcon->closecb = cb; evcon->closecb_arg = cbarg; } void evhttp_connection_get_peer(struct evhttp_connection *evcon, char **address, ev_uint16_t *port) { *address = evcon->address; *port = evcon->port; } const struct sockaddr* evhttp_connection_get_addr(struct evhttp_connection *evcon) { return bufferevent_socket_get_conn_address_(evcon->bufev); } int evhttp_connection_connect_(struct evhttp_connection *evcon) { int old_state = evcon->state; const char *address = evcon->address; const struct sockaddr *sa = evhttp_connection_get_addr(evcon); int ret; if (evcon->state == EVCON_CONNECTING) return (0); evhttp_connection_reset_(evcon); EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); evcon->flags |= EVHTTP_CON_OUTGOING; if (evcon->bind_address || evcon->bind_port) { evcon->fd = bind_socket( evcon->bind_address, evcon->bind_port, 0 /*reuse*/); if (evcon->fd == -1) { event_debug(("%s: failed to bind to \"%s\"", __func__, evcon->bind_address)); return (-1); } if (bufferevent_setfd(evcon->bufev, evcon->fd)) return (-1); } else { if (bufferevent_setfd(evcon->bufev, -1)) return (-1); } /* Set up a callback for successful connection setup */ bufferevent_setcb(evcon->bufev, NULL /* evhttp_read_cb */, NULL /* evhttp_write_cb */, evhttp_connection_cb, evcon); if (!evutil_timerisset(&evcon->timeout)) { const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 }; bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv); } else { bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); } /* make sure that we get a write callback */ if (bufferevent_enable(evcon->bufev, EV_WRITE)) return (-1); evcon->state = EVCON_CONNECTING; if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR && sa && (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) { int socklen = sizeof(struct sockaddr_in); if (sa->sa_family == AF_INET6) { socklen = sizeof(struct sockaddr_in6); } ret = bufferevent_socket_connect(evcon->bufev, sa, socklen); } else { ret = bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, evcon->ai_family, address, evcon->port); } if (ret < 0) { evcon->state = old_state; event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", __func__, evcon->address); /* some operating systems return ECONNREFUSED immediately * when connecting to a local address. the cleanup is going * to reschedule this function call. */ evhttp_connection_cb_cleanup(evcon); return (0); } return (0); } /* * Starts an HTTP request on the provided evhttp_connection object. * If the connection object is not connected to the web server already, * this will start the connection. */ int evhttp_make_request(struct evhttp_connection *evcon, struct evhttp_request *req, enum evhttp_cmd_type type, const char *uri) { /* We are making a request */ req->kind = EVHTTP_REQUEST; req->type = type; if (req->uri != NULL) mm_free(req->uri); if ((req->uri = mm_strdup(uri)) == NULL) { event_warn("%s: strdup", __func__); evhttp_request_free_auto(req); return (-1); } /* Set the protocol version if it is not supplied */ if (!req->major && !req->minor) { req->major = 1; req->minor = 1; } EVUTIL_ASSERT(req->evcon == NULL); req->evcon = evcon; EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); TAILQ_INSERT_TAIL(&evcon->requests, req, next); /* We do not want to conflict with retry_ev */ if (evcon->retry_cnt) return (0); /* If the connection object is not connected; make it so */ if (!evhttp_connected(evcon)) { int res = evhttp_connection_connect_(evcon); /* evhttp_connection_fail_(), which is called through * evhttp_connection_connect_(), assumes that req lies in * evcon->requests. Thus, enqueue the request in advance and * remove it in the error case. */ if (res != 0) TAILQ_REMOVE(&evcon->requests, req, next); return (res); } /* * If it's connected already and we are the first in the queue, * then we can dispatch this request immediately. Otherwise, it * will be dispatched once the pending requests are completed. */ if (TAILQ_FIRST(&evcon->requests) == req) evhttp_request_dispatch(evcon); return (0); } void evhttp_cancel_request(struct evhttp_request *req) { struct evhttp_connection *evcon = req->evcon; if (evcon != NULL) { /* We need to remove it from the connection */ if (TAILQ_FIRST(&evcon->requests) == req) { /* it's currently being worked on, so reset * the connection. */ evhttp_connection_fail_(evcon, EVREQ_HTTP_REQUEST_CANCEL); /* connection fail freed the request */ return; } else { /* otherwise, we can just remove it from the * queue */ TAILQ_REMOVE(&evcon->requests, req, next); } } evhttp_request_free_auto(req); } /* * Reads data from file descriptor into request structure * Request structure needs to be set up correctly. */ void evhttp_start_read_(struct evhttp_connection *evcon) { bufferevent_disable(evcon->bufev, EV_WRITE); bufferevent_enable(evcon->bufev, EV_READ); evcon->state = EVCON_READING_FIRSTLINE; /* Reset the bufferevent callbacks */ bufferevent_setcb(evcon->bufev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); /* If there's still data pending, process it next time through the * loop. Don't do it now; that could get recusive. */ if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) { event_deferred_cb_schedule_(get_deferred_queue(evcon), &evcon->read_more_deferred_cb); } } void evhttp_start_write_(struct evhttp_connection *evcon) { bufferevent_disable(evcon->bufev, EV_WRITE); bufferevent_enable(evcon->bufev, EV_READ); evcon->state = EVCON_WRITING; evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); } static void evhttp_send_done(struct evhttp_connection *evcon, void *arg) { int need_close; struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); TAILQ_REMOVE(&evcon->requests, req, next); if (req->on_complete_cb != NULL) { req->on_complete_cb(req, req->on_complete_cb_arg); } need_close = (REQ_VERSION_BEFORE(req, 1, 1) && !evhttp_is_connection_keepalive(req->input_headers)) || evhttp_is_request_connection_close(req); EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); evhttp_request_free(req); if (need_close) { evhttp_connection_free(evcon); return; } /* we have a persistent connection; try to accept another request. */ if (evhttp_associate_new_request_with_connection(evcon) == -1) { evhttp_connection_free(evcon); } } /* * Returns an error page. */ void evhttp_send_error(struct evhttp_request *req, int error, const char *reason) { #define ERR_FORMAT "\n" \ "%d %s\n" \ "\n" \ "

%s

\n" \ "\n" struct evbuffer *buf = evbuffer_new(); if (buf == NULL) { /* if we cannot allocate memory; we just drop the connection */ evhttp_connection_free(req->evcon); return; } if (reason == NULL) { reason = evhttp_response_phrase_internal(error); } evhttp_response_code_(req, error, reason); evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); evhttp_send_page_(req, buf); evbuffer_free(buf); #undef ERR_FORMAT } /* Requires that headers and response code are already set up */ static inline void evhttp_send(struct evhttp_request *req, struct evbuffer *databuf) { struct evhttp_connection *evcon = req->evcon; if (evcon == NULL) { evhttp_request_free(req); return; } EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req); /* we expect no more calls form the user on this request */ req->userdone = 1; /* xxx: not sure if we really should expose the data buffer this way */ if (databuf != NULL) evbuffer_add_buffer(req->output_buffer, databuf); /* Adds headers to the response */ evhttp_make_header(evcon, req); evhttp_write_buffer(evcon, evhttp_send_done, NULL); } void evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *databuf) { evhttp_response_code_(req, code, reason); evhttp_send(req, databuf); } void evhttp_send_reply_start(struct evhttp_request *req, int code, const char *reason) { evhttp_response_code_(req, code, reason); if (req->evcon == NULL) return; if (evhttp_find_header(req->output_headers, "Content-Length") == NULL && REQ_VERSION_ATLEAST(req, 1, 1) && evhttp_response_needs_body(req)) { /* * prefer HTTP/1.1 chunked encoding to closing the connection; * note RFC 2616 section 4.4 forbids it with Content-Length: * and it's not necessary then anyway. */ evhttp_add_header(req->output_headers, "Transfer-Encoding", "chunked"); req->chunked = 1; } else { req->chunked = 0; } evhttp_make_header(req->evcon, req); evhttp_write_buffer(req->evcon, NULL, NULL); } void evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf, void (*cb)(struct evhttp_connection *, void *), void *arg) { struct evhttp_connection *evcon = req->evcon; struct evbuffer *output; if (evcon == NULL) return; output = bufferevent_get_output(evcon->bufev); if (evbuffer_get_length(databuf) == 0) return; if (!evhttp_response_needs_body(req)) return; if (req->chunked) { evbuffer_add_printf(output, "%x\r\n", (unsigned)evbuffer_get_length(databuf)); } evbuffer_add_buffer(output, databuf); if (req->chunked) { evbuffer_add(output, "\r\n", 2); } evhttp_write_buffer(evcon, cb, arg); } void evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) { evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL); } void evhttp_send_reply_end(struct evhttp_request *req) { struct evhttp_connection *evcon = req->evcon; struct evbuffer *output; if (evcon == NULL) { evhttp_request_free(req); return; } output = bufferevent_get_output(evcon->bufev); /* we expect no more calls form the user on this request */ req->userdone = 1; if (req->chunked) { evbuffer_add(output, "0\r\n\r\n", 5); evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); req->chunked = 0; } else if (evbuffer_get_length(output) == 0) { /* let the connection know that we are done with the request */ evhttp_send_done(evcon, NULL); } else { /* make the callback execute after all data has been written */ evcon->cb = evhttp_send_done; evcon->cb_arg = NULL; } } static const char *informational_phrases[] = { /* 100 */ "Continue", /* 101 */ "Switching Protocols" }; static const char *success_phrases[] = { /* 200 */ "OK", /* 201 */ "Created", /* 202 */ "Accepted", /* 203 */ "Non-Authoritative Information", /* 204 */ "No Content", /* 205 */ "Reset Content", /* 206 */ "Partial Content" }; static const char *redirection_phrases[] = { /* 300 */ "Multiple Choices", /* 301 */ "Moved Permanently", /* 302 */ "Found", /* 303 */ "See Other", /* 304 */ "Not Modified", /* 305 */ "Use Proxy", /* 307 */ "Temporary Redirect" }; static const char *client_error_phrases[] = { /* 400 */ "Bad Request", /* 401 */ "Unauthorized", /* 402 */ "Payment Required", /* 403 */ "Forbidden", /* 404 */ "Not Found", /* 405 */ "Method Not Allowed", /* 406 */ "Not Acceptable", /* 407 */ "Proxy Authentication Required", /* 408 */ "Request Time-out", /* 409 */ "Conflict", /* 410 */ "Gone", /* 411 */ "Length Required", /* 412 */ "Precondition Failed", /* 413 */ "Request Entity Too Large", /* 414 */ "Request-URI Too Large", /* 415 */ "Unsupported Media Type", /* 416 */ "Requested range not satisfiable", /* 417 */ "Expectation Failed" }; static const char *server_error_phrases[] = { /* 500 */ "Internal Server Error", /* 501 */ "Not Implemented", /* 502 */ "Bad Gateway", /* 503 */ "Service Unavailable", /* 504 */ "Gateway Time-out", /* 505 */ "HTTP Version not supported" }; struct response_class { const char *name; size_t num_responses; const char **responses; }; #ifndef MEMBERSOF #define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) #endif static const struct response_class response_classes[] = { /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } }; static const char * evhttp_response_phrase_internal(int code) { int klass = code / 100 - 1; int subcode = code % 100; /* Unknown class - can't do any better here */ if (klass < 0 || klass >= (int) MEMBERSOF(response_classes)) return "Unknown Status Class"; /* Unknown sub-code, return class name at least */ if (subcode >= (int) response_classes[klass].num_responses) return response_classes[klass].name; return response_classes[klass].responses[subcode]; } void evhttp_response_code_(struct evhttp_request *req, int code, const char *reason) { req->kind = EVHTTP_RESPONSE; req->response_code = code; if (req->response_code_line != NULL) mm_free(req->response_code_line); if (reason == NULL) reason = evhttp_response_phrase_internal(code); req->response_code_line = mm_strdup(reason); if (req->response_code_line == NULL) { event_warn("%s: strdup", __func__); /* XXX what else can we do? */ } } void evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf) { if (!req->major || !req->minor) { req->major = 1; req->minor = 1; } if (req->kind != EVHTTP_RESPONSE) evhttp_response_code_(req, 200, "OK"); evhttp_clear_headers(req->output_headers); evhttp_add_header(req->output_headers, "Content-Type", "text/html"); evhttp_add_header(req->output_headers, "Connection", "close"); evhttp_send(req, databuf); } static const char uri_chars[256] = { /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 64 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define CHAR_IS_UNRESERVED(c) \ (uri_chars[(unsigned char)(c)]) /* * Helper functions to encode/decode a string for inclusion in a URI. * The returned string must be freed by the caller. */ char * evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus) { struct evbuffer *buf = evbuffer_new(); const char *p, *end; char *result = NULL; if (!buf) { goto out; } if (len >= 0) { if (uri + len < uri) { goto out; } end = uri + len; } else { size_t slen = strlen(uri); if (slen >= EV_SSIZE_MAX) { /* we don't want to mix signed and unsigned */ goto out; } if (uri + slen < uri) { goto out; } end = uri + slen; } for (p = uri; p < end; p++) { if (CHAR_IS_UNRESERVED(*p)) { evbuffer_add(buf, p, 1); } else if (*p == ' ' && space_as_plus) { evbuffer_add(buf, "+", 1); } else { evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p)); } } evbuffer_add(buf, "", 1); /* NUL-terminator. */ result = mm_malloc(evbuffer_get_length(buf)); if (result) evbuffer_remove(buf, result, evbuffer_get_length(buf)); out: if (buf) evbuffer_free(buf); return result; } char * evhttp_encode_uri(const char *str) { return evhttp_uriencode(str, -1, 0); } /* * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't. * If -1, when true we transform plus to space only after we've seen * a ?. -1 is deprecated. * @return the number of bytes written to 'ret'. */ int evhttp_decode_uri_internal( const char *uri, size_t length, char *ret, int decode_plus_ctl) { char c; int j; int decode_plus = (decode_plus_ctl == 1) ? 1: 0; unsigned i; for (i = j = 0; i < length; i++) { c = uri[i]; if (c == '?') { if (decode_plus_ctl < 0) decode_plus = 1; } else if (c == '+' && decode_plus) { c = ' '; } else if ((i + 2) < length && c == '%' && EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) { char tmp[3]; tmp[0] = uri[i+1]; tmp[1] = uri[i+2]; tmp[2] = '\0'; c = (char)strtol(tmp, NULL, 16); i += 2; } ret[j++] = c; } ret[j] = '\0'; return (j); } /* deprecated */ char * evhttp_decode_uri(const char *uri) { char *ret; if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { event_warn("%s: malloc(%lu)", __func__, (unsigned long)(strlen(uri) + 1)); return (NULL); } evhttp_decode_uri_internal(uri, strlen(uri), ret, -1 /*always_decode_plus*/); return (ret); } char * evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out) { char *ret; int n; if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { event_warn("%s: malloc(%lu)", __func__, (unsigned long)(strlen(uri) + 1)); return (NULL); } n = evhttp_decode_uri_internal(uri, strlen(uri), ret, !!decode_plus/*always_decode_plus*/); if (size_out) { EVUTIL_ASSERT(n >= 0); *size_out = (size_t)n; } return (ret); } /* * Helper function to parse out arguments in a query. * The arguments are separated by key and value. */ static int evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers, int is_whole_uri) { char *line=NULL; char *argument; char *p; const char *query_part; int result = -1; struct evhttp_uri *uri=NULL; TAILQ_INIT(headers); if (is_whole_uri) { uri = evhttp_uri_parse(str); if (!uri) goto error; query_part = evhttp_uri_get_query(uri); } else { query_part = str; } /* No arguments - we are done */ if (!query_part || !strlen(query_part)) { result = 0; goto done; } if ((line = mm_strdup(query_part)) == NULL) { event_warn("%s: strdup", __func__); goto error; } p = argument = line; while (p != NULL && *p != '\0') { char *key, *value, *decoded_value; int err; argument = strsep(&p, "&"); value = argument; key = strsep(&value, "="); if (value == NULL || *key == '\0') { goto error; } if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) { event_warn("%s: mm_malloc", __func__); goto error; } evhttp_decode_uri_internal(value, strlen(value), decoded_value, 1 /*always_decode_plus*/); event_debug(("Query Param: %s -> %s\n", key, decoded_value)); err = evhttp_add_header_internal(headers, key, decoded_value); mm_free(decoded_value); if (err) goto error; } result = 0; goto done; error: evhttp_clear_headers(headers); done: if (line) mm_free(line); if (uri) evhttp_uri_free(uri); return result; } int evhttp_parse_query(const char *uri, struct evkeyvalq *headers) { return evhttp_parse_query_impl(uri, headers, 1); } int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers) { return evhttp_parse_query_impl(uri, headers, 0); } static struct evhttp_cb * evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) { struct evhttp_cb *cb; size_t offset = 0; char *translated; const char *path; /* Test for different URLs */ path = evhttp_uri_get_path(req->uri_elems); offset = strlen(path); if ((translated = mm_malloc(offset + 1)) == NULL) return (NULL); evhttp_decode_uri_internal(path, offset, translated, 0 /* decode_plus */); TAILQ_FOREACH(cb, callbacks, next) { if (!strcmp(cb->what, translated)) { mm_free(translated); return (cb); } } mm_free(translated); return (NULL); } static int prefix_suffix_match(const char *pattern, const char *name, int ignorecase) { char c; while (1) { switch (c = *pattern++) { case '\0': return *name == '\0'; case '*': while (*name != '\0') { if (prefix_suffix_match(pattern, name, ignorecase)) return (1); ++name; } return (0); default: if (c != *name) { if (!ignorecase || EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name)) return (0); } ++name; } } /* NOTREACHED */ } /* Search the vhost hierarchy beginning with http for a server alias matching hostname. If a match is found, and outhttp is non-null, outhttp is set to the matching http object and 1 is returned. */ static int evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp, const char *hostname) { struct evhttp_server_alias *alias; struct evhttp *vhost; TAILQ_FOREACH(alias, &http->aliases, next) { /* XXX Do we need to handle IP addresses? */ if (!evutil_ascii_strcasecmp(alias->alias, hostname)) { if (outhttp) *outhttp = http; return 1; } } /* XXX It might be good to avoid recursion here, but I don't see a way to do that w/o a list. */ TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { if (evhttp_find_alias(vhost, outhttp, hostname)) return 1; } return 0; } /* Attempts to find the best http object to handle a request for a hostname. All aliases for the root http object and vhosts are searched for an exact match. Then, the vhost hierarchy is traversed again for a matching pattern. If an alias or vhost is matched, 1 is returned, and outhttp, if non-null, is set with the best matching http object. If there are no matches, the root http object is stored in outhttp and 0 is returned. */ static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, const char *hostname) { struct evhttp *vhost; struct evhttp *oldhttp; int match_found = 0; if (evhttp_find_alias(http, outhttp, hostname)) return 1; do { oldhttp = http; TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { if (prefix_suffix_match(vhost->vhost_pattern, hostname, 1 /* ignorecase */)) { http = vhost; match_found = 1; break; } } } while (oldhttp != http); if (outhttp) *outhttp = http; return match_found; } static void evhttp_handle_request(struct evhttp_request *req, void *arg) { struct evhttp *http = arg; struct evhttp_cb *cb = NULL; const char *hostname; /* we have a new request on which the user needs to take action */ req->userdone = 0; bufferevent_disable(req->evcon->bufev, EV_READ); if (req->type == 0 || req->uri == NULL) { evhttp_send_error(req, req->response_code, NULL); return; } if ((http->allowed_methods & req->type) == 0) { event_debug(("Rejecting disallowed method %x (allowed: %x)\n", (unsigned)req->type, (unsigned)http->allowed_methods)); evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL); return; } /* handle potential virtual hosts */ hostname = evhttp_request_get_host(req); if (hostname != NULL) { evhttp_find_vhost(http, &http, hostname); } if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { (*cb->cb)(req, cb->cbarg); return; } /* Generic call back */ if (http->gencb) { (*http->gencb)(req, http->gencbarg); return; } else { /* We need to send a 404 here */ #define ERR_FORMAT "" \ "404 Not Found" \ "" \ "

Not Found

" \ "

The requested URL %s was not found on this server.

"\ "\n" char *escaped_html; struct evbuffer *buf; if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) { evhttp_connection_free(req->evcon); return; } if ((buf = evbuffer_new()) == NULL) { mm_free(escaped_html); evhttp_connection_free(req->evcon); return; } evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found"); evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); mm_free(escaped_html); evhttp_send_page_(req, buf); evbuffer_free(buf); #undef ERR_FORMAT } } /* Listener callback when a connection arrives at a server. */ static void accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg) { struct evhttp *http = arg; evhttp_get_request(http, nfd, peer_sa, peer_socklen); } int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) { struct evhttp_bound_socket *bound = evhttp_bind_socket_with_handle(http, address, port); if (bound == NULL) return (-1); return (0); } struct evhttp_bound_socket * evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port) { evutil_socket_t fd; struct evhttp_bound_socket *bound; int serrno; if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) return (NULL); if (listen(fd, 128) == -1) { serrno = EVUTIL_SOCKET_ERROR(); event_sock_warn(fd, "%s: listen", __func__); evutil_closesocket(fd); EVUTIL_SET_SOCKET_ERROR(serrno); return (NULL); } bound = evhttp_accept_socket_with_handle(http, fd); if (bound != NULL) { event_debug(("Bound to port %d - Awaiting connections ... ", port)); return (bound); } return (NULL); } int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd) { struct evhttp_bound_socket *bound = evhttp_accept_socket_with_handle(http, fd); if (bound == NULL) return (-1); return (0); } void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument) { struct evhttp_bound_socket *bound; TAILQ_FOREACH(bound, &http->sockets, next) function(bound, argument); } struct evhttp_bound_socket * evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd) { struct evhttp_bound_socket *bound; struct evconnlistener *listener; const int flags = LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE; listener = evconnlistener_new(http->base, NULL, NULL, flags, 0, /* Backlog is '0' because we already said 'listen' */ fd); if (!listener) return (NULL); bound = evhttp_bind_listener(http, listener); if (!bound) { evconnlistener_free(listener); return (NULL); } return (bound); } struct evhttp_bound_socket * evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener) { struct evhttp_bound_socket *bound; bound = mm_malloc(sizeof(struct evhttp_bound_socket)); if (bound == NULL) return (NULL); bound->listener = listener; TAILQ_INSERT_TAIL(&http->sockets, bound, next); evconnlistener_set_cb(listener, accept_socket_cb, http); return bound; } evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound) { return evconnlistener_get_fd(bound->listener); } struct evconnlistener * evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound) { return bound->listener; } void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound) { TAILQ_REMOVE(&http->sockets, bound, next); evconnlistener_free(bound->listener); mm_free(bound); } static struct evhttp* evhttp_new_object(void) { struct evhttp *http = NULL; if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) { event_warn("%s: calloc", __func__); return (NULL); } evutil_timerclear(&http->timeout); evhttp_set_max_headers_size(http, EV_SIZE_MAX); evhttp_set_max_body_size(http, EV_SIZE_MAX); evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1"); evhttp_set_allowed_methods(http, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_HEAD | EVHTTP_REQ_PUT | EVHTTP_REQ_DELETE); TAILQ_INIT(&http->sockets); TAILQ_INIT(&http->callbacks); TAILQ_INIT(&http->connections); TAILQ_INIT(&http->virtualhosts); TAILQ_INIT(&http->aliases); return (http); } struct evhttp * evhttp_new(struct event_base *base) { struct evhttp *http = NULL; http = evhttp_new_object(); if (http == NULL) return (NULL); http->base = base; return (http); } /* * Start a web server on the specified address and port. */ struct evhttp * evhttp_start(const char *address, ev_uint16_t port) { struct evhttp *http = NULL; http = evhttp_new_object(); if (http == NULL) return (NULL); if (evhttp_bind_socket(http, address, port) == -1) { mm_free(http); return (NULL); } return (http); } void evhttp_free(struct evhttp* http) { struct evhttp_cb *http_cb; struct evhttp_connection *evcon; struct evhttp_bound_socket *bound; struct evhttp* vhost; struct evhttp_server_alias *alias; /* Remove the accepting part */ while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) { TAILQ_REMOVE(&http->sockets, bound, next); evconnlistener_free(bound->listener); mm_free(bound); } while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { /* evhttp_connection_free removes the connection */ evhttp_connection_free(evcon); } while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { TAILQ_REMOVE(&http->callbacks, http_cb, next); mm_free(http_cb->what); mm_free(http_cb); } while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) { TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); evhttp_free(vhost); } if (http->vhost_pattern != NULL) mm_free(http->vhost_pattern); while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) { TAILQ_REMOVE(&http->aliases, alias, next); mm_free(alias->alias); mm_free(alias); } mm_free(http); } int evhttp_add_virtual_host(struct evhttp* http, const char *pattern, struct evhttp* vhost) { /* a vhost can only be a vhost once and should not have bound sockets */ if (vhost->vhost_pattern != NULL || TAILQ_FIRST(&vhost->sockets) != NULL) return (-1); vhost->vhost_pattern = mm_strdup(pattern); if (vhost->vhost_pattern == NULL) return (-1); TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost); return (0); } int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost) { if (vhost->vhost_pattern == NULL) return (-1); TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); mm_free(vhost->vhost_pattern); vhost->vhost_pattern = NULL; return (0); } int evhttp_add_server_alias(struct evhttp *http, const char *alias) { struct evhttp_server_alias *evalias; evalias = mm_calloc(1, sizeof(*evalias)); if (!evalias) return -1; evalias->alias = mm_strdup(alias); if (!evalias->alias) { mm_free(evalias); return -1; } TAILQ_INSERT_TAIL(&http->aliases, evalias, next); return 0; } int evhttp_remove_server_alias(struct evhttp *http, const char *alias) { struct evhttp_server_alias *evalias; TAILQ_FOREACH(evalias, &http->aliases, next) { if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) { TAILQ_REMOVE(&http->aliases, evalias, next); mm_free(evalias->alias); mm_free(evalias); return 0; } } return -1; } void evhttp_set_timeout(struct evhttp* http, int timeout_in_secs) { if (timeout_in_secs == -1) { evhttp_set_timeout_tv(http, NULL); } else { struct timeval tv; tv.tv_sec = timeout_in_secs; tv.tv_usec = 0; evhttp_set_timeout_tv(http, &tv); } } void evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv) { if (tv) { http->timeout = *tv; } else { evutil_timerclear(&http->timeout); } } int evhttp_set_flags(struct evhttp *http, int flags) { int avail_flags = 0; avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE; if (flags & ~avail_flags) return 1; http->flags &= ~avail_flags; http->flags |= flags; return 0; } void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) { if (max_headers_size < 0) http->default_max_headers_size = EV_SIZE_MAX; else http->default_max_headers_size = max_headers_size; } void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) { if (max_body_size < 0) http->default_max_body_size = EV_UINT64_MAX; else http->default_max_body_size = max_body_size; } void evhttp_set_default_content_type(struct evhttp *http, const char *content_type) { http->default_content_type = content_type; } void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods) { http->allowed_methods = methods; } int evhttp_set_cb(struct evhttp *http, const char *uri, void (*cb)(struct evhttp_request *, void *), void *cbarg) { struct evhttp_cb *http_cb; TAILQ_FOREACH(http_cb, &http->callbacks, next) { if (strcmp(http_cb->what, uri) == 0) return (-1); } if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) { event_warn("%s: calloc", __func__); return (-2); } http_cb->what = mm_strdup(uri); if (http_cb->what == NULL) { event_warn("%s: strdup", __func__); mm_free(http_cb); return (-3); } http_cb->cb = cb; http_cb->cbarg = cbarg; TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); return (0); } int evhttp_del_cb(struct evhttp *http, const char *uri) { struct evhttp_cb *http_cb; TAILQ_FOREACH(http_cb, &http->callbacks, next) { if (strcmp(http_cb->what, uri) == 0) break; } if (http_cb == NULL) return (-1); TAILQ_REMOVE(&http->callbacks, http_cb, next); mm_free(http_cb->what); mm_free(http_cb); return (0); } void evhttp_set_gencb(struct evhttp *http, void (*cb)(struct evhttp_request *, void *), void *cbarg) { http->gencb = cb; http->gencbarg = cbarg; } void evhttp_set_bevcb(struct evhttp *http, struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg) { http->bevcb = cb; http->bevcbarg = cbarg; } /* * Request related functions */ struct evhttp_request * evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) { struct evhttp_request *req = NULL; /* Allocate request structure */ if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) { event_warn("%s: calloc", __func__); goto error; } req->headers_size = 0; req->body_size = 0; req->kind = EVHTTP_RESPONSE; req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq)); if (req->input_headers == NULL) { event_warn("%s: calloc", __func__); goto error; } TAILQ_INIT(req->input_headers); req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq)); if (req->output_headers == NULL) { event_warn("%s: calloc", __func__); goto error; } TAILQ_INIT(req->output_headers); if ((req->input_buffer = evbuffer_new()) == NULL) { event_warn("%s: evbuffer_new", __func__); goto error; } if ((req->output_buffer = evbuffer_new()) == NULL) { event_warn("%s: evbuffer_new", __func__); goto error; } req->cb = cb; req->cb_arg = arg; return (req); error: if (req != NULL) evhttp_request_free(req); return (NULL); } void evhttp_request_free(struct evhttp_request *req) { if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) { req->flags |= EVHTTP_REQ_NEEDS_FREE; return; } if (req->remote_host != NULL) mm_free(req->remote_host); if (req->uri != NULL) mm_free(req->uri); if (req->uri_elems != NULL) evhttp_uri_free(req->uri_elems); if (req->response_code_line != NULL) mm_free(req->response_code_line); if (req->host_cache != NULL) mm_free(req->host_cache); evhttp_clear_headers(req->input_headers); mm_free(req->input_headers); evhttp_clear_headers(req->output_headers); mm_free(req->output_headers); if (req->input_buffer != NULL) evbuffer_free(req->input_buffer); if (req->output_buffer != NULL) evbuffer_free(req->output_buffer); mm_free(req); } void evhttp_request_own(struct evhttp_request *req) { req->flags |= EVHTTP_USER_OWNED; } int evhttp_request_is_owned(struct evhttp_request *req) { return (req->flags & EVHTTP_USER_OWNED) != 0; } struct evhttp_connection * evhttp_request_get_connection(struct evhttp_request *req) { return req->evcon; } struct event_base * evhttp_connection_get_base(struct evhttp_connection *conn) { return conn->base; } void evhttp_request_set_chunked_cb(struct evhttp_request *req, void (*cb)(struct evhttp_request *, void *)) { req->chunk_cb = cb; } void evhttp_request_set_header_cb(struct evhttp_request *req, int (*cb)(struct evhttp_request *, void *)) { req->header_cb = cb; } void evhttp_request_set_error_cb(struct evhttp_request *req, void (*cb)(enum evhttp_request_error, void *)) { req->error_cb = cb; } void evhttp_request_set_on_complete_cb(struct evhttp_request *req, void (*cb)(struct evhttp_request *, void *), void *cb_arg) { req->on_complete_cb = cb; req->on_complete_cb_arg = cb_arg; } /* * Allows for inspection of the request URI */ const char * evhttp_request_get_uri(const struct evhttp_request *req) { if (req->uri == NULL) event_debug(("%s: request %p has no uri\n", __func__, req)); return (req->uri); } const struct evhttp_uri * evhttp_request_get_evhttp_uri(const struct evhttp_request *req) { if (req->uri_elems == NULL) event_debug(("%s: request %p has no uri elems\n", __func__, req)); return (req->uri_elems); } const char * evhttp_request_get_host(struct evhttp_request *req) { const char *host = NULL; if (req->host_cache) return req->host_cache; if (req->uri_elems) host = evhttp_uri_get_host(req->uri_elems); if (!host && req->input_headers) { const char *p; size_t len; host = evhttp_find_header(req->input_headers, "Host"); /* The Host: header may include a port. Remove it here to be consistent with uri_elems case above. */ if (host) { p = host + strlen(host) - 1; while (p > host && EVUTIL_ISDIGIT_(*p)) --p; if (p > host && *p == ':') { len = p - host; req->host_cache = mm_malloc(len + 1); if (!req->host_cache) { event_warn("%s: malloc", __func__); return NULL; } memcpy(req->host_cache, host, len); req->host_cache[len] = '\0'; host = req->host_cache; } } } return host; } enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req) { return (req->type); } int evhttp_request_get_response_code(const struct evhttp_request *req) { return req->response_code; } const char * evhttp_request_get_response_code_line(const struct evhttp_request *req) { return req->response_code_line; } /** Returns the input headers */ struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) { return (req->input_headers); } /** Returns the output headers */ struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) { return (req->output_headers); } /** Returns the input buffer */ struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) { return (req->input_buffer); } /** Returns the output buffer */ struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) { return (req->output_buffer); } /* * Takes a file descriptor to read a request from. * The callback is executed once the whole request has been read. */ static struct evhttp_connection* evhttp_get_request_connection( struct evhttp* http, evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) { struct evhttp_connection *evcon; char *hostname = NULL, *portname = NULL; struct bufferevent* bev = NULL; #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN if (sa->sa_family == AF_UNIX) { struct sockaddr_un *sa_un = (struct sockaddr_un *)sa; sa_un->sun_path[0] = '\0'; } #endif name_from_addr(sa, salen, &hostname, &portname); if (hostname == NULL || portname == NULL) { if (hostname) mm_free(hostname); if (portname) mm_free(portname); return (NULL); } event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n", __func__, hostname, portname, EV_SOCK_ARG(fd))); /* we need a connection object to put the http request on */ if (http->bevcb != NULL) { bev = (*http->bevcb)(http->base, http->bevcbarg); } evcon = evhttp_connection_base_bufferevent_new( http->base, NULL, bev, hostname, atoi(portname)); mm_free(hostname); mm_free(portname); if (evcon == NULL) return (NULL); evcon->max_headers_size = http->default_max_headers_size; evcon->max_body_size = http->default_max_body_size; if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE) evcon->flags |= EVHTTP_CON_LINGERING_CLOSE; evcon->flags |= EVHTTP_CON_INCOMING; evcon->state = EVCON_READING_FIRSTLINE; evcon->fd = fd; if (bufferevent_setfd(evcon->bufev, fd)) goto err; if (bufferevent_enable(evcon->bufev, EV_READ)) goto err; if (bufferevent_disable(evcon->bufev, EV_WRITE)) goto err; bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen); return (evcon); err: evhttp_connection_free(evcon); return (NULL); } static int evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) { struct evhttp *http = evcon->http_server; struct evhttp_request *req; if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) return (-1); if ((req->remote_host = mm_strdup(evcon->address)) == NULL) { event_warn("%s: strdup", __func__); evhttp_request_free(req); return (-1); } req->remote_port = evcon->port; req->evcon = evcon; /* the request ends up owning the connection */ req->flags |= EVHTTP_REQ_OWN_CONNECTION; /* We did not present the request to the user user yet, so treat it as * if the user was done with the request. This allows us to free the * request on a persistent connection if the client drops it without * sending a request. */ req->userdone = 1; TAILQ_INSERT_TAIL(&evcon->requests, req, next); req->kind = EVHTTP_REQUEST; evhttp_start_read_(evcon); return (0); } static void evhttp_get_request(struct evhttp *http, evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) { struct evhttp_connection *evcon; evcon = evhttp_get_request_connection(http, fd, sa, salen); if (evcon == NULL) { event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT, __func__, EV_SOCK_ARG(fd)); evutil_closesocket(fd); return; } /* the timeout can be used by the server to close idle connections */ if (evutil_timerisset(&http->timeout)) evhttp_connection_set_timeout_tv(evcon, &http->timeout); /* * if we want to accept more than one request on a connection, * we need to know which http server it belongs to. */ evcon->http_server = http; TAILQ_INSERT_TAIL(&http->connections, evcon, next); if (evhttp_associate_new_request_with_connection(evcon) == -1) evhttp_connection_free(evcon); } /* * Network helper functions that we do not want to export to the rest of * the world. */ static void name_from_addr(struct sockaddr *sa, ev_socklen_t salen, char **phost, char **pport) { char ntop[NI_MAXHOST]; char strport[NI_MAXSERV]; int ni_result; #ifdef EVENT__HAVE_GETNAMEINFO ni_result = getnameinfo(sa, salen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV); if (ni_result != 0) { #ifdef EAI_SYSTEM /* Windows doesn't have an EAI_SYSTEM. */ if (ni_result == EAI_SYSTEM) event_err(1, "getnameinfo failed"); else #endif event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); return; } #else ni_result = fake_getnameinfo(sa, salen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV); if (ni_result != 0) return; #endif *phost = mm_strdup(ntop); *pport = mm_strdup(strport); } /* Create a non-blocking socket and bind it */ static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse) { evutil_socket_t fd; int on = 1, r; int serrno; /* Create listen socket */ fd = evutil_socket_(ai ? ai->ai_family : AF_INET, SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0); if (fd == -1) { event_sock_warn(-1, "socket"); return (-1); } if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0) goto out; if (reuse) { if (evutil_make_listen_socket_reuseable(fd) < 0) goto out; } if (ai != NULL) { r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen); if (r == -1) goto out; } return (fd); out: serrno = EVUTIL_SOCKET_ERROR(); evutil_closesocket(fd); EVUTIL_SET_SOCKET_ERROR(serrno); return (-1); } static struct evutil_addrinfo * make_addrinfo(const char *address, ev_uint16_t port) { struct evutil_addrinfo *ai = NULL; struct evutil_addrinfo hints; char strport[NI_MAXSERV]; int ai_result; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* turn NULL hostname into INADDR_ANY, and skip looking up any address * types we don't have an interface to connect to. */ hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; evutil_snprintf(strport, sizeof(strport), "%d", port); if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai)) != 0) { if (ai_result == EVUTIL_EAI_SYSTEM) event_warn("getaddrinfo"); else event_warnx("getaddrinfo: %s", evutil_gai_strerror(ai_result)); return (NULL); } return (ai); } static evutil_socket_t bind_socket(const char *address, ev_uint16_t port, int reuse) { evutil_socket_t fd; struct evutil_addrinfo *aitop = NULL; /* just create an unbound socket */ if (address == NULL && port == 0) return create_bind_socket_nonblock(NULL, 0); aitop = make_addrinfo(address, port); if (aitop == NULL) return (-1); fd = create_bind_socket_nonblock(aitop, reuse); evutil_freeaddrinfo(aitop); return (fd); } struct evhttp_uri { unsigned flags; char *scheme; /* scheme; e.g http, ftp etc */ char *userinfo; /* userinfo (typically username:pass), or NULL */ char *host; /* hostname, IP address, or NULL */ int port; /* port, or zero */ char *path; /* path, or "". */ char *query; /* query, or NULL */ char *fragment; /* fragment or NULL */ }; struct evhttp_uri * evhttp_uri_new(void) { struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1); if (uri) uri->port = -1; return uri; } void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) { uri->flags = flags; } /* Return true if the string starting at s and ending immediately before eos * is a valid URI scheme according to RFC3986 */ static int scheme_ok(const char *s, const char *eos) { /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ EVUTIL_ASSERT(eos >= s); if (s == eos) return 0; if (!EVUTIL_ISALPHA_(*s)) return 0; while (++s < eos) { if (! EVUTIL_ISALNUM_(*s) && *s != '+' && *s != '-' && *s != '.') return 0; } return 1; } #define SUBDELIMS "!$&'()*+,;=" /* Return true iff [s..eos) is a valid userinfo */ static int userinfo_ok(const char *s, const char *eos) { while (s < eos) { if (CHAR_IS_UNRESERVED(*s) || strchr(SUBDELIMS, *s) || *s == ':') ++s; else if (*s == '%' && s+2 < eos && EVUTIL_ISXDIGIT_(s[1]) && EVUTIL_ISXDIGIT_(s[2])) s += 3; else return 0; } return 1; } static int regname_ok(const char *s, const char *eos) { while (s && s 65535) return -1; ++s; } return portnum; } /* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */ static int bracket_addr_ok(const char *s, const char *eos) { if (s + 3 > eos || *s != '[' || *(eos-1) != ']') return 0; if (s[1] == 'v') { /* IPvFuture, or junk. "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) */ s += 2; /* skip [v */ --eos; if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/ return 0; while (s < eos && *s != '.') { if (EVUTIL_ISXDIGIT_(*s)) ++s; else return 0; } if (*s != '.') return 0; ++s; while (s < eos) { if (CHAR_IS_UNRESERVED(*s) || strchr(SUBDELIMS, *s) || *s == ':') ++s; else return 0; } return 2; } else { /* IPv6, or junk */ char buf[64]; ev_ssize_t n_chars = eos-s-2; struct in6_addr in6; if (n_chars >= 64) /* way too long */ return 0; memcpy(buf, s+1, n_chars); buf[n_chars]='\0'; return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0; } } static int parse_authority(struct evhttp_uri *uri, char *s, char *eos) { char *cp, *port; EVUTIL_ASSERT(eos); if (eos == s) { uri->host = mm_strdup(""); if (uri->host == NULL) { event_warn("%s: strdup", __func__); return -1; } return 0; } /* Optionally, we start with "userinfo@" */ cp = strchr(s, '@'); if (cp && cp < eos) { if (! userinfo_ok(s,cp)) return -1; *cp++ = '\0'; uri->userinfo = mm_strdup(s); if (uri->userinfo == NULL) { event_warn("%s: strdup", __func__); return -1; } } else { cp = s; } /* Optionally, we end with ":port" */ for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port) ; if (port >= cp && *port == ':') { if (port+1 == eos) /* Leave port unspecified; the RFC allows a * nil port */ uri->port = -1; else if ((uri->port = parse_port(port+1, eos))<0) return -1; eos = port; } /* Now, cp..eos holds the "host" port, which can be an IPv4Address, * an IP-Literal, or a reg-name */ EVUTIL_ASSERT(eos >= cp); if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') { /* IPv6address, IP-Literal, or junk. */ if (! bracket_addr_ok(cp, eos)) return -1; } else { /* Make sure the host part is ok. */ if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */ return -1; } uri->host = mm_malloc(eos-cp+1); if (uri->host == NULL) { event_warn("%s: malloc", __func__); return -1; } memcpy(uri->host, cp, eos-cp); uri->host[eos-cp] = '\0'; return 0; } static char * end_of_authority(char *cp) { while (*cp) { if (*cp == '?' || *cp == '#' || *cp == '/') return cp; ++cp; } return cp; } enum uri_part { PART_PATH, PART_QUERY, PART_FRAGMENT }; /* Return the character after the longest prefix of 'cp' that matches... * *pchar / "/" if allow_qchars is false, or * *(pchar / "/" / "?") if allow_qchars is true. */ static char * end_of_path(char *cp, enum uri_part part, unsigned flags) { if (flags & EVHTTP_URI_NONCONFORMANT) { /* If NONCONFORMANT: * Path is everything up to a # or ? or nul. * Query is everything up a # or nul * Fragment is everything up to a nul. */ switch (part) { case PART_PATH: while (*cp && *cp != '#' && *cp != '?') ++cp; break; case PART_QUERY: while (*cp && *cp != '#') ++cp; break; case PART_FRAGMENT: cp += strlen(cp); break; }; return cp; } while (*cp) { if (CHAR_IS_UNRESERVED(*cp) || strchr(SUBDELIMS, *cp) || *cp == ':' || *cp == '@' || *cp == '/') ++cp; else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) && EVUTIL_ISXDIGIT_(cp[2])) cp += 3; else if (*cp == '?' && part != PART_PATH) ++cp; else return cp; } return cp; } static int path_matches_noscheme(const char *cp) { while (*cp) { if (*cp == ':') return 0; else if (*cp == '/') return 1; ++cp; } return 1; } struct evhttp_uri * evhttp_uri_parse(const char *source_uri) { return evhttp_uri_parse_with_flags(source_uri, 0); } struct evhttp_uri * evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) { char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; char *path = NULL, *fragment = NULL; int got_authority = 0; struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); if (uri == NULL) { event_warn("%s: calloc", __func__); goto err; } uri->port = -1; uri->flags = flags; readbuf = mm_strdup(source_uri); if (readbuf == NULL) { event_warn("%s: strdup", __func__); goto err; } readp = readbuf; token = NULL; /* We try to follow RFC3986 here as much as we can, and match the productions URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] relative-ref = relative-part [ "?" query ] [ "#" fragment ] */ /* 1. scheme: */ token = strchr(readp, ':'); if (token && scheme_ok(readp,token)) { *token = '\0'; uri->scheme = mm_strdup(readp); if (uri->scheme == NULL) { event_warn("%s: strdup", __func__); goto err; } readp = token+1; /* eat : */ } /* 2. Optionally, "//" then an 'authority' part. */ if (readp[0]=='/' && readp[1] == '/') { char *authority; readp += 2; authority = readp; path = end_of_authority(readp); if (parse_authority(uri, authority, path) < 0) goto err; readp = path; got_authority = 1; } /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty */ path = readp; readp = end_of_path(path, PART_PATH, flags); /* Query */ if (*readp == '?') { *readp = '\0'; ++readp; query = readp; readp = end_of_path(readp, PART_QUERY, flags); } /* fragment */ if (*readp == '#') { *readp = '\0'; ++readp; fragment = readp; readp = end_of_path(readp, PART_FRAGMENT, flags); } if (*readp != '\0') { goto err; } /* These next two cases may be unreachable; I'm leaving them * in to be defensive. */ /* If you didn't get an authority, the path can't begin with "//" */ if (!got_authority && path[0]=='/' && path[1]=='/') goto err; /* If you did get an authority, the path must begin with "/" or be * empty. */ if (got_authority && path[0] != '/' && path[0] != '\0') goto err; /* (End of maybe-unreachable cases) */ /* If there was no scheme, the first part of the path (if any) must * have no colon in it. */ if (! uri->scheme && !path_matches_noscheme(path)) goto err; EVUTIL_ASSERT(path); uri->path = mm_strdup(path); if (uri->path == NULL) { event_warn("%s: strdup", __func__); goto err; } if (query) { uri->query = mm_strdup(query); if (uri->query == NULL) { event_warn("%s: strdup", __func__); goto err; } } if (fragment) { uri->fragment = mm_strdup(fragment); if (uri->fragment == NULL) { event_warn("%s: strdup", __func__); goto err; } } mm_free(readbuf); return uri; err: if (uri) evhttp_uri_free(uri); if (readbuf) mm_free(readbuf); return NULL; } static struct evhttp_uri * evhttp_uri_parse_authority(char *source_uri) { struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); char *end; if (uri == NULL) { event_warn("%s: calloc", __func__); goto err; } uri->port = -1; uri->flags = 0; end = end_of_authority(source_uri); if (parse_authority(uri, source_uri, end) < 0) goto err; uri->path = mm_strdup(""); if (uri->path == NULL) { event_warn("%s: strdup", __func__); goto err; } return uri; err: if (uri) evhttp_uri_free(uri); return NULL; } void evhttp_uri_free(struct evhttp_uri *uri) { #define URI_FREE_STR_(f) \ if (uri->f) { \ mm_free(uri->f); \ } URI_FREE_STR_(scheme); URI_FREE_STR_(userinfo); URI_FREE_STR_(host); URI_FREE_STR_(path); URI_FREE_STR_(query); URI_FREE_STR_(fragment); mm_free(uri); #undef URI_FREE_STR_ } char * evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit) { struct evbuffer *tmp = 0; size_t joined_size = 0; char *output = NULL; #define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f)) if (!uri || !buf || !limit) return NULL; tmp = evbuffer_new(); if (!tmp) return NULL; if (uri->scheme) { URI_ADD_(scheme); evbuffer_add(tmp, ":", 1); } if (uri->host) { evbuffer_add(tmp, "//", 2); if (uri->userinfo) evbuffer_add_printf(tmp,"%s@", uri->userinfo); URI_ADD_(host); if (uri->port >= 0) evbuffer_add_printf(tmp,":%d", uri->port); if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0') goto err; } if (uri->path) URI_ADD_(path); if (uri->query) { evbuffer_add(tmp, "?", 1); URI_ADD_(query); } if (uri->fragment) { evbuffer_add(tmp, "#", 1); URI_ADD_(fragment); } evbuffer_add(tmp, "\0", 1); /* NUL */ joined_size = evbuffer_get_length(tmp); if (joined_size > limit) { /* It doesn't fit. */ evbuffer_free(tmp); return NULL; } evbuffer_remove(tmp, buf, joined_size); output = buf; err: evbuffer_free(tmp); return output; #undef URI_ADD_ } const char * evhttp_uri_get_scheme(const struct evhttp_uri *uri) { return uri->scheme; } const char * evhttp_uri_get_userinfo(const struct evhttp_uri *uri) { return uri->userinfo; } const char * evhttp_uri_get_host(const struct evhttp_uri *uri) { return uri->host; } int evhttp_uri_get_port(const struct evhttp_uri *uri) { return uri->port; } const char * evhttp_uri_get_path(const struct evhttp_uri *uri) { return uri->path; } const char * evhttp_uri_get_query(const struct evhttp_uri *uri) { return uri->query; } const char * evhttp_uri_get_fragment(const struct evhttp_uri *uri) { return uri->fragment; } #define URI_SET_STR_(f) do { \ if (uri->f) \ mm_free(uri->f); \ if (f) { \ if ((uri->f = mm_strdup(f)) == NULL) { \ event_warn("%s: strdup()", __func__); \ return -1; \ } \ } else { \ uri->f = NULL; \ } \ } while(0) int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme) { if (scheme && !scheme_ok(scheme, scheme+strlen(scheme))) return -1; URI_SET_STR_(scheme); return 0; } int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo) { if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo))) return -1; URI_SET_STR_(userinfo); return 0; } int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host) { if (host) { if (host[0] == '[') { if (! bracket_addr_ok(host, host+strlen(host))) return -1; } else { if (! regname_ok(host, host+strlen(host))) return -1; } } URI_SET_STR_(host); return 0; } int evhttp_uri_set_port(struct evhttp_uri *uri, int port) { if (port < -1) return -1; uri->port = port; return 0; } #define end_of_cpath(cp,p,f) \ ((const char*)(end_of_path(((char*)(cp)), (p), (f)))) int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) { if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) return -1; URI_SET_STR_(path); return 0; } int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) { if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) return -1; URI_SET_STR_(query); return 0; } int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) { if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) return -1; URI_SET_STR_(fragment); return 0; } lldpd-1.0.13/libevent/defer-internal.h0000644000076400001440000000541514111362570020256 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DEFER_INTERNAL_H_INCLUDED_ #define DEFER_INTERNAL_H_INCLUDED_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.h" #include "evconfig-private.h" #include struct event_callback; typedef void (*deferred_cb_fn)(struct event_callback *, void *); /** Initialize an empty, non-pending event_callback. @param deferred The struct event_callback structure to initialize. @param priority The priority that the callback should run at. @param cb The function to run when the struct event_callback executes. @param arg The function's second argument. */ EVENT2_EXPORT_SYMBOL void event_deferred_cb_init_(struct event_callback *, ev_uint8_t, deferred_cb_fn, void *); /** Change the priority of a non-pending event_callback. */ void event_deferred_cb_set_priority_(struct event_callback *, ev_uint8_t); /** Cancel a struct event_callback if it is currently scheduled in an event_base. */ EVENT2_EXPORT_SYMBOL void event_deferred_cb_cancel_(struct event_base *, struct event_callback *); /** Activate a struct event_callback if it is not currently scheduled in an event_base. Return true if it was not previously scheduled. */ EVENT2_EXPORT_SYMBOL int event_deferred_cb_schedule_(struct event_base *, struct event_callback *); #ifdef __cplusplus } #endif #endif /* EVENT_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/config.h.in0000644000076400001440000004147614143730641017243 0ustar00bernatusers00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if libevent should build without support for a debug mode */ #undef DISABLE_DEBUG_MODE /* Define if libevent should not allow replacing the mm functions */ #undef DISABLE_MM_REPLACEMENT /* Define if libevent should not be compiled with thread support */ #undef DISABLE_THREAD_SUPPORT /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 /* Define to 1 if you have the header file. */ #undef HAVE_AFUNIX_H /* Define to 1 if you have the `arc4random' function. */ #undef HAVE_ARC4RANDOM /* Define to 1 if you have the `arc4random_addrandom' function. */ #undef HAVE_ARC4RANDOM_ADDRANDOM /* Define to 1 if you have the `arc4random_buf' function. */ #undef HAVE_ARC4RANDOM_BUF /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if you have the declaration of `CTL_KERN', and to 0 if you don't. */ #undef HAVE_DECL_CTL_KERN /* Define to 1 if you have the declaration of `KERN_ARND', and to 0 if you don't. */ #undef HAVE_DECL_KERN_ARND /* Define if /dev/poll is available */ #undef HAVE_DEVPOLL /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define if your system supports the epoll system calls */ #undef HAVE_EPOLL /* Define to 1 if you have the `epoll_create1' function. */ #undef HAVE_EPOLL_CREATE1 /* Define to 1 if you have the `epoll_ctl' function. */ #undef HAVE_EPOLL_CTL /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the `eventfd' function. */ #undef HAVE_EVENTFD /* Define if your system supports event ports */ #undef HAVE_EVENT_PORTS /* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if the system has the type `fd_mask'. */ #undef HAVE_FD_MASK /* Do we have getaddrinfo()? */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getegid' function. */ #undef HAVE_GETEGID /* Define to 1 if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define this if you have any gethostbyname_r() */ #undef HAVE_GETHOSTBYNAME_R /* Define this if gethostbyname_r takes 3 arguments */ #undef HAVE_GETHOSTBYNAME_R_3_ARG /* Define this if gethostbyname_r takes 5 arguments */ #undef HAVE_GETHOSTBYNAME_R_5_ARG /* Define this if gethostbyname_r takes 6 arguments */ #undef HAVE_GETHOSTBYNAME_R_6_ARG /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the `getnameinfo' function. */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the `getprotobynumber' function. */ #undef HAVE_GETPROTOBYNUMBER /* Define to 1 if you have the `getrandom' function. */ #undef HAVE_GETRANDOM /* Define to 1 if you have the `getservbyname' function. */ #undef HAVE_GETSERVBYNAME /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `issetugid' function. */ #undef HAVE_ISSETUGID /* Define to 1 if you have the `kqueue' function. */ #undef HAVE_KQUEUE /* Define to 1 if you have the `ws2_32' library (-lws2_32). */ #undef HAVE_LIBWS2_32 /* Define if the system has zlib */ #undef HAVE_LIBZ /* Define to 1 if you have the `mach_absolute_time' function. */ #undef HAVE_MACH_ABSOLUTE_TIME /* Define to 1 if you have the header file. */ #undef HAVE_MACH_MACH_H /* Define to 1 if you have the header file. */ #undef HAVE_MACH_MACH_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* Define to 1 if you have the `nanosleep' function. */ #undef HAVE_NANOSLEEP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN6_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define if the system has openssl */ #undef HAVE_OPENSSL /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the `pipe' function. */ #undef HAVE_PIPE /* Define to 1 if you have the `pipe2' function. */ #undef HAVE_PIPE2 /* Define to 1 if you have the `poll' function. */ #undef HAVE_POLL /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define to 1 if you have the `port_create' function. */ #undef HAVE_PORT_CREATE /* Define to 1 if you have the header file. */ #undef HAVE_PORT_H /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD /* Define if we have pthreads on this system */ #undef HAVE_PTHREADS /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define to 1 if the system has the type `sa_family_t'. */ #undef HAVE_SA_FAMILY_T /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `sendfile' function. */ #undef HAVE_SENDFILE /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define if F_SETFD is defined in */ #undef HAVE_SETFD /* Define to 1 if you have the `setrlimit' function. */ #undef HAVE_SETRLIMIT /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the `signal' function. */ #undef HAVE_SIGNAL /* Define to 1 if you have the `splice' function. */ #undef HAVE_SPLICE /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* Define to 1 if you have the `strtoll' function. */ #undef HAVE_STRTOLL /* Define to 1 if the system has the type `struct addrinfo'. */ #undef HAVE_STRUCT_ADDRINFO /* Define to 1 if the system has the type `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR /* Define to 1 if `s6_addr16' is a member of `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 /* Define to 1 if `s6_addr32' is a member of `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 /* Define to 1 if the system has the type `struct linger'. */ #undef HAVE_STRUCT_LINGER /* Define to 1 if the system has the type `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6 /* Define to 1 if `sin6_len' is a member of `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE /* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY /* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY /* Define to 1 if the system has the type `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN /* Define to 1 if you have the `sysctl' function. */ #undef HAVE_SYSCTL /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DEVPOLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EPOLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EVENTFD_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EVENT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_QUEUE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RANDOM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SENDFILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIMERFD_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define if TAILQ_FOREACH is defined in */ #undef HAVE_TAILQFOREACH /* Define if timeradd is defined in */ #undef HAVE_TIMERADD /* Define if timerclear is defined in */ #undef HAVE_TIMERCLEAR /* Define if timercmp is defined in */ #undef HAVE_TIMERCMP /* Define to 1 if you have the `timerfd_create' function. */ #undef HAVE_TIMERFD_CREATE /* Define if timerisset is defined in */ #undef HAVE_TIMERISSET /* Define to 1 if the system has the type `uint16_t'. */ #undef HAVE_UINT16_T /* Define to 1 if the system has the type `uint32_t'. */ #undef HAVE_UINT32_T /* Define to 1 if the system has the type `uint64_t'. */ #undef HAVE_UINT64_T /* Define to 1 if the system has the type `uint8_t'. */ #undef HAVE_UINT8_T /* Define to 1 if the system has the type `uintptr_t'. */ #undef HAVE_UINTPTR_T /* Define to 1 if you have the `umask' function. */ #undef HAVE_UMASK /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define if kqueue works correctly with pipes */ #undef HAVE_WORKING_KQUEUE /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H /* Define to 1 if you have the `_gmtime64' function. */ #undef HAVE__GMTIME64 /* Define to 1 if you have the `_gmtime64_s' function. */ #undef HAVE__GMTIME64_S /* Define to 1 if compiler have __FUNCTION__ */ #undef HAVE___FUNCTION__ /* Define to 1 if compiler have __func__ */ #undef HAVE___func__ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Numeric representation of the version */ #undef NUMERIC_VERSION /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The size of `off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T /* The size of `pthread_t', as computed by sizeof. */ #undef SIZEOF_PTHREAD_T /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . This macro is obsolete. */ #undef TIME_WITH_SYS_TIME /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to unsigned int if you dont have it */ #undef socklen_t /* Define to `int' if does not define. */ #undef ssize_t lldpd-1.0.13/libevent/bufferevent_sock.c0000644000076400001440000004355514111362570020713 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * Copyright (c) 2002-2006 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #ifdef EVENT__HAVE_STDARG_H #include #endif #ifdef EVENT__HAVE_UNISTD_H #include #endif #ifdef _WIN32 #include #include #endif #ifdef EVENT__HAVE_SYS_SOCKET_H #include #endif #ifdef EVENT__HAVE_NETINET_IN_H #include #endif #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #include "event2/util.h" #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/bufferevent_struct.h" #include "event2/bufferevent_compat.h" #include "event2/event.h" #include "log-internal.h" #include "mm-internal.h" #include "bufferevent-internal.h" #include "util-internal.h" #ifdef _WIN32 #include "iocp-internal.h" #endif /* prototypes */ static int be_socket_enable(struct bufferevent *, short); static int be_socket_disable(struct bufferevent *, short); static void be_socket_destruct(struct bufferevent *); static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode); static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); static void be_socket_setfd(struct bufferevent *, evutil_socket_t); const struct bufferevent_ops bufferevent_ops_socket = { "socket", evutil_offsetof(struct bufferevent_private, bev), be_socket_enable, be_socket_disable, NULL, /* unlink */ be_socket_destruct, bufferevent_generic_adj_existing_timeouts_, be_socket_flush, be_socket_ctrl, }; const struct sockaddr* bufferevent_socket_get_conn_address_(struct bufferevent *bev) { struct bufferevent_private *bev_p = BEV_UPCAST(bev); return (struct sockaddr *)&bev_p->conn_address; } void bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev, evutil_socket_t fd) { struct bufferevent_private *bev_p = BEV_UPCAST(bev); socklen_t len = sizeof(bev_p->conn_address); struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address; if (addr->sa_family != AF_UNSPEC) getpeername(fd, addr, &len); } void bufferevent_socket_set_conn_address_(struct bufferevent *bev, struct sockaddr *addr, size_t addrlen) { struct bufferevent_private *bev_p = BEV_UPCAST(bev); EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address)); memcpy(&bev_p->conn_address, addr, addrlen); } static void bufferevent_socket_outbuf_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); if (cbinfo->n_added && (bufev->enabled & EV_WRITE) && !event_pending(&bufev->ev_write, EV_WRITE, NULL) && !bufev_p->write_suspended) { /* Somebody added data to the buffer, and we would like to * write, and we were not writing. So, start writing. */ if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) { /* Should we log this? */ } } } static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; bufferevent_incref_and_lock_(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_READ, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* we somehow lowered the watermark, stop reading */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } readmax = bufferevent_get_read_max_(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; if (EVUTIL_ERR_CONNECT_REFUSED(err)) { bufev_p->connection_refused = 1; goto done; } /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; bufferevent_decrement_read_buckets_(bufev_p, res); /* Invoke the user callback - must always be called last */ bufferevent_trigger_nolock_(bufev, EV_READ, 0); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); bufferevent_run_eventcb_(bufev, what, 0); done: bufferevent_decref_and_unlock_(bufev); } static void bufferevent_writecb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); int res = 0; short what = BEV_EVENT_WRITING; int connected = 0; ev_ssize_t atmost = -1; bufferevent_incref_and_lock_(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } if (bufev_p->connecting) { int c = evutil_socket_finished_connecting_(fd); /* we need to fake the error if the connection was refused * immediately - usually connection to localhost on BSD */ if (bufev_p->connection_refused) { bufev_p->connection_refused = 0; c = -1; } if (c == 0) goto done; bufev_p->connecting = 0; if (c < 0) { event_del(&bufev->ev_write); event_del(&bufev->ev_read); bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0); goto done; } else { connected = 1; bufferevent_socket_set_conn_address_fd_(bufev, fd); #ifdef _WIN32 if (BEV_IS_ASYNC(bufev)) { event_del(&bufev->ev_write); bufferevent_async_set_connected_(bufev); bufferevent_run_eventcb_(bufev, BEV_EVENT_CONNECTED, 0); goto done; } #endif bufferevent_run_eventcb_(bufev, BEV_EVENT_CONNECTED, 0); if (!(bufev->enabled & EV_WRITE) || bufev_p->write_suspended) { event_del(&bufev->ev_write); goto done; } } } atmost = bufferevent_get_write_max_(bufev_p); if (bufev_p->write_suspended) goto done; if (evbuffer_get_length(bufev->output)) { evbuffer_unfreeze(bufev->output, 1); res = evbuffer_write_atmost(bufev->output, fd, atmost); evbuffer_freeze(bufev->output, 1); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case XXXX Actually, a 0 on write doesn't indicate an EOF. An ECONNRESET might be more typical. */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; bufferevent_decrement_write_buckets_(bufev_p, res); } if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } /* * Invoke the user callback if our buffer is drained or below the * low watermark. */ if (res || !connected) { bufferevent_trigger_nolock_(bufev, EV_WRITE, 0); } goto done; reschedule: if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } goto done; error: bufferevent_disable(bufev, EV_WRITE); bufferevent_run_eventcb_(bufev, what, 0); done: bufferevent_decref_and_unlock_(bufev); } struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef _WIN32 if (base && event_base_get_iocp_(base)) return bufferevent_async_new_(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); evbuffer_freeze(bufev->input, 0); evbuffer_freeze(bufev->output, 1); return bufev; } int bufferevent_socket_connect(struct bufferevent *bev, const struct sockaddr *sa, int socklen) { struct bufferevent_private *bufev_p = BEV_UPCAST(bev); evutil_socket_t fd; int r = 0; int result=-1; int ownfd = 0; bufferevent_incref_and_lock_(bev); fd = bufferevent_getfd(bev); if (fd < 0) { if (!sa) goto done; fd = evutil_socket_(sa->sa_family, SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0); if (fd < 0) goto freesock; ownfd = 1; } if (sa) { #ifdef _WIN32 if (bufferevent_async_can_connect_(bev)) { bufferevent_setfd(bev, fd); r = bufferevent_async_connect_(bev, fd, sa, socklen); if (r < 0) goto freesock; bufev_p->connecting = 1; result = 0; goto done; } else #endif r = evutil_socket_connect_(&fd, sa, socklen); if (r < 0) goto freesock; } #ifdef _WIN32 /* ConnectEx() isn't always around, even when IOCP is enabled. * Here, we borrow the socket object's write handler to fall back * on a non-blocking connect() when ConnectEx() is unavailable. */ if (BEV_IS_ASYNC(bev)) { event_assign(&bev->ev_write, bev->ev_base, fd, EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev); } #endif bufferevent_setfd(bev, fd); if (r == 0) { if (! be_socket_enable(bev, EV_WRITE)) { bufev_p->connecting = 1; result = 0; goto done; } } else if (r == 1) { /* The connect succeeded already. How very BSD of it. */ result = 0; bufev_p->connecting = 1; bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS); } else { /* The connect failed already. How very BSD of it. */ result = 0; bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS); bufferevent_disable(bev, EV_WRITE|EV_READ); } goto done; freesock: if (ownfd) evutil_closesocket(fd); done: bufferevent_decref_and_unlock_(bev); return result; } static void bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, void *arg) { struct bufferevent *bev = arg; struct bufferevent_private *bev_p = BEV_UPCAST(bev); int r; BEV_LOCK(bev); bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP); bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP); bev_p->dns_request = NULL; if (result == EVUTIL_EAI_CANCEL) { bev_p->dns_error = result; bufferevent_decref_and_unlock_(bev); return; } if (result != 0) { bev_p->dns_error = result; bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); bufferevent_decref_and_unlock_(bev); if (ai) evutil_freeaddrinfo(ai); return; } /* XXX use the other addrinfos? */ bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen); r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); if (r < 0) bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); bufferevent_decref_and_unlock_(bev); evutil_freeaddrinfo(ai); } int bufferevent_socket_connect_hostname(struct bufferevent *bev, struct evdns_base *evdns_base, int family, const char *hostname, int port) { char portbuf[10]; struct evutil_addrinfo hint; struct bufferevent_private *bev_p = BEV_UPCAST(bev); if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) return -1; if (port < 1 || port > 65535) return -1; memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_protocol = IPPROTO_TCP; hint.ai_socktype = SOCK_STREAM; evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); BEV_LOCK(bev); bev_p->dns_error = 0; bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP); bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP); bufferevent_incref_(bev); bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev); BEV_UNLOCK(bev); return 0; } int bufferevent_socket_get_dns_error(struct bufferevent *bev) { int rv; struct bufferevent_private *bev_p = BEV_UPCAST(bev); BEV_LOCK(bev); rv = bev_p->dns_error; BEV_UNLOCK(bev); return rv; } /* * Create a new buffered event object. * * The read callback is invoked whenever we read new data. * The write callback is invoked whenever the output buffer is drained. * The error callback is invoked on a write/read error or on EOF. * * Both read and write callbacks maybe NULL. The error callback is not * allowed to be NULL and have to be provided always. */ struct bufferevent * bufferevent_new(evutil_socket_t fd, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg) { struct bufferevent *bufev; if (!(bufev = bufferevent_socket_new(NULL, fd, 0))) return NULL; bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg); return bufev; } static int be_socket_enable(struct bufferevent *bufev, short event) { if (event & EV_READ && bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1) return -1; if (event & EV_WRITE && bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) return -1; return 0; } static int be_socket_disable(struct bufferevent *bufev, short event) { struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); if (event & EV_READ) { if (event_del(&bufev->ev_read) == -1) return -1; } /* Don't actually disable the write if we are trying to connect. */ if ((event & EV_WRITE) && ! bufev_p->connecting) { if (event_del(&bufev->ev_write) == -1) return -1; } return 0; } static void be_socket_destruct(struct bufferevent *bufev) { struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); evutil_socket_t fd; EVUTIL_ASSERT(BEV_IS_SOCKET(bufev)); fd = event_get_fd(&bufev->ev_read); if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0) EVUTIL_CLOSESOCKET(fd); evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); } static int be_socket_flush(struct bufferevent *bev, short iotype, enum bufferevent_flush_mode mode) { return 0; } static void be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd) { struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); BEV_LOCK(bufev); EVUTIL_ASSERT(BEV_IS_SOCKET(bufev)); event_del(&bufev->ev_read); event_del(&bufev->ev_write); evbuffer_unfreeze(bufev->input, 0); evbuffer_unfreeze(bufev->output, 1); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); if (fd >= 0) bufferevent_enable(bufev, bufev->enabled); evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); BEV_UNLOCK(bufev); } /* XXXX Should non-socket bufferevents support this? */ int bufferevent_priority_set(struct bufferevent *bufev, int priority) { int r = -1; struct bufferevent_private *bufev_p = BEV_UPCAST(bufev); BEV_LOCK(bufev); if (BEV_IS_ASYNC(bufev) || BEV_IS_FILTER(bufev) || BEV_IS_PAIR(bufev)) goto done; if (event_priority_set(&bufev->ev_read, priority) == -1) goto done; if (event_priority_set(&bufev->ev_write, priority) == -1) goto done; event_deferred_cb_set_priority_(&bufev_p->deferred, priority); r = 0; done: BEV_UNLOCK(bufev); return r; } /* XXXX Should non-socket bufferevents support this? */ int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev) { int res = -1; BEV_LOCK(bufev); if (!BEV_IS_SOCKET(bufev)) goto done; bufev->ev_base = base; res = event_base_set(base, &bufev->ev_read); if (res == -1) goto done; res = event_base_set(base, &bufev->ev_write); done: BEV_UNLOCK(bufev); return res; } static int be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data) { switch (op) { case BEV_CTRL_SET_FD: be_socket_setfd(bev, data->fd); return 0; case BEV_CTRL_GET_FD: data->fd = event_get_fd(&bev->ev_read); return 0; case BEV_CTRL_GET_UNDERLYING: case BEV_CTRL_CANCEL_ALL: default: return -1; } } lldpd-1.0.13/libevent/evsignal-internal.h0000644000076400001440000000510614111362570020776 0ustar00bernatusers00000000000000/* * Copyright 2000-2007 Niels Provos * Copyright 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EVSIGNAL_INTERNAL_H_INCLUDED_ #define EVSIGNAL_INTERNAL_H_INCLUDED_ #ifndef evutil_socket_t #include "event2/util.h" #endif #include typedef void (*ev_sighandler_t)(int); /* Data structure for the default signal-handling implementation in signal.c */ struct evsig_info { /* Event watching ev_signal_pair[1] */ struct event ev_signal; /* Socketpair used to send notifications from the signal handler */ evutil_socket_t ev_signal_pair[2]; /* True iff we've added the ev_signal event yet. */ int ev_signal_added; /* Count of the number of signals we're currently watching. */ int ev_n_signals_added; /* Array of previous signal handler objects before Libevent started * messing with them. Used to restore old signal handlers. */ #ifdef EVENT__HAVE_SIGACTION struct sigaction **sh_old; #else ev_sighandler_t **sh_old; #endif /* Size of sh_old. */ int sh_old_max; }; int evsig_init_(struct event_base *); void evsig_dealloc_(struct event_base *); void evsig_set_base_(struct event_base *base); void evsig_free_globals_(void); #endif /* EVSIGNAL_INTERNAL_H_INCLUDED_ */ lldpd-1.0.13/libevent/sample/0000755000076400001440000000000014143730656016473 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/sample/event-read-fifo.c0000644000076400001440000000653514111362571021613 0ustar00bernatusers00000000000000/* * This sample code shows how to use Libevent to read from a named pipe. * XXX This code could make better use of the Libevent interfaces. * * XXX This does not work on Windows; ignore everything inside the _WIN32 block. * * On UNIX, compile with: * cc -I/usr/local/include -o event-read-fifo event-read-fifo.c \ * -L/usr/local/lib -levent */ #include #include #include #ifndef _WIN32 #include #include #include #include #else #include #include #endif #include #include #include #include #include #include static void fifo_read(evutil_socket_t fd, short event, void *arg) { char buf[255]; int len; struct event *ev = arg; #ifdef _WIN32 DWORD dwBytesRead; #endif fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n", (int)fd, event, arg); #ifdef _WIN32 len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL); /* Check for end of file. */ if (len && dwBytesRead == 0) { fprintf(stderr, "End Of File"); event_del(ev); return; } buf[dwBytesRead] = '\0'; #else len = read(fd, buf, sizeof(buf) - 1); if (len <= 0) { if (len == -1) perror("read"); else if (len == 0) fprintf(stderr, "Connection closed\n"); event_del(ev); event_base_loopbreak(event_get_base(ev)); return; } buf[len] = '\0'; #endif fprintf(stdout, "Read: %s\n", buf); } /* On Unix, cleanup event.fifo if SIGINT is received. */ #ifndef _WIN32 static void signal_cb(evutil_socket_t fd, short event, void *arg) { struct event_base *base = arg; event_base_loopbreak(base); } #endif int main(int argc, char **argv) { struct event *evfifo; struct event_base* base; #ifdef _WIN32 HANDLE socket; /* Open a file. */ socket = CreateFileA("test.txt", /* open File */ GENERIC_READ, /* open for reading */ 0, /* do not share */ NULL, /* no security */ OPEN_EXISTING, /* existing file only */ FILE_ATTRIBUTE_NORMAL, /* normal file */ NULL); /* no attr. template */ if (socket == INVALID_HANDLE_VALUE) return 1; #else struct event *signal_int; struct stat st; const char *fifo = "event.fifo"; int socket; if (lstat(fifo, &st) == 0) { if ((st.st_mode & S_IFMT) == S_IFREG) { errno = EEXIST; perror("lstat"); exit(1); } } unlink(fifo); if (mkfifo(fifo, 0600) == -1) { perror("mkfifo"); exit(1); } socket = open(fifo, O_RDONLY | O_NONBLOCK, 0); if (socket == -1) { perror("open"); exit(1); } fprintf(stderr, "Write data to %s\n", fifo); #endif /* Initialize the event library */ base = event_base_new(); /* Initialize one event */ #ifdef _WIN32 evfifo = event_new(base, (evutil_socket_t)socket, EV_READ|EV_PERSIST, fifo_read, event_self_cbarg()); #else /* catch SIGINT so that event.fifo can be cleaned up */ signal_int = evsignal_new(base, SIGINT, signal_cb, base); event_add(signal_int, NULL); evfifo = event_new(base, socket, EV_READ|EV_PERSIST, fifo_read, event_self_cbarg()); #endif /* Add it to the active events, without a timeout */ event_add(evfifo, NULL); event_base_dispatch(base); event_base_free(base); #ifdef _WIN32 CloseHandle(socket); #else close(socket); unlink(fifo); #endif libevent_global_shutdown(); return (0); } lldpd-1.0.13/libevent/sample/le-proxy.c0000644000076400001440000001655614111362571020423 0ustar00bernatusers00000000000000/* This example code shows how to write an (optionally encrypting) SSL proxy with Libevent's bufferevent layer. XXX It's a little ugly and should probably be cleaned up. */ // Get rid of OSX 10.7 and greater deprecation warnings. #if defined(__APPLE__) && defined(__clang__) #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif #include #include #include #include #include #ifdef _WIN32 #include #include #else #include #include #endif #include #include #include #include #include #include "util-internal.h" #include #include #include #include "openssl-compat.h" static struct event_base *base; static struct sockaddr_storage listen_on_addr; static struct sockaddr_storage connect_to_addr; static int connect_to_addrlen; static int use_wrapper = 1; static SSL_CTX *ssl_ctx = NULL; #define MAX_OUTPUT (512*1024) static void drained_writecb(struct bufferevent *bev, void *ctx); static void eventcb(struct bufferevent *bev, short what, void *ctx); static void readcb(struct bufferevent *bev, void *ctx) { struct bufferevent *partner = ctx; struct evbuffer *src, *dst; size_t len; src = bufferevent_get_input(bev); len = evbuffer_get_length(src); if (!partner) { evbuffer_drain(src, len); return; } dst = bufferevent_get_output(partner); evbuffer_add_buffer(dst, src); if (evbuffer_get_length(dst) >= MAX_OUTPUT) { /* We're giving the other side data faster than it can * pass it on. Stop reading here until we have drained the * other side to MAX_OUTPUT/2 bytes. */ bufferevent_setcb(partner, readcb, drained_writecb, eventcb, bev); bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2, MAX_OUTPUT); bufferevent_disable(bev, EV_READ); } } static void drained_writecb(struct bufferevent *bev, void *ctx) { struct bufferevent *partner = ctx; /* We were choking the other side until we drained our outbuf a bit. * Now it seems drained. */ bufferevent_setcb(bev, readcb, NULL, eventcb, partner); bufferevent_setwatermark(bev, EV_WRITE, 0, 0); if (partner) bufferevent_enable(partner, EV_READ); } static void close_on_finished_writecb(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_output(bev); if (evbuffer_get_length(b) == 0) { bufferevent_free(bev); } } static void eventcb(struct bufferevent *bev, short what, void *ctx) { struct bufferevent *partner = ctx; if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { if (what & BEV_EVENT_ERROR) { unsigned long err; while ((err = (bufferevent_get_openssl_error(bev)))) { const char *msg = (const char*) ERR_reason_error_string(err); const char *lib = (const char*) ERR_lib_error_string(err); const char *func = (const char*) ERR_func_error_string(err); fprintf(stderr, "%s in %s %s\n", msg, lib, func); } if (errno) perror("connection error"); } if (partner) { /* Flush all pending data */ readcb(bev, ctx); if (evbuffer_get_length( bufferevent_get_output(partner))) { /* We still have to flush data from the other * side, but when that's done, close the other * side. */ bufferevent_setcb(partner, NULL, close_on_finished_writecb, eventcb, NULL); bufferevent_disable(partner, EV_READ); } else { /* We have nothing left to say to the other * side; close it. */ bufferevent_free(partner); } } bufferevent_free(bev); } } static void syntax(void) { fputs("Syntax:\n", stderr); fputs(" le-proxy [-s] [-W] \n", stderr); fputs("Example:\n", stderr); fputs(" le-proxy 127.0.0.1:8888 1.2.3.4:80\n", stderr); exit(1); } static void accept_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *a, int slen, void *p) { struct bufferevent *b_out, *b_in; /* Create two linked bufferevent objects: one to connect, one for the * new connection */ b_in = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!ssl_ctx || use_wrapper) b_out = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); else { SSL *ssl = SSL_new(ssl_ctx); b_out = bufferevent_openssl_socket_new(base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); } assert(b_in && b_out); if (bufferevent_socket_connect(b_out, (struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) { perror("bufferevent_socket_connect"); bufferevent_free(b_out); bufferevent_free(b_in); return; } if (ssl_ctx && use_wrapper) { struct bufferevent *b_ssl; SSL *ssl = SSL_new(ssl_ctx); b_ssl = bufferevent_openssl_filter_new(base, b_out, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); if (!b_ssl) { perror("Bufferevent_openssl_new"); bufferevent_free(b_out); bufferevent_free(b_in); return; } b_out = b_ssl; } bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out); bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in); bufferevent_enable(b_in, EV_READ|EV_WRITE); bufferevent_enable(b_out, EV_READ|EV_WRITE); } int main(int argc, char **argv) { int i; int socklen; int use_ssl = 0; struct evconnlistener *listener; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); (void) WSAStartup(wVersionRequested, &wsaData); #endif if (argc < 3) syntax(); for (i=1; i < argc; ++i) { if (!strcmp(argv[i], "-s")) { use_ssl = 1; } else if (!strcmp(argv[i], "-W")) { use_wrapper = 0; } else if (argv[i][0] == '-') { syntax(); } else break; } if (i+2 != argc) syntax(); memset(&listen_on_addr, 0, sizeof(listen_on_addr)); socklen = sizeof(listen_on_addr); if (evutil_parse_sockaddr_port(argv[i], (struct sockaddr*)&listen_on_addr, &socklen)<0) { int p = atoi(argv[i]); struct sockaddr_in *sin = (struct sockaddr_in*)&listen_on_addr; if (p < 1 || p > 65535) syntax(); sin->sin_port = htons(p); sin->sin_addr.s_addr = htonl(0x7f000001); sin->sin_family = AF_INET; socklen = sizeof(struct sockaddr_in); } memset(&connect_to_addr, 0, sizeof(connect_to_addr)); connect_to_addrlen = sizeof(connect_to_addr); if (evutil_parse_sockaddr_port(argv[i+1], (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) syntax(); base = event_base_new(); if (!base) { perror("event_base_new()"); return 1; } if (use_ssl) { int r; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) SSL_library_init(); ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif r = RAND_poll(); if (r == 0) { fprintf(stderr, "RAND_poll() failed.\n"); return 1; } ssl_ctx = SSL_CTX_new(TLS_method()); } listener = evconnlistener_new_bind(base, accept_cb, NULL, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&listen_on_addr, socklen); if (! listener) { fprintf(stderr, "Couldn't open listener.\n"); event_base_free(base); return 1; } event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); #ifdef _WIN32 WSACleanup(); #endif return 0; } lldpd-1.0.13/libevent/sample/time-test.c0000644000076400001440000000425114111362571020544 0ustar00bernatusers00000000000000/* * XXX This sample code was once meant to show how to use the basic Libevent * interfaces, but it never worked on non-Unix platforms, and some of the * interfaces have changed since it was first written. It should probably * be removed or replaced with something better. * * Compile with: * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent */ #include #include #include #ifndef _WIN32 #include #include #endif #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #endif struct timeval lasttime; int event_is_persistent; static void timeout_cb(evutil_socket_t fd, short event, void *arg) { struct timeval newtime, difference; struct event *timeout = arg; double elapsed; evutil_gettimeofday(&newtime, NULL); evutil_timersub(&newtime, &lasttime, &difference); elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6); printf("timeout_cb called at %d: %.3f seconds elapsed.\n", (int)newtime.tv_sec, elapsed); lasttime = newtime; if (! event_is_persistent) { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 2; event_add(timeout, &tv); } } int main(int argc, char **argv) { struct event timeout; struct timeval tv; struct event_base *base; int flags; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); (void)WSAStartup(wVersionRequested, &wsaData); #endif if (argc == 2 && !strcmp(argv[1], "-p")) { event_is_persistent = 1; flags = EV_PERSIST; } else { event_is_persistent = 0; flags = 0; } /* Initialize the event library */ base = event_base_new(); /* Initialize one event */ event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout); evutil_timerclear(&tv); tv.tv_sec = 2; event_add(&timeout, &tv); evutil_gettimeofday(&lasttime, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); event_base_dispatch(base); return (0); } lldpd-1.0.13/libevent/sample/dns-example.c0000644000076400001440000001514714111362571021054 0ustar00bernatusers00000000000000/* This example code shows how to use the high-level, low-level, and server-level interfaces of evdns. XXX It's pretty ugly and should probably be cleaned up. */ #include /* Compatibility for possible missing IPv6 declarations */ #include "../ipv6-internal.h" #include #ifdef EVENT__HAVE_UNISTD_H #include #endif #ifdef _WIN32 #include #include #include #else #include #include #include #endif #include #include #include #include #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #include #include #include #define u32 ev_uint32_t #define u8 ev_uint8_t static const char * debug_ntoa(u32 address) { static char buf[32]; u32 a = ntohl(address); evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d", (int)(u8)((a>>24)&0xff), (int)(u8)((a>>16)&0xff), (int)(u8)((a>>8 )&0xff), (int)(u8)((a )&0xff)); return buf; } static void main_callback(int result, char type, int count, int ttl, void *addrs, void *orig) { char *n = (char*)orig; int i; for (i = 0; i < count; ++i) { if (type == DNS_IPv4_A) { printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i])); } else if (type == DNS_PTR) { printf("%s: %s\n", n, ((char**)addrs)[i]); } } if (!count) { printf("%s: No answer (%d)\n", n, result); } fflush(stdout); } static void gai_callback(int err, struct evutil_addrinfo *ai, void *arg) { const char *name = arg; int i; struct evutil_addrinfo *first_ai = ai; if (err) { printf("%s: %s\n", name, evutil_gai_strerror(err)); } if (ai && ai->ai_canonname) printf(" %s ==> %s\n", name, ai->ai_canonname); for (i=0; ai; ai = ai->ai_next, ++i) { char buf[128]; if (ai->ai_family == PF_INET) { struct sockaddr_in *sin = (struct sockaddr_in*)ai->ai_addr; evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); printf("[%d] %s: %s\n",i,name,buf); } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr; evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf)); printf("[%d] %s: %s\n",i,name,buf); } } if (first_ai) evutil_freeaddrinfo(first_ai); } static void evdns_server_callback(struct evdns_server_request *req, void *data) { int i, r; (void)data; /* dummy; give 192.168.11.11 as an answer for all A questions, * give foo.bar.example.com as an answer for all PTR questions. */ for (i = 0; i < req->nquestions; ++i) { u32 ans = htonl(0xc0a80b0bUL); if (req->questions[i]->type == EVDNS_TYPE_A && req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { printf(" -- replying for %s (A)\n", req->questions[i]->name); r = evdns_server_request_add_a_reply(req, req->questions[i]->name, 1, &ans, 10); if (r<0) printf("eeep, didn't work.\n"); } else if (req->questions[i]->type == EVDNS_TYPE_PTR && req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { printf(" -- replying for %s (PTR)\n", req->questions[i]->name); r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, "foo.bar.example.com", 10); if (r<0) printf("ugh, no luck"); } else { printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, req->questions[i]->type, req->questions[i]->dns_question_class); } } r = evdns_server_request_respond(req, 0); if (r<0) printf("eeek, couldn't send reply.\n"); } static int verbose = 0; static void logfn(int is_warn, const char *msg) { if (!is_warn && !verbose) return; fprintf(stderr, "%s: %s\n", is_warn?"WARN":"INFO", msg); } int main(int c, char **v) { struct options { int reverse; int use_getaddrinfo; int servertest; const char *resolv_conf; const char *ns; }; struct options o; int opt; struct event_base *event_base = NULL; struct evdns_base *evdns_base = NULL; memset(&o, 0, sizeof(o)); if (c < 2) { fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] [-s ns] hostname\n", v[0]); fprintf(stderr, "syntax: %s [-T]\n", v[0]); return 1; } while ((opt = getopt(c, v, "xvc:Ts:g")) != -1) { switch (opt) { case 'x': o.reverse = 1; break; case 'v': ++verbose; break; case 'g': o.use_getaddrinfo = 1; break; case 'T': o.servertest = 1; break; case 'c': o.resolv_conf = optarg; break; case 's': o.ns = optarg; break; default : fprintf(stderr, "Unknown option %c\n", opt); break; } } #ifdef _WIN32 { WSADATA WSAData; WSAStartup(0x101, &WSAData); } #endif event_base = event_base_new(); evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); evdns_set_log_fn(logfn); if (o.servertest) { evutil_socket_t sock; struct sockaddr_in my_addr; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock == -1) { perror("socket"); exit(1); } evutil_make_socket_nonblocking(sock); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(10053); my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) { perror("bind"); exit(1); } evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL); } if (optind < c) { int res; #ifdef _WIN32 if (o.resolv_conf == NULL && !o.ns) res = evdns_base_config_windows_nameservers(evdns_base); else #endif if (o.ns) res = evdns_base_nameserver_ip_add(evdns_base, o.ns); else res = evdns_base_resolv_conf_parse(evdns_base, DNS_OPTION_NAMESERVERS, o.resolv_conf); if (res) { fprintf(stderr, "Couldn't configure nameservers\n"); return 1; } } printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME); for (; optind < c; ++optind) { if (o.reverse) { struct in_addr addr; if (evutil_inet_pton(AF_INET, v[optind], &addr)!=1) { fprintf(stderr, "Skipping non-IP %s\n", v[optind]); continue; } fprintf(stderr, "resolving %s...\n",v[optind]); evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[optind]); } else if (o.use_getaddrinfo) { struct evutil_addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = EVUTIL_AI_CANONNAME; fprintf(stderr, "resolving (fwd) %s...\n",v[optind]); evdns_getaddrinfo(evdns_base, v[optind], NULL, &hints, gai_callback, v[optind]); } else { fprintf(stderr, "resolving (fwd) %s...\n",v[optind]); evdns_base_resolve_ipv4(evdns_base, v[optind], 0, main_callback, v[optind]); } } fflush(stdout); event_base_dispatch(event_base); evdns_base_free(evdns_base, 1); event_base_free(event_base); return 0; } lldpd-1.0.13/libevent/sample/hello-world.c0000644000076400001440000000661714111362571021071 0ustar00bernatusers00000000000000/* This example program provides a trivial server program that listens for TCP connections on port 9995. When they arrive, it writes a short message to each client connection, and closes each connection once it is flushed. Where possible, it exits cleanly in response to a SIGINT (ctrl-c). */ #include #include #include #include #ifndef _WIN32 #include # ifdef _XOPEN_SOURCE_EXTENDED # include # endif #include #endif #include #include #include #include #include static const char MESSAGE[] = "Hello, World!\n"; static const int PORT = 9995; static void listener_cb(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *); static void conn_writecb(struct bufferevent *, void *); static void conn_eventcb(struct bufferevent *, short, void *); static void signal_cb(evutil_socket_t, short, void *); int main(int argc, char **argv) { struct event_base *base; struct evconnlistener *listener; struct event *signal_event; struct sockaddr_in sin = {0}; #ifdef _WIN32 WSADATA wsa_data; WSAStartup(0x0201, &wsa_data); #endif base = event_base_new(); if (!base) { fprintf(stderr, "Could not initialize libevent!\n"); return 1; } sin.sin_family = AF_INET; sin.sin_port = htons(PORT); listener = evconnlistener_new_bind(base, listener_cb, (void *)base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { fprintf(stderr, "Could not create a listener!\n"); return 1; } signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base); if (!signal_event || event_add(signal_event, NULL)<0) { fprintf(stderr, "Could not create/add a signal event!\n"); return 1; } event_base_dispatch(base); evconnlistener_free(listener); event_free(signal_event); event_base_free(base); printf("done\n"); return 0; } static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data) { struct event_base *base = user_data; struct bufferevent *bev; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); if (!bev) { fprintf(stderr, "Error constructing bufferevent!"); event_base_loopbreak(base); return; } bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL); bufferevent_enable(bev, EV_WRITE); bufferevent_disable(bev, EV_READ); bufferevent_write(bev, MESSAGE, strlen(MESSAGE)); } static void conn_writecb(struct bufferevent *bev, void *user_data) { struct evbuffer *output = bufferevent_get_output(bev); if (evbuffer_get_length(output) == 0) { printf("flushed answer\n"); bufferevent_free(bev); } } static void conn_eventcb(struct bufferevent *bev, short events, void *user_data) { if (events & BEV_EVENT_EOF) { printf("Connection closed.\n"); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s\n", strerror(errno));/*XXX win32*/ } /* None of the other events can happen here, since we haven't enabled * timeouts */ bufferevent_free(bev); } static void signal_cb(evutil_socket_t sig, short events, void *user_data) { struct event_base *base = user_data; struct timeval delay = { 2, 0 }; printf("Caught an interrupt signal; exiting cleanly in two seconds.\n"); event_base_loopexit(base, &delay); } lldpd-1.0.13/libevent/sample/hostcheck.c0000644000076400001440000001473714111362571020616 0ustar00bernatusers00000000000000/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* This file is an amalgamation of hostcheck.c and most of rawstr.c from cURL. The contents of the COPYING file mentioned above are: COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2013, Daniel Stenberg, . All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. */ #include "hostcheck.h" #include /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ static char Curl_raw_toupper(char in) { switch (in) { case 'a': return 'A'; case 'b': return 'B'; case 'c': return 'C'; case 'd': return 'D'; case 'e': return 'E'; case 'f': return 'F'; case 'g': return 'G'; case 'h': return 'H'; case 'i': return 'I'; case 'j': return 'J'; case 'k': return 'K'; case 'l': return 'L'; case 'm': return 'M'; case 'n': return 'N'; case 'o': return 'O'; case 'p': return 'P'; case 'q': return 'Q'; case 'r': return 'R'; case 's': return 'S'; case 't': return 'T'; case 'u': return 'U'; case 'v': return 'V'; case 'w': return 'W'; case 'x': return 'X'; case 'y': return 'Y'; case 'z': return 'Z'; } return in; } /* * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant * to be locale independent and only compare strings we know are safe for * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for * some further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for * non-ascii. */ static int Curl_raw_equal(const char *first, const char *second) { while(*first && *second) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) /* get out of the loop as soon as they don't match */ break; first++; second++; } /* we do the comparison here (possibly again), just to make sure that if the loop above is skipped because one of the strings reached zero, we must not return this as a successful match */ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } static int Curl_raw_nequal(const char *first, const char *second, size_t max) { while(*first && *second && max) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { break; } max--; first++; second++; } if(0 == max) return 1; /* they are equal this far */ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); } /* * Match a hostname against a wildcard pattern. * E.g. * "foo.host.com" matches "*.host.com". * * We use the matching rule described in RFC6125, section 6.4.3. * http://tools.ietf.org/html/rfc6125#section-6.4.3 */ static int hostmatch(const char *hostname, const char *pattern) { const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; int wildcard_enabled; size_t prefixlen, suffixlen; pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) return Curl_raw_equal(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* We require at least 2 dots in pattern to avoid too wide wildcard match. */ wildcard_enabled = 1; pattern_label_end = strchr(pattern, '.'); if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || pattern_wildcard > pattern_label_end || Curl_raw_nequal(pattern, "xn--", 4)) { wildcard_enabled = 0; } if(!wildcard_enabled) return Curl_raw_equal(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if(hostname_label_end == NULL || !Curl_raw_equal(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most label of the hostname is at least as large as the left-most label of the pattern. */ if(hostname_label_end - hostname < pattern_label_end - pattern) return CURL_HOST_NOMATCH; prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard+1); return Curl_raw_nequal(pattern, hostname, prefixlen) && Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) { if(!match_pattern || !*match_pattern || !hostname || !*hostname) /* sanity check */ return 0; if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */ return 1; if(hostmatch(hostname,match_pattern) == CURL_HOST_MATCH) return 1; return 0; } lldpd-1.0.13/libevent/sample/signal-test.c0000644000076400001440000000254414111362571021066 0ustar00bernatusers00000000000000/* * Compile with: * cc -I/usr/local/include -o signal-test \ * signal-test.c -L/usr/local/lib -levent */ #include #include #include #ifndef _WIN32 #include #include #include #else #include #include #endif #include #include #include #include #include #include #include int called = 0; static void signal_cb(evutil_socket_t fd, short event, void *arg) { struct event *signal = arg; printf("signal_cb: got signal %d\n", event_get_signal(signal)); if (called >= 2) event_del(signal); called++; } int main(int argc, char **argv) { struct event *signal_int = NULL; struct event_base* base; int ret = 0; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); (void) WSAStartup(wVersionRequested, &wsaData); #endif /* Initialize the event library */ base = event_base_new(); if (!base) { ret = 1; goto out; } /* Initialize one event */ signal_int = evsignal_new(base, SIGINT, signal_cb, event_self_cbarg()); if (!signal_int) { ret = 2; goto out; } event_add(signal_int, NULL); event_base_dispatch(base); out: if (signal_int) event_free(signal_int); if (base) event_base_free(base); return ret; } lldpd-1.0.13/libevent/sample/openssl_hostname_validation.c0000644000076400001440000001567514111362571024440 0ustar00bernatusers00000000000000/* Obtained from: https://github.com/iSECPartners/ssl-conservatory */ /* Copyright (C) 2012, iSEC Partners. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Helper functions to perform basic hostname validation using OpenSSL. * * Please read "everything-you-wanted-to-know-about-openssl.pdf" before * attempting to use this code. This whitepaper describes how the code works, * how it should be used, and what its limitations are. * * Author: Alban Diquet * License: See LICENSE * */ // Get rid of OSX 10.7 and greater deprecation warnings. #if defined(__APPLE__) && defined(__clang__) #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif #include #include #include #include "openssl_hostname_validation.h" #include "hostcheck.h" #define HOSTNAME_MAX_SIZE 255 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) #define ASN1_STRING_get0_data ASN1_STRING_data #endif /** * Tries to find a match for hostname in the certificate's Common Name field. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if the Common Name had a NUL character embedded in it. * Returns Error if the Common Name could not be extracted. */ static HostnameValidationResult matches_common_name(const char *hostname, const X509 *server_cert) { int common_name_loc = -1; X509_NAME_ENTRY *common_name_entry = NULL; ASN1_STRING *common_name_asn1 = NULL; const char *common_name_str = NULL; // Find the position of the CN field in the Subject field of the certificate common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, -1); if (common_name_loc < 0) { return Error; } // Extract the CN field common_name_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), common_name_loc); if (common_name_entry == NULL) { return Error; } // Convert the CN field to a C string common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); if (common_name_asn1 == NULL) { return Error; } common_name_str = (char *) ASN1_STRING_get0_data(common_name_asn1); // Make sure there isn't an embedded NUL character in the CN if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) { return MalformedCertificate; } // Compare expected hostname with the CN if (Curl_cert_hostcheck(common_name_str, hostname) == CURL_HOST_MATCH) { return MatchFound; } else { return MatchNotFound; } } /** * Tries to find a match for hostname in the certificate's Subject Alternative Name extension. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns NoSANPresent if the SAN extension was not present in the certificate. */ static HostnameValidationResult matches_subject_alternative_name(const char *hostname, const X509 *server_cert) { HostnameValidationResult result = MatchNotFound; int i; int san_names_nb = -1; STACK_OF(GENERAL_NAME) *san_names = NULL; // Try to extract the names within the SAN extension from the certificate san_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL); if (san_names == NULL) { return NoSANPresent; } san_names_nb = sk_GENERAL_NAME_num(san_names); // Check each name within the extension for (i=0; itype == GEN_DNS) { // Current name is a DNS name, let's check it const char *dns_name = (char *) ASN1_STRING_get0_data(current_name->d.dNSName); // Make sure there isn't an embedded NUL character in the DNS name if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) { result = MalformedCertificate; break; } else { // Compare expected hostname with the DNS name if (Curl_cert_hostcheck(dns_name, hostname) == CURL_HOST_MATCH) { result = MatchFound; break; } } } } sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); return result; } /** * Validates the server's identity by looking for the expected hostname in the * server's certificate. As described in RFC 6125, it first tries to find a match * in the Subject Alternative Name extension. If the extension is not present in * the certificate, it checks the Common Name instead. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns Error if there was an error. */ HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert) { HostnameValidationResult result; if((hostname == NULL) || (server_cert == NULL)) return Error; // First try the Subject Alternative Names extension result = matches_subject_alternative_name(hostname, server_cert); if (result == NoSANPresent) { // Extension was not found: try the Common Name result = matches_common_name(hostname, server_cert); } return result; } lldpd-1.0.13/libevent/sample/https-client.c0000644000076400001440000003242714111362571021255 0ustar00bernatusers00000000000000/* This is an example of how to hook up evhttp with bufferevent_ssl It just GETs an https URL given on the command-line and prints the response body to stdout. Actually, it also accepts plain http URLs to make it easy to compare http vs https code paths. Loosely based on le-proxy.c. */ // Get rid of OSX 10.7 and greater deprecation warnings. #if defined(__APPLE__) && defined(__clang__) #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif #include #include #include #include #include #ifdef _WIN32 #include #include #define snprintf _snprintf #define strcasecmp _stricmp #else #include #include #endif #include #include #include #include #include #include #include #include #include #include "openssl_hostname_validation.h" static int ignore_cert = 0; static void http_request_done(struct evhttp_request *req, void *ctx) { char buffer[256]; int nread; if (!req || !evhttp_request_get_response_code(req)) { /* If req is NULL, it means an error occurred, but * sadly we are mostly left guessing what the error * might have been. We'll do our best... */ struct bufferevent *bev = (struct bufferevent *) ctx; unsigned long oslerr; int printed_err = 0; int errcode = EVUTIL_SOCKET_ERROR(); fprintf(stderr, "some request failed - no idea which one though!\n"); /* Print out the OpenSSL error queue that libevent * squirreled away for us, if any. */ while ((oslerr = bufferevent_get_openssl_error(bev))) { ERR_error_string_n(oslerr, buffer, sizeof(buffer)); fprintf(stderr, "%s\n", buffer); printed_err = 1; } /* If the OpenSSL error queue was empty, maybe it was a * socket error; let's try printing that. */ if (! printed_err) fprintf(stderr, "socket error = %s (%d)\n", evutil_socket_error_to_string(errcode), errcode); return; } fprintf(stderr, "Response line: %d %s\n", evhttp_request_get_response_code(req), evhttp_request_get_response_code_line(req)); while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req), buffer, sizeof(buffer))) > 0) { /* These are just arbitrary chunks of 256 bytes. * They are not lines, so we can't treat them as such. */ fwrite(buffer, nread, 1, stdout); } } static void syntax(void) { fputs("Syntax:\n", stderr); fputs(" https-client -url [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr); fputs("Example:\n", stderr); fputs(" https-client -url https://ip.appspot.com/\n", stderr); } static void err(const char *msg) { fputs(msg, stderr); } static void err_openssl(const char *func) { fprintf (stderr, "%s failed:\n", func); /* This is the OpenSSL function that prints the contents of the * error stack to the specified file handle. */ ERR_print_errors_fp (stderr); exit(1); } /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */ static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg) { char cert_str[256]; const char *host = (const char *) arg; const char *res_str = "X509_verify_cert failed"; HostnameValidationResult res = Error; /* This is the function that OpenSSL would call if we hadn't called * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping" * the default functionality, rather than replacing it. */ int ok_so_far = 0; X509 *server_cert = NULL; if (ignore_cert) { return 1; } ok_so_far = X509_verify_cert(x509_ctx); server_cert = X509_STORE_CTX_get_current_cert(x509_ctx); if (ok_so_far) { res = validate_hostname(host, server_cert); switch (res) { case MatchFound: res_str = "MatchFound"; break; case MatchNotFound: res_str = "MatchNotFound"; break; case NoSANPresent: res_str = "NoSANPresent"; break; case MalformedCertificate: res_str = "MalformedCertificate"; break; case Error: res_str = "Error"; break; default: res_str = "WTF!"; break; } } X509_NAME_oneline(X509_get_subject_name (server_cert), cert_str, sizeof (cert_str)); if (res == MatchFound) { printf("https server '%s' has this certificate, " "which looks good to me:\n%s\n", host, cert_str); return 1; } else { printf("Got '%s' for hostname '%s' and certificate:\n%s\n", res_str, host, cert_str); return 0; } } #ifdef _WIN32 static int add_cert_for_store(X509_STORE *store, const char *name) { HCERTSTORE sys_store = NULL; PCCERT_CONTEXT ctx = NULL; int r = 0; sys_store = CertOpenSystemStore(0, name); if (!sys_store) { err("failed to open system certificate store"); return -1; } while ((ctx = CertEnumCertificatesInStore(sys_store, ctx))) { X509 *x509 = d2i_X509(NULL, (unsigned char const **)&ctx->pbCertEncoded, ctx->cbCertEncoded); if (x509) { X509_STORE_add_cert(store, x509); X509_free(x509); } else { r = -1; err_openssl("d2i_X509"); break; } } CertCloseStore(sys_store, 0); return r; } #endif int main(int argc, char **argv) { int r; struct event_base *base = NULL; struct evhttp_uri *http_uri = NULL; const char *url = NULL, *data_file = NULL; const char *crt = NULL; const char *scheme, *host, *path, *query; char uri[256]; int port; int retries = 0; int timeout = -1; SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; struct bufferevent *bev; struct evhttp_connection *evcon = NULL; struct evhttp_request *req; struct evkeyvalq *output_headers; struct evbuffer *output_buffer; int i; int ret = 0; enum { HTTP, HTTPS } type = HTTP; for (i = 1; i < argc; i++) { if (!strcmp("-url", argv[i])) { if (i < argc - 1) { url = argv[i + 1]; } else { syntax(); goto error; } } else if (!strcmp("-crt", argv[i])) { if (i < argc - 1) { crt = argv[i + 1]; } else { syntax(); goto error; } } else if (!strcmp("-ignore-cert", argv[i])) { ignore_cert = 1; } else if (!strcmp("-data", argv[i])) { if (i < argc - 1) { data_file = argv[i + 1]; } else { syntax(); goto error; } } else if (!strcmp("-retries", argv[i])) { if (i < argc - 1) { retries = atoi(argv[i + 1]); } else { syntax(); goto error; } } else if (!strcmp("-timeout", argv[i])) { if (i < argc - 1) { timeout = atoi(argv[i + 1]); } else { syntax(); goto error; } } else if (!strcmp("-help", argv[i])) { syntax(); goto error; } } if (!url) { syntax(); goto error; } #ifdef _WIN32 { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { printf("WSAStartup failed with error: %d\n", err); goto error; } } #endif // _WIN32 http_uri = evhttp_uri_parse(url); if (http_uri == NULL) { err("malformed url"); goto error; } scheme = evhttp_uri_get_scheme(http_uri); if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && strcasecmp(scheme, "http") != 0)) { err("url must be http or https"); goto error; } host = evhttp_uri_get_host(http_uri); if (host == NULL) { err("url must have a host"); goto error; } port = evhttp_uri_get_port(http_uri); if (port == -1) { port = (strcasecmp(scheme, "http") == 0) ? 80 : 443; } path = evhttp_uri_get_path(http_uri); if (strlen(path) == 0) { path = "/"; } query = evhttp_uri_get_query(http_uri); if (query == NULL) { snprintf(uri, sizeof(uri) - 1, "%s", path); } else { snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query); } uri[sizeof(uri) - 1] = '\0'; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) // Initialize OpenSSL SSL_library_init(); ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif /* This isn't strictly necessary... OpenSSL performs RAND_poll * automatically on first use of random number generator. */ r = RAND_poll(); if (r == 0) { err_openssl("RAND_poll"); goto error; } /* Create a new OpenSSL context */ ssl_ctx = SSL_CTX_new(SSLv23_method()); if (!ssl_ctx) { err_openssl("SSL_CTX_new"); goto error; } if (crt == NULL) { X509_STORE *store; /* Attempt to use the system's trusted root certificates. */ store = SSL_CTX_get_cert_store(ssl_ctx); #ifdef _WIN32 if (add_cert_for_store(store, "CA") < 0 || add_cert_for_store(store, "AuthRoot") < 0 || add_cert_for_store(store, "ROOT") < 0) { goto error; } #else // _WIN32 if (X509_STORE_set_default_paths(store) != 1) { err_openssl("X509_STORE_set_default_paths"); goto error; } #endif // _WIN32 } else { if (SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL) != 1) { err_openssl("SSL_CTX_load_verify_locations"); goto error; } } /* Ask OpenSSL to verify the server certificate. Note that this * does NOT include verifying that the hostname is correct. * So, by itself, this means anyone with any legitimate * CA-issued certificate for any website, can impersonate any * other website in the world. This is not good. See "The * Most Dangerous Code in the World" article at * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html */ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); /* This is how we solve the problem mentioned in the previous * comment. We "wrap" OpenSSL's validation routine in our * own routine, which also validates the hostname by calling * the code provided by iSECPartners. Note that even though * the "Everything You've Always Wanted to Know About * Certificate Validation With OpenSSL (But Were Afraid to * Ask)" paper from iSECPartners says very explicitly not to * call SSL_CTX_set_cert_verify_callback (at the bottom of * page 2), what we're doing here is safe because our * cert_verify_callback() calls X509_verify_cert(), which is * OpenSSL's built-in routine which would have been called if * we hadn't set the callback. Therefore, we're just * "wrapping" OpenSSL's routine, not replacing it. */ SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback, (void *) host); // Create event base base = event_base_new(); if (!base) { perror("event_base_new()"); goto error; } // Create OpenSSL bufferevent and stack evhttp on top of it ssl = SSL_new(ssl_ctx); if (ssl == NULL) { err_openssl("SSL_new()"); goto error; } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME // Set hostname for SNI extension SSL_set_tlsext_host_name(ssl, host); #endif if (strcasecmp(scheme, "http") == 0) { bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); } else { type = HTTPS; bev = bufferevent_openssl_socket_new(base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); } if (bev == NULL) { fprintf(stderr, "bufferevent_openssl_socket_new() failed\n"); goto error; } bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); // For simplicity, we let DNS resolution block. Everything else should be // asynchronous though. evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev, host, port); if (evcon == NULL) { fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n"); goto error; } if (retries > 0) { evhttp_connection_set_retries(evcon, retries); } if (timeout >= 0) { evhttp_connection_set_timeout(evcon, timeout); } // Fire off the request req = evhttp_request_new(http_request_done, bev); if (req == NULL) { fprintf(stderr, "evhttp_request_new() failed\n"); goto error; } output_headers = evhttp_request_get_output_headers(req); evhttp_add_header(output_headers, "Host", host); evhttp_add_header(output_headers, "Connection", "close"); if (data_file) { /* NOTE: In production code, you'd probably want to use * evbuffer_add_file() or evbuffer_add_file_segment(), to * avoid needless copying. */ FILE * f = fopen(data_file, "rb"); char buf[1024]; size_t s; size_t bytes = 0; if (!f) { syntax(); goto error; } output_buffer = evhttp_request_get_output_buffer(req); while ((s = fread(buf, 1, sizeof(buf), f)) > 0) { evbuffer_add(output_buffer, buf, s); bytes += s; } evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes); evhttp_add_header(output_headers, "Content-Length", buf); fclose(f); } r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri); if (r != 0) { fprintf(stderr, "evhttp_make_request() failed\n"); goto error; } event_base_dispatch(base); goto cleanup; error: ret = 1; cleanup: if (evcon) evhttp_connection_free(evcon); if (http_uri) evhttp_uri_free(http_uri); if (base) event_base_free(base); if (ssl_ctx) SSL_CTX_free(ssl_ctx); if (type == HTTP && ssl) SSL_free(ssl); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) EVP_cleanup(); ERR_free_strings(); #if OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); #else ERR_remove_thread_state(NULL); #endif CRYPTO_cleanup_all_ex_data(); sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); #endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */ #ifdef _WIN32 WSACleanup(); #endif return ret; } lldpd-1.0.13/libevent/sample/http-connect.c0000644000076400001440000000662714111362571021250 0ustar00bernatusers00000000000000#include "event2/event-config.h" #include #include #include #include #include #include #include #define VERIFY(cond) do { \ if (!(cond)) { \ fprintf(stderr, "[error] %s\n", #cond); \ exit(EXIT_FAILURE); \ } \ } while (0); \ #define URL_MAX 4096 struct connect_base { struct evhttp_connection *evcon; struct evhttp_uri *location; }; static struct evhttp_uri* uri_parse(const char *str) { struct evhttp_uri *uri; VERIFY(uri = evhttp_uri_parse(str)); VERIFY(evhttp_uri_get_host(uri)); VERIFY(evhttp_uri_get_port(uri) > 0); return uri; } static char* uri_path(struct evhttp_uri *uri, char buffer[URL_MAX]) { struct evhttp_uri *path; VERIFY(evhttp_uri_join(uri, buffer, URL_MAX)); path = evhttp_uri_parse(buffer); evhttp_uri_set_scheme(path, NULL); evhttp_uri_set_userinfo(path, 0); evhttp_uri_set_host(path, NULL); evhttp_uri_set_port(path, -1); VERIFY(evhttp_uri_join(path, buffer, URL_MAX)); return buffer; } static char* uri_hostport(struct evhttp_uri *uri, char buffer[URL_MAX]) { VERIFY(evhttp_uri_join(uri, buffer, URL_MAX)); VERIFY(evhttp_uri_get_host(uri)); VERIFY(evhttp_uri_get_port(uri) > 0); evutil_snprintf(buffer, URL_MAX, "%s:%d", evhttp_uri_get_host(uri), evhttp_uri_get_port(uri)); return buffer; } static void get_cb(struct evhttp_request *req, void *arg) { ev_ssize_t len; struct evbuffer *evbuf; VERIFY(req); evbuf = evhttp_request_get_input_buffer(req); len = evbuffer_get_length(evbuf); fwrite(evbuffer_pullup(evbuf, len), len, 1, stdout); evbuffer_drain(evbuf, len); } static void connect_cb(struct evhttp_request *proxy_req, void *arg) { struct connect_base *base = arg; struct evhttp_connection *evcon = base->evcon; struct evhttp_uri *location = base->location; struct evhttp_request *req; char buffer[URL_MAX]; VERIFY(proxy_req); VERIFY(evcon); req = evhttp_request_new(get_cb, NULL); evhttp_add_header(req->output_headers, "Connection", "close"); evhttp_add_header(req->output_headers, "Host", evhttp_uri_get_host(location)); VERIFY(!evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri_path(location, buffer))); } int main(int argc, const char **argv) { char hostport[URL_MAX]; struct evhttp_uri *location; struct evhttp_uri *proxy; struct event_base *base; struct evhttp_connection *evcon; struct evhttp_request *req; struct connect_base connect_base; if (argc != 3) { printf("Usage: %s proxy url\n", argv[0]); return 1; } proxy = uri_parse(argv[1]); location = uri_parse(argv[2]); VERIFY(base = event_base_new()); VERIFY(evcon = evhttp_connection_base_new(base, NULL, evhttp_uri_get_host(proxy), evhttp_uri_get_port(proxy))); connect_base.evcon = evcon; connect_base.location = location; VERIFY(req = evhttp_request_new(connect_cb, &connect_base)); uri_hostport(location, hostport); evhttp_add_header(req->output_headers, "Connection", "keep-alive"); evhttp_add_header(req->output_headers, "Proxy-Connection", "keep-alive"); evhttp_add_header(req->output_headers, "Host", hostport); evhttp_make_request(evcon, req, EVHTTP_REQ_CONNECT, hostport); event_base_dispatch(base); evhttp_connection_free(evcon); event_base_free(base); evhttp_uri_free(proxy); evhttp_uri_free(location); return 0; } lldpd-1.0.13/libevent/sample/include.am0000644000076400001440000000356714111362571020440 0ustar00bernatusers00000000000000# sample/include.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. SAMPLES = \ sample/dns-example \ sample/event-read-fifo \ sample/hello-world \ sample/http-server \ sample/http-connect \ sample/signal-test \ sample/time-test if OPENSSL SAMPLES += sample/le-proxy sample_le_proxy_SOURCES = sample/le-proxy.c sample_le_proxy_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD) sample_le_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS) SAMPLES += sample/https-client sample_https_client_SOURCES = \ sample/https-client.c \ sample/hostcheck.c \ sample/openssl_hostname_validation.c sample_https_client_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD) if BUILD_WIN32 sample_https_client_LDADD += -lcrypt32 endif sample_https_client_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS) noinst_HEADERS += \ sample/hostcheck.h \ sample/openssl_hostname_validation.h endif if BUILD_SAMPLES noinst_PROGRAMS += $(SAMPLES) endif $(SAMPLES) : libevent.la sample_event_read_fifo_SOURCES = sample/event-read-fifo.c sample_event_read_fifo_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_time_test_SOURCES = sample/time-test.c sample_time_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_signal_test_SOURCES = sample/signal-test.c sample_signal_test_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_dns_example_SOURCES = sample/dns-example.c sample_dns_example_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_hello_world_SOURCES = sample/hello-world.c sample_hello_world_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_http_server_SOURCES = sample/http-server.c sample_http_server_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la sample_http_connect_SOURCES = sample/http-connect.c sample_http_connect_LDADD = $(LIBEVENT_GC_SECTIONS) libevent.la lldpd-1.0.13/libevent/sample/openssl_hostname_validation.h0000644000076400001440000000431314111362571024430 0ustar00bernatusers00000000000000/* Obtained from: https://github.com/iSECPartners/ssl-conservatory */ /* Copyright (C) 2012, iSEC Partners. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Helper functions to perform basic hostname validation using OpenSSL. * * Please read "everything-you-wanted-to-know-about-openssl.pdf" before * attempting to use this code. This whitepaper describes how the code works, * how it should be used, and what its limitations are. * * Author: Alban Diquet * License: See LICENSE * */ typedef enum { MatchFound, MatchNotFound, NoSANPresent, MalformedCertificate, Error } HostnameValidationResult; /** * Validates the server's identity by looking for the expected hostname in the * server's certificate. As described in RFC 6125, it first tries to find a match * in the Subject Alternative Name extension. If the extension is not present in * the certificate, it checks the Common Name instead. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns Error if there was an error. */ HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert); lldpd-1.0.13/libevent/sample/hostcheck.h0000644000076400001440000000235314111362571020612 0ustar00bernatusers00000000000000#ifndef HEADER_CURL_HOSTCHECK_H #define HEADER_CURL_HOSTCHECK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #define CURL_HOST_NOMATCH 0 #define CURL_HOST_MATCH 1 int Curl_cert_hostcheck(const char *match_pattern, const char *hostname); #endif /* HEADER_CURL_HOSTCHECK_H */ lldpd-1.0.13/libevent/sample/http-server.c0000644000076400001440000003264214111362571021121 0ustar00bernatusers00000000000000/* A trivial static http webserver using Libevent's evhttp. This is not the best code in the world, and it does some fairly stupid stuff that you would never want to do in a production webserver. Caveat hackor! */ /* Compatibility for possible missing IPv6 declarations */ #include "../util-internal.h" #include #include #include #include #include #ifdef _WIN32 #include #include #include #include #include #include #ifndef S_ISDIR #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) #endif #else /* !_WIN32 */ #include #include #include #include #include #endif /* _WIN32 */ #include #ifdef EVENT__HAVE_SYS_UN_H #include #endif #ifdef EVENT__HAVE_AFUNIX_H #include #endif #include #include #include #include #include #include #ifdef _WIN32 #include #endif /* _WIN32 */ #ifdef EVENT__HAVE_NETINET_IN_H #include # ifdef _XOPEN_SOURCE_EXTENDED # include # endif #endif #ifdef _WIN32 #ifndef stat #define stat _stat #endif #ifndef fstat #define fstat _fstat #endif #ifndef open #define open _open #endif #ifndef close #define close _close #endif #ifndef O_RDONLY #define O_RDONLY _O_RDONLY #endif #endif /* _WIN32 */ char uri_root[512]; static const struct table_entry { const char *extension; const char *content_type; } content_type_table[] = { { "txt", "text/plain" }, { "c", "text/plain" }, { "h", "text/plain" }, { "html", "text/html" }, { "htm", "text/htm" }, { "css", "text/css" }, { "gif", "image/gif" }, { "jpg", "image/jpeg" }, { "jpeg", "image/jpeg" }, { "png", "image/png" }, { "pdf", "application/pdf" }, { "ps", "application/postscript" }, { NULL, NULL }, }; struct options { int port; int iocp; int verbose; int unlink; const char *unixsock; const char *docroot; }; /* Try to guess a good content-type for 'path' */ static const char * guess_content_type(const char *path) { const char *last_period, *extension; const struct table_entry *ent; last_period = strrchr(path, '.'); if (!last_period || strchr(last_period, '/')) goto not_found; /* no exension */ extension = last_period + 1; for (ent = &content_type_table[0]; ent->extension; ++ent) { if (!evutil_ascii_strcasecmp(ent->extension, extension)) return ent->content_type; } not_found: return "application/misc"; } /* Callback used for the /dump URI, and for every non-GET request: * dumps all information to stdout and gives back a trivial 200 ok */ static void dump_request_cb(struct evhttp_request *req, void *arg) { const char *cmdtype; struct evkeyvalq *headers; struct evkeyval *header; struct evbuffer *buf; switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: cmdtype = "GET"; break; case EVHTTP_REQ_POST: cmdtype = "POST"; break; case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break; case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break; case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; default: cmdtype = "unknown"; break; } printf("Received a %s request for %s\nHeaders:\n", cmdtype, evhttp_request_get_uri(req)); headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; header = header->next.tqe_next) { printf(" %s: %s\n", header->key, header->value); } buf = evhttp_request_get_input_buffer(req); puts("Input data: <<<"); while (evbuffer_get_length(buf)) { int n; char cbuf[128]; n = evbuffer_remove(buf, cbuf, sizeof(cbuf)); if (n > 0) (void) fwrite(cbuf, 1, n, stdout); } puts(">>>"); evhttp_send_reply(req, 200, "OK", NULL); } /* This callback gets invoked when we get any http request that doesn't match * any other callback. Like any evhttp server callback, it has a simple job: * it must eventually call evhttp_send_error() or evhttp_send_reply(). */ static void send_document_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = NULL; struct options *o = arg; const char *uri = evhttp_request_get_uri(req); struct evhttp_uri *decoded = NULL; const char *path; char *decoded_path; char *whole_path = NULL; size_t len; int fd = -1; struct stat st; if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) { dump_request_cb(req, arg); return; } printf("Got a GET request for <%s>\n", uri); /* Decode the URI */ decoded = evhttp_uri_parse(uri); if (!decoded) { printf("It's not a good URI. Sending BADREQUEST\n"); evhttp_send_error(req, HTTP_BADREQUEST, 0); return; } /* Let's see what path the user asked for. */ path = evhttp_uri_get_path(decoded); if (!path) path = "/"; /* We need to decode it, to see what path the user really wanted. */ decoded_path = evhttp_uridecode(path, 0, NULL); if (decoded_path == NULL) goto err; /* Don't allow any ".."s in the path, to avoid exposing stuff outside * of the docroot. This test is both overzealous and underzealous: * it forbids aceptable paths like "/this/one..here", but it doesn't * do anything to prevent symlink following." */ if (strstr(decoded_path, "..")) goto err; len = strlen(decoded_path)+strlen(o->docroot)+2; if (!(whole_path = malloc(len))) { perror("malloc"); goto err; } evutil_snprintf(whole_path, len, "%s/%s", o->docroot, decoded_path); if (stat(whole_path, &st)<0) { goto err; } /* This holds the content we're sending. */ evb = evbuffer_new(); if (S_ISDIR(st.st_mode)) { /* If it's a directory, read the comments and make a little * index page */ #ifdef _WIN32 HANDLE d; WIN32_FIND_DATAA ent; char *pattern; size_t dirlen; #else DIR *d; struct dirent *ent; #endif const char *trailing_slash = ""; if (!strlen(path) || path[strlen(path)-1] != '/') trailing_slash = "/"; #ifdef _WIN32 dirlen = strlen(whole_path); pattern = malloc(dirlen+3); memcpy(pattern, whole_path, dirlen); pattern[dirlen] = '\\'; pattern[dirlen+1] = '*'; pattern[dirlen+2] = '\0'; d = FindFirstFileA(pattern, &ent); free(pattern); if (d == INVALID_HANDLE_VALUE) goto err; #else if (!(d = opendir(whole_path))) goto err; #endif evbuffer_add_printf(evb, "\n" "\n \n" " \n" " %s\n" " \n" " \n" " \n" "

%s

\n" "
    \n", decoded_path, /* XXX html-escape this. */ path, /* XXX html-escape this? */ trailing_slash, decoded_path /* XXX html-escape this */); #ifdef _WIN32 do { const char *name = ent.cFileName; #else while ((ent = readdir(d))) { const char *name = ent->d_name; #endif evbuffer_add_printf(evb, "
  • %s\n", name, name);/* XXX escape this */ #ifdef _WIN32 } while (FindNextFileA(d, &ent)); #else } #endif evbuffer_add_printf(evb, "
\n"); #ifdef _WIN32 FindClose(d); #else closedir(d); #endif evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/html"); } else { /* Otherwise it's a file; add it to the buffer to get * sent via sendfile */ const char *type = guess_content_type(decoded_path); if ((fd = open(whole_path, O_RDONLY)) < 0) { perror("open"); goto err; } if (fstat(fd, &st)<0) { /* Make sure the length still matches, now that we * opened the file :/ */ perror("fstat"); goto err; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", type); evbuffer_add_file(evb, fd, 0, st.st_size); } evhttp_send_reply(req, 200, "OK", evb); goto done; err: evhttp_send_error(req, 404, "Document was not found"); if (fd>=0) close(fd); done: if (decoded) evhttp_uri_free(decoded); if (decoded_path) free(decoded_path); if (whole_path) free(whole_path); if (evb) evbuffer_free(evb); } static void print_usage(FILE *out, const char *prog, int exit_code) { fprintf(out, "Syntax: %s [ OPTS ] \n" " -p - port\n" " -U - bind to unix socket\n" " -u - unlink unix socket before bind\n" " -I - IOCP\n" " -v - verbosity, enables libevent debug logging too\n", prog); exit(exit_code); } static struct options parse_opts(int argc, char **argv) { struct options o; int opt; memset(&o, 0, sizeof(o)); while ((opt = getopt(argc, argv, "hp:U:uIv")) != -1) { switch (opt) { case 'p': o.port = atoi(optarg); break; case 'U': o.unixsock = optarg; break; case 'u': o.unlink = 1; break; case 'I': o.iocp = 1; break; case 'v': ++o.verbose; break; case 'h': print_usage(stdout, argv[0], 0); break; default : fprintf(stderr, "Unknown option %c\n", opt); break; } } if (optind >= argc || (argc - optind) > 1) { print_usage(stdout, argv[0], 1); } o.docroot = argv[optind]; return o; } static void do_term(int sig, short events, void *arg) { struct event_base *base = arg; event_base_loopbreak(base); fprintf(stderr, "Got %i, Terminating\n", sig); } static int display_listen_sock(struct evhttp_bound_socket *handle) { struct sockaddr_storage ss; evutil_socket_t fd; ev_socklen_t socklen = sizeof(ss); char addrbuf[128]; void *inaddr; const char *addr; int got_port = -1; fd = evhttp_bound_socket_get_fd(handle); memset(&ss, 0, sizeof(ss)); if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) { perror("getsockname() failed"); return 1; } if (ss.ss_family == AF_INET) { got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port); inaddr = &((struct sockaddr_in*)&ss)->sin_addr; } else if (ss.ss_family == AF_INET6) { got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port); inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr; } #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN else if (ss.ss_family == AF_UNIX) { printf("Listening on <%s>\n", ((struct sockaddr_un*)&ss)->sun_path); return 0; } #endif else { fprintf(stderr, "Weird address family %d\n", ss.ss_family); return 1; } addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, sizeof(addrbuf)); if (addr) { printf("Listening on %s:%d\n", addr, got_port); evutil_snprintf(uri_root, sizeof(uri_root), "http://%s:%d",addr,got_port); } else { fprintf(stderr, "evutil_inet_ntop failed\n"); return 1; } return 0; } int main(int argc, char **argv) { struct event_config *cfg = NULL; struct event_base *base = NULL; struct evhttp *http = NULL; struct evhttp_bound_socket *handle = NULL; struct evconnlistener *lev = NULL; struct event *term = NULL; struct options o = parse_opts(argc, argv); int ret = 0; #ifdef _WIN32 { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); } #else if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { ret = 1; goto err; } #endif setbuf(stdout, NULL); setbuf(stderr, NULL); /** Read env like in regress */ if (o.verbose || getenv("EVENT_DEBUG_LOGGING_ALL")) event_enable_debug_logging(EVENT_DBG_ALL); cfg = event_config_new(); #ifdef _WIN32 if (o.iocp) { #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED evthread_use_windows_threads(); event_config_set_num_cpus_hint(cfg, 8); #endif event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP); } #endif base = event_base_new_with_config(cfg); if (!base) { fprintf(stderr, "Couldn't create an event_base: exiting\n"); ret = 1; } event_config_free(cfg); cfg = NULL; /* Create a new evhttp object to handle requests. */ http = evhttp_new(base); if (!http) { fprintf(stderr, "couldn't create evhttp. Exiting.\n"); ret = 1; } /* The /dump URI will dump all requests to stdout and say 200 ok. */ evhttp_set_cb(http, "/dump", dump_request_cb, NULL); /* We want to accept arbitrary requests, so we need to set a "generic" * cb. We can also add callbacks for specific paths. */ evhttp_set_gencb(http, send_document_cb, &o); if (o.unixsock) { #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN struct sockaddr_un addr; if (o.unlink && (unlink(o.unixsock) && errno != ENOENT)) { perror(o.unixsock); ret = 1; goto err; } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, o.unixsock); lev = evconnlistener_new_bind(base, NULL, NULL, LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr *)&addr, sizeof(addr)); if (!lev) { perror("Cannot create listener"); ret = 1; goto err; } handle = evhttp_bind_listener(http, lev); if (!handle) { fprintf(stderr, "couldn't bind to %s. Exiting.\n", o.unixsock); ret = 1; goto err; } #else /* !EVENT__HAVE_STRUCT_SOCKADDR_UN */ fprintf(stderr, "-U is not supported on this platform. Exiting.\n"); ret = 1; goto err; #endif /* EVENT__HAVE_STRUCT_SOCKADDR_UN */ } else { handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", o.port); if (!handle) { fprintf(stderr, "couldn't bind to port %d. Exiting.\n", o.port); ret = 1; goto err; } } if (display_listen_sock(handle)) { ret = 1; goto err; } term = evsignal_new(base, SIGINT, do_term, base); if (!term) goto err; if (event_add(term, NULL)) goto err; event_base_dispatch(base); #ifdef _WIN32 WSACleanup(); #endif err: if (cfg) event_config_free(cfg); if (http) evhttp_free(http); if (term) event_free(term); if (base) event_base_free(base); return ret; } lldpd-1.0.13/libevent/bufferevent_filter.c0000644000076400001440000004313614111362570021234 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * Copyright (c) 2002-2006 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "evconfig-private.h" #include #include "event2/event-config.h" #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #ifdef EVENT__HAVE_STDARG_H #include #endif #ifdef _WIN32 #include #endif #include "event2/util.h" #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/bufferevent_struct.h" #include "event2/event.h" #include "log-internal.h" #include "mm-internal.h" #include "bufferevent-internal.h" #include "util-internal.h" /* prototypes */ static int be_filter_enable(struct bufferevent *, short); static int be_filter_disable(struct bufferevent *, short); static void be_filter_unlink(struct bufferevent *); static void be_filter_destruct(struct bufferevent *); static void be_filter_readcb(struct bufferevent *, void *); static void be_filter_writecb(struct bufferevent *, void *); static void be_filter_eventcb(struct bufferevent *, short, void *); static int be_filter_flush(struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode mode); static int be_filter_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); static void bufferevent_filtered_inbuf_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg); static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf, const struct evbuffer_cb_info *info, void *arg); struct bufferevent_filtered { struct bufferevent_private bev; /** The bufferevent that we read/write filtered data from/to. */ struct bufferevent *underlying; /** A callback on our inbuf to notice somebory removes data */ struct evbuffer_cb_entry *inbuf_cb; /** A callback on our outbuf to notice when somebody adds data */ struct evbuffer_cb_entry *outbuf_cb; /** True iff we have received an EOF callback from the underlying * bufferevent. */ unsigned got_eof; /** Function to free context when we're done. */ void (*free_context)(void *); /** Input filter */ bufferevent_filter_cb process_in; /** Output filter */ bufferevent_filter_cb process_out; /** User-supplied argument to the filters. */ void *context; }; const struct bufferevent_ops bufferevent_ops_filter = { "filter", evutil_offsetof(struct bufferevent_filtered, bev.bev), be_filter_enable, be_filter_disable, be_filter_unlink, be_filter_destruct, bufferevent_generic_adj_timeouts_, be_filter_flush, be_filter_ctrl, }; /* Given a bufferevent that's really the bev filter of a bufferevent_filtered, * return that bufferevent_filtered. Returns NULL otherwise.*/ static inline struct bufferevent_filtered * upcast(struct bufferevent *bev) { struct bufferevent_filtered *bev_f; if (!BEV_IS_FILTER(bev)) return NULL; bev_f = (void*)( ((char*)bev) - evutil_offsetof(struct bufferevent_filtered, bev.bev)); EVUTIL_ASSERT(BEV_IS_FILTER(&bev_f->bev.bev)); return bev_f; } #define downcast(bev_f) (&(bev_f)->bev.bev) /** Return 1 iff bevf's underlying bufferevent's output buffer is at or * over its high watermark such that we should not write to it in a given * flush mode. */ static int be_underlying_writebuf_full(struct bufferevent_filtered *bevf, enum bufferevent_flush_mode state) { struct bufferevent *u = bevf->underlying; return state == BEV_NORMAL && u->wm_write.high && evbuffer_get_length(u->output) >= u->wm_write.high; } /** Return 1 if our input buffer is at or over its high watermark such that we * should not write to it in a given flush mode. */ static int be_readbuf_full(struct bufferevent_filtered *bevf, enum bufferevent_flush_mode state) { struct bufferevent *bufev = downcast(bevf); return state == BEV_NORMAL && bufev->wm_read.high && evbuffer_get_length(bufev->input) >= bufev->wm_read.high; } /* Filter to use when we're created with a NULL filter. */ static enum bufferevent_filter_result be_null_filter(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t lim, enum bufferevent_flush_mode state, void *ctx) { (void)state; if (evbuffer_remove_buffer(src, dst, lim) >= 0) return BEV_OK; else return BEV_ERROR; } struct bufferevent * bufferevent_filter_new(struct bufferevent *underlying, bufferevent_filter_cb input_filter, bufferevent_filter_cb output_filter, int options, void (*free_context)(void *), void *ctx) { struct bufferevent_filtered *bufev_f; int tmp_options = options & ~BEV_OPT_THREADSAFE; if (!underlying) return NULL; if (!input_filter) input_filter = be_null_filter; if (!output_filter) output_filter = be_null_filter; bufev_f = mm_calloc(1, sizeof(struct bufferevent_filtered)); if (!bufev_f) return NULL; if (bufferevent_init_common_(&bufev_f->bev, underlying->ev_base, &bufferevent_ops_filter, tmp_options) < 0) { mm_free(bufev_f); return NULL; } if (options & BEV_OPT_THREADSAFE) { bufferevent_enable_locking_(downcast(bufev_f), NULL); } bufev_f->underlying = underlying; bufev_f->process_in = input_filter; bufev_f->process_out = output_filter; bufev_f->free_context = free_context; bufev_f->context = ctx; bufferevent_setcb(bufev_f->underlying, be_filter_readcb, be_filter_writecb, be_filter_eventcb, bufev_f); bufev_f->inbuf_cb = evbuffer_add_cb(downcast(bufev_f)->input, bufferevent_filtered_inbuf_cb, bufev_f); evbuffer_cb_clear_flags(downcast(bufev_f)->input, bufev_f->inbuf_cb, EVBUFFER_CB_ENABLED); bufev_f->outbuf_cb = evbuffer_add_cb(downcast(bufev_f)->output, bufferevent_filtered_outbuf_cb, bufev_f); bufferevent_init_generic_timeout_cbs_(downcast(bufev_f)); bufferevent_incref_(underlying); bufferevent_enable(underlying, EV_READ|EV_WRITE); bufferevent_suspend_read_(underlying, BEV_SUSPEND_FILT_READ); return downcast(bufev_f); } static void be_filter_unlink(struct bufferevent *bev) { struct bufferevent_filtered *bevf = upcast(bev); EVUTIL_ASSERT(bevf); if (bevf->bev.options & BEV_OPT_CLOSE_ON_FREE) { /* Yes, there is also a decref in bufferevent_decref_. * That decref corresponds to the incref when we set * underlying for the first time. This decref is an * extra one to remove the last reference. */ if (BEV_UPCAST(bevf->underlying)->refcnt < 2) { event_warnx("BEV_OPT_CLOSE_ON_FREE set on an " "bufferevent with too few references"); } else { bufferevent_free(bevf->underlying); } } else { if (bevf->underlying) { if (bevf->underlying->errorcb == be_filter_eventcb) bufferevent_setcb(bevf->underlying, NULL, NULL, NULL, NULL); bufferevent_unsuspend_read_(bevf->underlying, BEV_SUSPEND_FILT_READ); } } } static void be_filter_destruct(struct bufferevent *bev) { struct bufferevent_filtered *bevf = upcast(bev); EVUTIL_ASSERT(bevf); if (bevf->free_context) bevf->free_context(bevf->context); if (bevf->inbuf_cb) evbuffer_remove_cb_entry(bev->input, bevf->inbuf_cb); if (bevf->outbuf_cb) evbuffer_remove_cb_entry(bev->output, bevf->outbuf_cb); } static int be_filter_enable(struct bufferevent *bev, short event) { struct bufferevent_filtered *bevf = upcast(bev); if (event & EV_WRITE) BEV_RESET_GENERIC_WRITE_TIMEOUT(bev); if (event & EV_READ) { BEV_RESET_GENERIC_READ_TIMEOUT(bev); bufferevent_unsuspend_read_(bevf->underlying, BEV_SUSPEND_FILT_READ); } return 0; } static int be_filter_disable(struct bufferevent *bev, short event) { struct bufferevent_filtered *bevf = upcast(bev); if (event & EV_WRITE) BEV_DEL_GENERIC_WRITE_TIMEOUT(bev); if (event & EV_READ) { BEV_DEL_GENERIC_READ_TIMEOUT(bev); bufferevent_suspend_read_(bevf->underlying, BEV_SUSPEND_FILT_READ); } return 0; } static enum bufferevent_filter_result be_filter_process_input(struct bufferevent_filtered *bevf, enum bufferevent_flush_mode state, int *processed_out) { enum bufferevent_filter_result res; struct bufferevent *bev = downcast(bevf); if (state == BEV_NORMAL) { /* If we're in 'normal' mode, don't urge data on the filter * unless we're reading data and under our high-water mark.*/ if (!(bev->enabled & EV_READ) || be_readbuf_full(bevf, state)) return BEV_OK; } do { ev_ssize_t limit = -1; if (state == BEV_NORMAL && bev->wm_read.high) limit = bev->wm_read.high - evbuffer_get_length(bev->input); res = bevf->process_in(bevf->underlying->input, bev->input, limit, state, bevf->context); if (res == BEV_OK) *processed_out = 1; } while (res == BEV_OK && (bev->enabled & EV_READ) && evbuffer_get_length(bevf->underlying->input) && !be_readbuf_full(bevf, state)); if (*processed_out) BEV_RESET_GENERIC_READ_TIMEOUT(bev); return res; } static enum bufferevent_filter_result be_filter_process_output(struct bufferevent_filtered *bevf, enum bufferevent_flush_mode state, int *processed_out) { /* Requires references and lock: might call writecb */ enum bufferevent_filter_result res = BEV_OK; struct bufferevent *bufev = downcast(bevf); int again = 0; if (state == BEV_NORMAL) { /* If we're in 'normal' mode, don't urge data on the * filter unless we're writing data, and the underlying * bufferevent is accepting data, and we have data to * give the filter. If we're in 'flush' or 'finish', * call the filter no matter what. */ if (!(bufev->enabled & EV_WRITE) || be_underlying_writebuf_full(bevf, state) || !evbuffer_get_length(bufev->output)) return BEV_OK; } /* disable the callback that calls this function when the user adds to the output buffer. */ evbuffer_cb_clear_flags(bufev->output, bevf->outbuf_cb, EVBUFFER_CB_ENABLED); do { int processed = 0; again = 0; do { ev_ssize_t limit = -1; if (state == BEV_NORMAL && bevf->underlying->wm_write.high) limit = bevf->underlying->wm_write.high - evbuffer_get_length(bevf->underlying->output); res = bevf->process_out(downcast(bevf)->output, bevf->underlying->output, limit, state, bevf->context); if (res == BEV_OK) processed = *processed_out = 1; } while (/* Stop if the filter wasn't successful...*/ res == BEV_OK && /* Or if we aren't writing any more. */ (bufev->enabled & EV_WRITE) && /* Of if we have nothing more to write and we are * not flushing. */ evbuffer_get_length(bufev->output) && /* Or if we have filled the underlying output buffer. */ !be_underlying_writebuf_full(bevf,state)); if (processed) { /* call the write callback.*/ bufferevent_trigger_nolock_(bufev, EV_WRITE, 0); if (res == BEV_OK && (bufev->enabled & EV_WRITE) && evbuffer_get_length(bufev->output) && !be_underlying_writebuf_full(bevf, state)) { again = 1; } } } while (again); /* reenable the outbuf_cb */ evbuffer_cb_set_flags(bufev->output,bevf->outbuf_cb, EVBUFFER_CB_ENABLED); if (*processed_out) BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev); return res; } /* Called when the size of our outbuf changes. */ static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent_filtered *bevf = arg; struct bufferevent *bev = downcast(bevf); if (cbinfo->n_added) { int processed_any = 0; /* Somebody added more data to the output buffer. Try to * process it, if we should. */ bufferevent_incref_and_lock_(bev); be_filter_process_output(bevf, BEV_NORMAL, &processed_any); bufferevent_decref_and_unlock_(bev); } } static void be_filter_read_nolock_(struct bufferevent *underlying, void *me_) { struct bufferevent_filtered *bevf = me_; enum bufferevent_filter_result res; enum bufferevent_flush_mode state; struct bufferevent *bufev = downcast(bevf); struct bufferevent_private *bufev_private = BEV_UPCAST(bufev); int processed_any = 0; // It's possible our refcount is 0 at this point if another thread free'd our filterevent EVUTIL_ASSERT(bufev_private->refcnt >= 0); // If our refcount is > 0 if (bufev_private->refcnt > 0) { if (bevf->got_eof) state = BEV_FINISHED; else state = BEV_NORMAL; /* XXXX use return value */ res = be_filter_process_input(bevf, state, &processed_any); (void)res; /* XXX This should be in process_input, not here. There are * other places that can call process-input, and they should * force readcb calls as needed. */ if (processed_any) { bufferevent_trigger_nolock_(bufev, EV_READ, 0); if (evbuffer_get_length(underlying->input) > 0 && be_readbuf_full(bevf, state)) { /* data left in underlying buffer and filter input buffer * hit its read high watermark. * Schedule callback to avoid data gets stuck in underlying * input buffer. */ evbuffer_cb_set_flags(bufev->input, bevf->inbuf_cb, EVBUFFER_CB_ENABLED); } } } } /* Called when the size of our inbuf changes. */ static void bufferevent_filtered_inbuf_cb(struct evbuffer *buf, const struct evbuffer_cb_info *cbinfo, void *arg) { struct bufferevent_filtered *bevf = arg; enum bufferevent_flush_mode state; struct bufferevent *bev = downcast(bevf); BEV_LOCK(bev); if (bevf->got_eof) state = BEV_FINISHED; else state = BEV_NORMAL; if (!be_readbuf_full(bevf, state)) { /* opportunity to read data which was left in underlying * input buffer because filter input buffer hit read * high watermark. */ evbuffer_cb_clear_flags(bev->input, bevf->inbuf_cb, EVBUFFER_CB_ENABLED); if (evbuffer_get_length(bevf->underlying->input) > 0) be_filter_read_nolock_(bevf->underlying, bevf); } BEV_UNLOCK(bev); } /* Called when the underlying socket has read. */ static void be_filter_readcb(struct bufferevent *underlying, void *me_) { struct bufferevent_filtered *bevf = me_; struct bufferevent *bev = downcast(bevf); BEV_LOCK(bev); be_filter_read_nolock_(underlying, me_); BEV_UNLOCK(bev); } /* Called when the underlying socket has drained enough that we can write to it. */ static void be_filter_writecb(struct bufferevent *underlying, void *me_) { struct bufferevent_filtered *bevf = me_; struct bufferevent *bev = downcast(bevf); struct bufferevent_private *bufev_private = BEV_UPCAST(bev); int processed_any = 0; BEV_LOCK(bev); // It's possible our refcount is 0 at this point if another thread free'd our filterevent EVUTIL_ASSERT(bufev_private->refcnt >= 0); // If our refcount is > 0 if (bufev_private->refcnt > 0) { be_filter_process_output(bevf, BEV_NORMAL, &processed_any); } BEV_UNLOCK(bev); } /* Called when the underlying socket has given us an error */ static void be_filter_eventcb(struct bufferevent *underlying, short what, void *me_) { struct bufferevent_filtered *bevf = me_; struct bufferevent *bev = downcast(bevf); struct bufferevent_private *bufev_private = BEV_UPCAST(bev); BEV_LOCK(bev); // It's possible our refcount is 0 at this point if another thread free'd our filterevent EVUTIL_ASSERT(bufev_private->refcnt >= 0); // If our refcount is > 0 if (bufev_private->refcnt > 0) { /* All we can really to is tell our own eventcb. */ bufferevent_run_eventcb_(bev, what, 0); } BEV_UNLOCK(bev); } static int be_filter_flush(struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode mode) { struct bufferevent_filtered *bevf = upcast(bufev); int processed_any = 0; EVUTIL_ASSERT(bevf); bufferevent_incref_and_lock_(bufev); if (iotype & EV_READ) { be_filter_process_input(bevf, mode, &processed_any); } if (iotype & EV_WRITE) { be_filter_process_output(bevf, mode, &processed_any); } /* XXX check the return value? */ /* XXX does this want to recursively call lower-level flushes? */ bufferevent_flush(bevf->underlying, iotype, mode); bufferevent_decref_and_unlock_(bufev); return processed_any; } static int be_filter_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data) { struct bufferevent_filtered *bevf; switch (op) { case BEV_CTRL_GET_UNDERLYING: bevf = upcast(bev); data->ptr = bevf->underlying; return 0; case BEV_CTRL_SET_FD: case BEV_CTRL_GET_FD: bevf = upcast(bev); if (bevf->underlying && bevf->underlying->be_ops && bevf->underlying->be_ops->ctrl) { return (bevf->underlying->be_ops->ctrl)(bevf->underlying, op, data); } EVUTIL_FALLTHROUGH; case BEV_CTRL_CANCEL_ALL: EVUTIL_FALLTHROUGH; default: return -1; } return -1; } lldpd-1.0.13/libevent/event_tagging.c0000644000076400001440000003461214111362570020174 0ustar00bernatusers00000000000000/* * Copyright (c) 2003-2009 Niels Provos * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/event-config.h" #include "evconfig-private.h" #ifdef EVENT__HAVE_SYS_TYPES_H #include #endif #ifdef EVENT__HAVE_SYS_PARAM_H #include #endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #undef WIN32_LEAN_AND_MEAN #endif #ifdef EVENT__HAVE_SYS_IOCTL_H #include #endif #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #include #include #include #ifndef _WIN32 #include #endif #ifdef EVENT__HAVE_UNISTD_H #include #endif #include #include "event2/event.h" #include "event2/tag.h" #include "event2/buffer.h" #include "log-internal.h" #include "mm-internal.h" #include "util-internal.h" /* Here's our wire format: Stream = TaggedData* TaggedData = Tag Length Data where the integer value of 'Length' is the length of 'data'. Tag = HByte* LByte where HByte is a byte with the high bit set, and LByte is a byte with the high bit clear. The integer value of the tag is taken by concatenating the lower 7 bits from all the tags. So for example, the tag 0x66 is encoded as [66], whereas the tag 0x166 is encoded as [82 66] Length = Integer Integer = NNibbles Nibble* Padding? where NNibbles is a 4-bit value encoding the number of nibbles-1, and each Nibble is 4 bits worth of encoded integer, in big-endian order. If the total encoded integer size is an odd number of nibbles, a final padding nibble with value 0 is appended. */ EVENT2_EXPORT_SYMBOL int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf); EVENT2_EXPORT_SYMBOL int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf); EVENT2_EXPORT_SYMBOL int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag); EVENT2_EXPORT_SYMBOL int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf); void evtag_init(void) { } /* * We encode integers by nibbles; the first nibble contains the number * of significant nibbles - 1; this allows us to encode up to 64-bit * integers. This function is byte-order independent. * * @param number a 32-bit unsigned integer to encode * @param data a pointer to where the data should be written. Must * have at least 5 bytes free. * @return the number of bytes written into data. */ #define ENCODE_INT_INTERNAL(data, number) do { \ int off = 1, nibbles = 0; \ \ memset(data, 0, sizeof(number)+1); \ while (number) { \ if (off & 0x1) \ data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); \ else \ data[off/2] = (data[off/2] & 0x0f) | \ ((number & 0x0f) << 4); \ number >>= 4; \ off++; \ } \ \ if (off > 2) \ nibbles = off - 2; \ \ /* Off - 1 is the number of encoded nibbles */ \ data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); \ \ return ((off + 1) / 2); \ } while (0) static inline int encode_int_internal(ev_uint8_t *data, ev_uint32_t number) { ENCODE_INT_INTERNAL(data, number); } static inline int encode_int64_internal(ev_uint8_t *data, ev_uint64_t number) { ENCODE_INT_INTERNAL(data, number); } void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number) { ev_uint8_t data[5]; int len = encode_int_internal(data, number); evbuffer_add(evbuf, data, len); } void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number) { ev_uint8_t data[9]; int len = encode_int64_internal(data, number); evbuffer_add(evbuf, data, len); } /* * Support variable length encoding of tags; we use the high bit in each * octet as a continuation signal. */ int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag) { int bytes = 0; ev_uint8_t data[5]; memset(data, 0, sizeof(data)); do { ev_uint8_t lower = tag & 0x7f; tag >>= 7; if (tag) lower |= 0x80; data[bytes++] = lower; } while (tag); if (evbuf != NULL) evbuffer_add(evbuf, data, bytes); return (bytes); } static int decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain) { ev_uint32_t number = 0; size_t len = evbuffer_get_length(evbuf); ev_uint8_t *data; size_t count = 0; int shift = 0, done = 0; /* * the encoding of a number is at most one byte more than its * storage size. however, it may also be much smaller. */ data = evbuffer_pullup( evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1); if (!data) return (-1); while (count++ < len) { ev_uint8_t lower = *data++; if (shift >= 28) { /* Make sure it fits into 32 bits */ if (shift > 28) return (-1); if ((lower & 0x7f) > 15) return (-1); } number |= (lower & (unsigned)0x7f) << shift; shift += 7; if (!(lower & 0x80)) { done = 1; break; } } if (!done) return (-1); if (dodrain) evbuffer_drain(evbuf, count); if (ptag != NULL) *ptag = number; return count > INT_MAX ? INT_MAX : (int)(count); } int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf) { return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */)); } /* * Marshal a data type, the general format is as follows: * * tag number: one byte; length: var bytes; payload: var bytes */ void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, ev_uint32_t len) { evtag_encode_tag(evbuf, tag); evtag_encode_int(evbuf, len); evbuffer_add(evbuf, (void *)data, len); } void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag, struct evbuffer *data) { evtag_encode_tag(evbuf, tag); /* XXX support more than UINT32_MAX data */ evtag_encode_int(evbuf, (ev_uint32_t)evbuffer_get_length(data)); evbuffer_add_buffer(evbuf, data); } /* Marshaling for integers */ void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer) { ev_uint8_t data[5]; int len = encode_int_internal(data, integer); evtag_encode_tag(evbuf, tag); evtag_encode_int(evbuf, len); evbuffer_add(evbuf, data, len); } void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint64_t integer) { ev_uint8_t data[9]; int len = encode_int64_internal(data, integer); evtag_encode_tag(evbuf, tag); evtag_encode_int(evbuf, len); evbuffer_add(evbuf, data, len); } void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string) { /* TODO support strings longer than UINT32_MAX ? */ evtag_marshal(buf, tag, string, (ev_uint32_t)strlen(string)); } void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv) { ev_uint8_t data[10]; int len = encode_int_internal(data, tv->tv_sec); len += encode_int_internal(data + len, tv->tv_usec); evtag_marshal(evbuf, tag, data, len); } #define DECODE_INT_INTERNAL(number, maxnibbles, pnumber, evbuf, offset) \ do { \ ev_uint8_t *data; \ ev_ssize_t len = evbuffer_get_length(evbuf) - offset; \ int nibbles = 0; \ \ if (len <= 0) \ return (-1); \ \ /* XXX(niels): faster? */ \ data = evbuffer_pullup(evbuf, offset + 1) + offset; \ if (!data) \ return (-1); \ \ nibbles = ((data[0] & 0xf0) >> 4) + 1; \ if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len) \ return (-1); \ len = (nibbles >> 1) + 1; \ \ data = evbuffer_pullup(evbuf, offset + len) + offset; \ if (!data) \ return (-1); \ \ while (nibbles > 0) { \ number <<= 4; \ if (nibbles & 0x1) \ number |= data[nibbles >> 1] & 0x0f; \ else \ number |= (data[nibbles >> 1] & 0xf0) >> 4; \ nibbles--; \ } \ \ *pnumber = number; \ \ return (int)(len); \ } while (0) /* Internal: decode an integer from an evbuffer, without draining it. * Only integers up to 32-bits are supported. * * @param evbuf the buffer to read from * @param offset an index into the buffer at which we should start reading. * @param pnumber a pointer to receive the integer. * @return The length of the number as encoded, or -1 on error. */ static int decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset) { ev_uint32_t number = 0; DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset); } static int decode_int64_internal(ev_uint64_t *pnumber, struct evbuffer *evbuf, int offset) { ev_uint64_t number = 0; DECODE_INT_INTERNAL(number, 16, pnumber, evbuf, offset); } int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf) { int res = decode_int_internal(pnumber, evbuf, 0); if (res != -1) evbuffer_drain(evbuf, res); return (res == -1 ? -1 : 0); } int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf) { int res = decode_int64_internal(pnumber, evbuf, 0); if (res != -1) evbuffer_drain(evbuf, res); return (res == -1 ? -1 : 0); } int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag) { return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */)); } int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength) { int res, len; len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); if (len == -1) return (-1); res = decode_int_internal(plength, evbuf, len); if (res == -1) return (-1); *plength += res + len; return (0); } int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength) { int res, len; len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); if (len == -1) return (-1); res = decode_int_internal(plength, evbuf, len); if (res == -1) return (-1); return (0); } /* just unmarshals the header and returns the length of the remaining data */ int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag) { ev_uint32_t len; if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1) return (-1); if (evtag_decode_int(&len, evbuf) == -1) return (-1); if (evbuffer_get_length(evbuf) < len) return (-1); return (len); } int evtag_consume(struct evbuffer *evbuf) { int len; if ((len = evtag_unmarshal_header(evbuf, NULL)) == -1) return (-1); evbuffer_drain(evbuf, len); return (0); } /* Reads the data type from an event buffer */ int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst) { int len; if ((len = evtag_unmarshal_header(src, ptag)) == -1) return (-1); if (evbuffer_add(dst, evbuffer_pullup(src, len), len) == -1) return (-1); evbuffer_drain(src, len); return (len); } /* Marshaling for integers */ int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint32_t *pinteger) { ev_uint32_t tag; ev_uint32_t len; int result; if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) return (-1); if (need_tag != tag) return (-1); if (evtag_decode_int(&len, evbuf) == -1) return (-1); if (evbuffer_get_length(evbuf) < len) return (-1); result = decode_int_internal(pinteger, evbuf, 0); evbuffer_drain(evbuf, len); if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/ return (-1); else return result; } int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint64_t *pinteger) { ev_uint32_t tag; ev_uint32_t len; int result; if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) return (-1); if (need_tag != tag) return (-1); if (evtag_decode_int(&len, evbuf) == -1) return (-1); if (evbuffer_get_length(evbuf) < len) return (-1); result = decode_int64_internal(pinteger, evbuf, 0); evbuffer_drain(evbuf, len); if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/ return (-1); else return result; } /* Unmarshal a fixed length tag */ int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, size_t len) { ev_uint32_t tag; int tag_len; /* Now unmarshal a tag and check that it matches the tag we want */ if ((tag_len = evtag_unmarshal_header(src, &tag)) < 0 || tag != need_tag) return (-1); if ((size_t)tag_len != len) return (-1); evbuffer_remove(src, data, len); return (0); } int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring) { ev_uint32_t tag; int tag_len; if ((tag_len = evtag_unmarshal_header(evbuf, &tag)) == -1 || tag != need_tag) return (-1); *pstring = mm_malloc(tag_len + 1); if (*pstring == NULL) { event_warn("%s: malloc", __func__); return -1; } evbuffer_remove(evbuf, *pstring, tag_len); (*pstring)[tag_len] = '\0'; return (0); } int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv) { ev_uint32_t tag; ev_uint32_t integer; int len, offset, offset2; int result = -1; if ((len = evtag_unmarshal_header(evbuf, &tag)) == -1) return (-1); if (tag != need_tag) goto done; if ((offset = decode_int_internal(&integer, evbuf, 0)) == -1) goto done; ptv->tv_sec = integer; if ((offset2 = decode_int_internal(&integer, evbuf, offset)) == -1) goto done; ptv->tv_usec = integer; if (offset + offset2 > len) /* XXX Should this be != instead of > ? */ goto done; result = 0; done: evbuffer_drain(evbuf, len); return result; } lldpd-1.0.13/libevent/epolltable-internal.h0000644000076400001440000012062014111362570021310 0ustar00bernatusers00000000000000/* * Copyright (c) 2000-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef EPOLLTABLE_INTERNAL_H_INCLUDED_ #define EPOLLTABLE_INTERNAL_H_INCLUDED_ /* Here are the values we're masking off to decide what operations to do. Note that since EV_READ|EV_WRITE. Note also that this table is a little sparse, since ADD+DEL is nonsensical ("xxx" in the list below.) Note also that we are shifting old_events by only 5 bits, since EV_READ is 2 and EV_WRITE is 4. The table was auto-generated with a python script, according to this pseudocode:[*0] If either the read or the write change is add+del: This is impossible; Set op==-1, events=0. Else, if either the read or the write change is add: Set events to 0. If the read change is add, or (the read change is not del, and ev_read is in old_events): Add EPOLLIN to events. If the write change is add, or (the write change is not del, and ev_write is in old_events): Add EPOLLOUT to events. If old_events is set: Set op to EPOLL_CTL_MOD [*1,*2] Else: Set op to EPOLL_CTL_ADD [*3] Else, if the read or the write change is del: Set op to EPOLL_CTL_DEL. If the read change is del: If the write change is del: Set events to EPOLLIN|EPOLLOUT Else if ev_write is in old_events: Set events to EPOLLOUT Set op to EPOLL_CTL_MOD Else Set events to EPOLLIN Else: {The write change is del.} If ev_read is in old_events: Set events to EPOLLIN Set op to EPOLL_CTL_MOD Else: Set the events to EPOLLOUT Else: There is no read or write change; set op to 0 and events to 0. The logic is a little tricky, since we had no events set on the fd before, we need to set op="ADD" and set events=the events we want to add. If we had any events set on the fd before, and we want any events to remain on the fd, we need to say op="MOD" and set events=the events we want to remain. But if we want to delete the last event, we say op="DEL" and set events=(any non-null pointer). [*0] Actually, the Python script has gotten a bit more complicated, to support EPOLLRDHUP. [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was closed and a new file was opened with the same fd. If so, we'll retry with ADD. [*2] We can't replace this with a no-op even if old_events is the same as the new events: if the file was closed and reopened, we need to retry with an ADD. (We do a MOD in this case since "no change" is more common than "close and reopen", so we'll usually wind up doing 1 syscalls instead of 2.) [*3] This ADD is only a guess. There is a fun Linux kernel issue where if you have two fds for the same file (via dup) and you ADD one to an epfd, then close it, then re-create it with the same fd (via dup2 or an unlucky dup), then try to ADD it again, you'll get an EEXIST, since the struct epitem is not actually removed from the struct eventpoll until the file itself is closed. EV_CHANGE_ADD==1 EV_CHANGE_DEL==2 EV_READ ==2 EV_WRITE ==4 EV_CLOSED ==0x80 Bit 0: close change is add Bit 1: close change is del Bit 2: read change is add Bit 3: read change is del Bit 4: write change is add Bit 5: write change is del Bit 6: old events had EV_READ Bit 7: old events had EV_WRITE Bit 8: old events had EV_CLOSED */ #define EPOLL_OP_TABLE_INDEX(c) \ ( (((c)->close_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \ (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \ (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 4) | \ (((c)->old_events&(EV_READ|EV_WRITE)) << 5) | \ (((c)->old_events&(EV_CLOSED)) << 1) \ ) #if EV_READ != 2 || EV_WRITE != 4 || EV_CLOSED != 0x80 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2 #error "Libevent's internals changed! Regenerate the op_table in epolltable-internal.h" #endif static const struct operation { int events; int op; } epoll_op_table[] = { /* old= 0, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= 0, write: 0, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write: 0, read: 0, close:del */ { EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= 0, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= 0, write: 0, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add, close:del */ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= 0, write: 0, read:del, close: 0 */ { EPOLLIN, EPOLL_CTL_DEL }, /* old= 0, write: 0, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:del, close:del */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= 0, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= 0, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= 0, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= 0, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= 0, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= 0, write:add, read: 0, close: 0 */ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= 0, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:add, close:xxx */ { 0, 255 }, /* old= 0, write:add, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del, close:xxx */ { 0, 255 }, /* old= 0, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= 0, write:add, read:xxx, close:add */ { 0, 255 }, /* old= 0, write:add, read:xxx, close:del */ { 0, 255 }, /* old= 0, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= 0, write:del, read: 0, close: 0 */ { EPOLLOUT, EPOLL_CTL_DEL }, /* old= 0, write:del, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:del, read: 0, close:del */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= 0, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= 0, write:del, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add, close:xxx */ { 0, 255 }, /* old= 0, write:del, read:del, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL }, /* old= 0, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_ADD }, /* old= 0, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= 0, write:del, read:del, close:xxx */ { 0, 255 }, /* old= 0, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= 0, write:del, read:xxx, close:add */ { 0, 255 }, /* old= 0, write:del, read:xxx, close:del */ { 0, 255 }, /* old= 0, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= 0, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= 0, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= 0, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= 0, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= 0, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= 0, write:xxx, read:add, close:add */ { 0, 255 }, /* old= 0, write:xxx, read:add, close:del */ { 0, 255 }, /* old= 0, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= 0, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= 0, write:xxx, read:del, close:add */ { 0, 255 }, /* old= 0, write:xxx, read:del, close:del */ { 0, 255 }, /* old= 0, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= 0, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= 0, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= 0, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= 0, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= r, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= r, write: 0, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write: 0, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= r, write: 0, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= r, write: 0, read:del, close: 0 */ { EPOLLIN, EPOLL_CTL_DEL }, /* old= r, write: 0, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write: 0, read:del, close:del */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= r, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= r, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= r, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= r, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= r, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= r, write:add, read: 0, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:add, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= r, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:add, close:xxx */ { 0, 255 }, /* old= r, write:add, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:del, close:xxx */ { 0, 255 }, /* old= r, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= r, write:add, read:xxx, close:add */ { 0, 255 }, /* old= r, write:add, read:xxx, close:del */ { 0, 255 }, /* old= r, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= r, write:del, read: 0, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= r, write:del, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read:add, close:xxx */ { 0, 255 }, /* old= r, write:del, read:del, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL }, /* old= r, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= r, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= r, write:del, read:del, close:xxx */ { 0, 255 }, /* old= r, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= r, write:del, read:xxx, close:add */ { 0, 255 }, /* old= r, write:del, read:xxx, close:del */ { 0, 255 }, /* old= r, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= r, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= r, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= r, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= r, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= r, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= r, write:xxx, read:add, close:add */ { 0, 255 }, /* old= r, write:xxx, read:add, close:del */ { 0, 255 }, /* old= r, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= r, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= r, write:xxx, read:del, close:add */ { 0, 255 }, /* old= r, write:xxx, read:del, close:del */ { 0, 255 }, /* old= r, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= r, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= r, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= r, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= r, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= w, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= w, write: 0, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write: 0, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= w, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write: 0, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= w, write: 0, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= w, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= w, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= w, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= w, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= w, write:add, read: 0, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= w, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:add, close:xxx */ { 0, 255 }, /* old= w, write:add, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:del, close:xxx */ { 0, 255 }, /* old= w, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= w, write:add, read:xxx, close:add */ { 0, 255 }, /* old= w, write:add, read:xxx, close:del */ { 0, 255 }, /* old= w, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= w, write:del, read: 0, close: 0 */ { EPOLLOUT, EPOLL_CTL_DEL }, /* old= w, write:del, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:del, read: 0, close:del */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= w, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= w, write:del, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= w, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= w, write:del, read:add, close:xxx */ { 0, 255 }, /* old= w, write:del, read:del, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL }, /* old= w, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= w, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= w, write:del, read:del, close:xxx */ { 0, 255 }, /* old= w, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= w, write:del, read:xxx, close:add */ { 0, 255 }, /* old= w, write:del, read:xxx, close:del */ { 0, 255 }, /* old= w, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= w, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= w, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= w, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= w, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= w, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= w, write:xxx, read:add, close:add */ { 0, 255 }, /* old= w, write:xxx, read:add, close:del */ { 0, 255 }, /* old= w, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= w, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= w, write:xxx, read:del, close:add */ { 0, 255 }, /* old= w, write:xxx, read:del, close:del */ { 0, 255 }, /* old= w, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= w, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= w, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= w, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= w, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= rw, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= rw, write: 0, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write: 0, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= rw, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= rw, write: 0, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= rw, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= rw, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= rw, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= rw, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= rw, write:add, read: 0, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:add, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= rw, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read:add, close:xxx */ { 0, 255 }, /* old= rw, write:add, read:del, close: 0 */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= rw, write:add, read:del, close:xxx */ { 0, 255 }, /* old= rw, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= rw, write:add, read:xxx, close:add */ { 0, 255 }, /* old= rw, write:add, read:xxx, close:del */ { 0, 255 }, /* old= rw, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= rw, write:del, read: 0, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= rw, write:del, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:del, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= rw, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= rw, write:del, read:add, close: 0 */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= rw, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= rw, write:del, read:add, close:xxx */ { 0, 255 }, /* old= rw, write:del, read:del, close: 0 */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL }, /* old= rw, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= rw, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= rw, write:del, read:del, close:xxx */ { 0, 255 }, /* old= rw, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= rw, write:del, read:xxx, close:add */ { 0, 255 }, /* old= rw, write:del, read:xxx, close:del */ { 0, 255 }, /* old= rw, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= rw, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= rw, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= rw, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= rw, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= rw, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= rw, write:xxx, read:add, close:add */ { 0, 255 }, /* old= rw, write:xxx, read:add, close:del */ { 0, 255 }, /* old= rw, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= rw, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= rw, write:xxx, read:del, close:add */ { 0, 255 }, /* old= rw, write:xxx, read:del, close:del */ { 0, 255 }, /* old= rw, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= rw, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= rw, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= rw, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= rw, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= c, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= c, write: 0, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write: 0, read: 0, close:del */ { EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= c, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= c, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write: 0, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write: 0, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= c, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= c, write: 0, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write: 0, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write: 0, read:del, close:del */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= c, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= c, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= c, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= c, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= c, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= c, write:add, read: 0, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= c, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= c, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= c, write:add, read:add, close:xxx */ { 0, 255 }, /* old= c, write:add, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= c, write:add, read:del, close:xxx */ { 0, 255 }, /* old= c, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= c, write:add, read:xxx, close:add */ { 0, 255 }, /* old= c, write:add, read:xxx, close:del */ { 0, 255 }, /* old= c, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= c, write:del, read: 0, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read: 0, close:del */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= c, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= c, write:del, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= c, write:del, read:add, close:xxx */ { 0, 255 }, /* old= c, write:del, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= c, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= c, write:del, read:del, close:xxx */ { 0, 255 }, /* old= c, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= c, write:del, read:xxx, close:add */ { 0, 255 }, /* old= c, write:del, read:xxx, close:del */ { 0, 255 }, /* old= c, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= c, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= c, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= c, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= c, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= c, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= c, write:xxx, read:add, close:add */ { 0, 255 }, /* old= c, write:xxx, read:add, close:del */ { 0, 255 }, /* old= c, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= c, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= c, write:xxx, read:del, close:add */ { 0, 255 }, /* old= c, write:xxx, read:del, close:del */ { 0, 255 }, /* old= c, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= c, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= c, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= c, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= c, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= cr, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= cr, write: 0, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write: 0, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= cr, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= cr, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write: 0, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write: 0, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= cr, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= cr, write: 0, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write: 0, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write: 0, read:del, close:del */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= cr, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= cr, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= cr, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= cr, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= cr, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= cr, write:add, read: 0, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= cr, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= cr, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= cr, write:add, read:add, close:xxx */ { 0, 255 }, /* old= cr, write:add, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= cr, write:add, read:del, close:xxx */ { 0, 255 }, /* old= cr, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= cr, write:add, read:xxx, close:add */ { 0, 255 }, /* old= cr, write:add, read:xxx, close:del */ { 0, 255 }, /* old= cr, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= cr, write:del, read: 0, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= cr, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= cr, write:del, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= cr, write:del, read:add, close:xxx */ { 0, 255 }, /* old= cr, write:del, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cr, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= cr, write:del, read:del, close:xxx */ { 0, 255 }, /* old= cr, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= cr, write:del, read:xxx, close:add */ { 0, 255 }, /* old= cr, write:del, read:xxx, close:del */ { 0, 255 }, /* old= cr, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= cr, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= cr, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= cr, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= cr, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= cr, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= cr, write:xxx, read:add, close:add */ { 0, 255 }, /* old= cr, write:xxx, read:add, close:del */ { 0, 255 }, /* old= cr, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= cr, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= cr, write:xxx, read:del, close:add */ { 0, 255 }, /* old= cr, write:xxx, read:del, close:del */ { 0, 255 }, /* old= cr, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= cr, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= cr, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= cr, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= cr, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old= cw, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old= cw, write: 0, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write: 0, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old= cw, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:add, close:xxx */ { 0, 255 }, /* old= cw, write: 0, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write: 0, read:del, close:xxx */ { 0, 255 }, /* old= cw, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old= cw, write: 0, read:xxx, close:add */ { 0, 255 }, /* old= cw, write: 0, read:xxx, close:del */ { 0, 255 }, /* old= cw, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old= cw, write:add, read: 0, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read: 0, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read: 0, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write:add, read: 0, close:xxx */ { 0, 255 }, /* old= cw, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write:add, read:add, close:xxx */ { 0, 255 }, /* old= cw, write:add, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= cw, write:add, read:del, close:xxx */ { 0, 255 }, /* old= cw, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old= cw, write:add, read:xxx, close:add */ { 0, 255 }, /* old= cw, write:add, read:xxx, close:del */ { 0, 255 }, /* old= cw, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old= cw, write:del, read: 0, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read: 0, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read: 0, close:del */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= cw, write:del, read: 0, close:xxx */ { 0, 255 }, /* old= cw, write:del, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old= cw, write:del, read:add, close:xxx */ { 0, 255 }, /* old= cw, write:del, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old= cw, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old= cw, write:del, read:del, close:xxx */ { 0, 255 }, /* old= cw, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old= cw, write:del, read:xxx, close:add */ { 0, 255 }, /* old= cw, write:del, read:xxx, close:del */ { 0, 255 }, /* old= cw, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old= cw, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old= cw, write:xxx, read: 0, close:add */ { 0, 255 }, /* old= cw, write:xxx, read: 0, close:del */ { 0, 255 }, /* old= cw, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old= cw, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old= cw, write:xxx, read:add, close:add */ { 0, 255 }, /* old= cw, write:xxx, read:add, close:del */ { 0, 255 }, /* old= cw, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old= cw, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old= cw, write:xxx, read:del, close:add */ { 0, 255 }, /* old= cw, write:xxx, read:del, close:del */ { 0, 255 }, /* old= cw, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old= cw, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old= cw, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old= cw, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old= cw, write:xxx, read:xxx, close:xxx */ { 0, 255 }, /* old=crw, write: 0, read: 0, close: 0 */ { 0, 0 }, /* old=crw, write: 0, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write: 0, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write: 0, read: 0, close:xxx */ { 0, 255 }, /* old=crw, write: 0, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:add, close:xxx */ { 0, 255 }, /* old=crw, write: 0, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write: 0, read:del, close:xxx */ { 0, 255 }, /* old=crw, write: 0, read:xxx, close: 0 */ { 0, 255 }, /* old=crw, write: 0, read:xxx, close:add */ { 0, 255 }, /* old=crw, write: 0, read:xxx, close:del */ { 0, 255 }, /* old=crw, write: 0, read:xxx, close:xxx */ { 0, 255 }, /* old=crw, write:add, read: 0, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read: 0, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read: 0, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write:add, read: 0, close:xxx */ { 0, 255 }, /* old=crw, write:add, read:add, close: 0 */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read:add, close:add */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read:add, close:del */ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write:add, read:add, close:xxx */ { 0, 255 }, /* old=crw, write:add, read:del, close: 0 */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read:del, close:add */ { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:add, read:del, close:del */ { EPOLLOUT, EPOLL_CTL_MOD }, /* old=crw, write:add, read:del, close:xxx */ { 0, 255 }, /* old=crw, write:add, read:xxx, close: 0 */ { 0, 255 }, /* old=crw, write:add, read:xxx, close:add */ { 0, 255 }, /* old=crw, write:add, read:xxx, close:del */ { 0, 255 }, /* old=crw, write:add, read:xxx, close:xxx */ { 0, 255 }, /* old=crw, write:del, read: 0, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read: 0, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read: 0, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old=crw, write:del, read: 0, close:xxx */ { 0, 255 }, /* old=crw, write:del, read:add, close: 0 */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read:add, close:add */ { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read:add, close:del */ { EPOLLIN, EPOLL_CTL_MOD }, /* old=crw, write:del, read:add, close:xxx */ { 0, 255 }, /* old=crw, write:del, read:del, close: 0 */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read:del, close:add */ { EPOLLRDHUP, EPOLL_CTL_MOD }, /* old=crw, write:del, read:del, close:del */ { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL }, /* old=crw, write:del, read:del, close:xxx */ { 0, 255 }, /* old=crw, write:del, read:xxx, close: 0 */ { 0, 255 }, /* old=crw, write:del, read:xxx, close:add */ { 0, 255 }, /* old=crw, write:del, read:xxx, close:del */ { 0, 255 }, /* old=crw, write:del, read:xxx, close:xxx */ { 0, 255 }, /* old=crw, write:xxx, read: 0, close: 0 */ { 0, 255 }, /* old=crw, write:xxx, read: 0, close:add */ { 0, 255 }, /* old=crw, write:xxx, read: 0, close:del */ { 0, 255 }, /* old=crw, write:xxx, read: 0, close:xxx */ { 0, 255 }, /* old=crw, write:xxx, read:add, close: 0 */ { 0, 255 }, /* old=crw, write:xxx, read:add, close:add */ { 0, 255 }, /* old=crw, write:xxx, read:add, close:del */ { 0, 255 }, /* old=crw, write:xxx, read:add, close:xxx */ { 0, 255 }, /* old=crw, write:xxx, read:del, close: 0 */ { 0, 255 }, /* old=crw, write:xxx, read:del, close:add */ { 0, 255 }, /* old=crw, write:xxx, read:del, close:del */ { 0, 255 }, /* old=crw, write:xxx, read:del, close:xxx */ { 0, 255 }, /* old=crw, write:xxx, read:xxx, close: 0 */ { 0, 255 }, /* old=crw, write:xxx, read:xxx, close:add */ { 0, 255 }, /* old=crw, write:xxx, read:xxx, close:del */ { 0, 255 }, /* old=crw, write:xxx, read:xxx, close:xxx */ { 0, 255 }, }; #endif lldpd-1.0.13/libevent/event_rpcgen.py0000755000076400001440000015323214111362570020243 0ustar00bernatusers00000000000000#!/usr/bin/env python # # Copyright (c) 2005-2007 Niels Provos # Copyright (c) 2007-2012 Niels Provos and Nick Mathewson # All rights reserved. # # Generates marshaling code based on libevent. # pylint: disable=too-many-lines # pylint: disable=too-many-branches # pylint: disable=too-many-public-methods # pylint: disable=too-many-statements # pylint: disable=global-statement # TODO: # 1) propagate the arguments/options parsed by argparse down to the # instantiated factory objects. # 2) move the globals into a class that manages execution, including the # progress outputs that go to stderr at the moment. # 3) emit other languages. import argparse import re import sys _NAME = "event_rpcgen.py" _VERSION = "0.1" # Globals LINE_COUNT = 0 CPPCOMMENT_RE = re.compile(r"\/\/.*$") NONIDENT_RE = re.compile(r"\W") PREPROCESSOR_DEF_RE = re.compile(r"^#define") STRUCT_REF_RE = re.compile(r"^struct\[(?P[a-zA-Z_][a-zA-Z0-9_]*)\]$") STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$") WHITESPACE_RE = re.compile(r"\s+") HEADER_DIRECT = [] CPP_DIRECT = [] QUIETLY = False def declare(s): if not QUIETLY: print(s) def TranslateList(mylist, mydict): return [x % mydict for x in mylist] class RpcGenError(Exception): """An Exception class for parse errors.""" def __init__(self, why): # pylint: disable=super-init-not-called self.why = why def __str__(self): return str(self.why) # Holds everything that makes a struct class Struct(object): def __init__(self, name): self._name = name self._entries = [] self._tags = {} declare(" Created struct: %s" % name) def AddEntry(self, entry): if entry.Tag() in self._tags: raise RpcGenError( 'Entry "%s" duplicates tag number %d from "%s" ' "around line %d" % (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT) ) self._entries.append(entry) self._tags[entry.Tag()] = entry.Name() declare(" Added entry: %s" % entry.Name()) def Name(self): return self._name def EntryTagName(self, entry): """Creates the name inside an enumeration for distinguishing data types.""" name = "%s_%s" % (self._name, entry.Name()) return name.upper() @staticmethod def PrintIndented(filep, ident, code): """Takes an array, add indentation to each entry and prints it.""" for entry in code: filep.write("%s%s\n" % (ident, entry)) class StructCCode(Struct): """ Knows how to generate C code for a struct """ def __init__(self, name): Struct.__init__(self, name) def PrintTags(self, filep): """Prints the tag definitions for a structure.""" filep.write("/* Tag definition for %s */\n" % self._name) filep.write("enum %s_ {\n" % self._name.lower()) for entry in self._entries: filep.write(" %s=%d,\n" % (self.EntryTagName(entry), entry.Tag())) filep.write(" %s_MAX_TAGS\n" % (self._name.upper())) filep.write("};\n\n") def PrintForwardDeclaration(self, filep): filep.write("struct %s;\n" % self._name) def PrintDeclaration(self, filep): filep.write("/* Structure declaration for %s */\n" % self._name) filep.write("struct %s_access_ {\n" % self._name) for entry in self._entries: dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name()) dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name())) if entry.Array(): dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name())) self.PrintIndented(filep, " ", dcl) filep.write("};\n\n") filep.write("struct %s {\n" % self._name) filep.write(" struct %s_access_ *base;\n\n" % self._name) for entry in self._entries: dcl = entry.Declaration() self.PrintIndented(filep, " ", dcl) filep.write("\n") for entry in self._entries: filep.write(" ev_uint8_t %s_set;\n" % entry.Name()) filep.write("};\n\n") filep.write( """struct %(name)s *%(name)s_new(void); struct %(name)s *%(name)s_new_with_arg(void *); void %(name)s_free(struct %(name)s *); void %(name)s_clear(struct %(name)s *); void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); int %(name)s_complete(struct %(name)s *); void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, const struct %(name)s *); int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, struct %(name)s *);\n""" % {"name": self._name} ) # Write a setting function of every variable for entry in self._entries: self.PrintIndented( filep, "", entry.AssignDeclaration(entry.AssignFuncName()) ) self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName())) if entry.Array(): self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName())) filep.write("/* --- %s done --- */\n\n" % self._name) def PrintCode(self, filep): filep.write( """/* * Implementation of %s */ """ % (self._name) ) filep.write( """ static struct %(name)s_access_ %(name)s_base__ = { """ % {"name": self._name} ) for entry in self._entries: self.PrintIndented(filep, " ", entry.CodeBase()) filep.write("};\n\n") # Creation filep.write( """struct %(name)s * %(name)s_new(void) { return %(name)s_new_with_arg(NULL); } struct %(name)s * %(name)s_new_with_arg(void *unused) { struct %(name)s *tmp; if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) { event_warn("%%s: malloc", __func__); return (NULL); } tmp->base = &%(name)s_base__; """ % {"name": self._name} ) for entry in self._entries: self.PrintIndented(filep, " ", entry.CodeInitialize("tmp")) filep.write(" tmp->%s_set = 0;\n\n" % entry.Name()) filep.write( """ return (tmp); } """ ) # Adding for entry in self._entries: if entry.Array(): self.PrintIndented(filep, "", entry.CodeAdd()) filep.write("\n") # Assigning for entry in self._entries: self.PrintIndented(filep, "", entry.CodeAssign()) filep.write("\n") # Getting for entry in self._entries: self.PrintIndented(filep, "", entry.CodeGet()) filep.write("\n") # Clearing filep.write( """void %(name)s_clear(struct %(name)s *tmp) { """ % {"name": self._name} ) for entry in self._entries: self.PrintIndented(filep, " ", entry.CodeClear("tmp")) filep.write("}\n\n") # Freeing filep.write( """void %(name)s_free(struct %(name)s *tmp) { """ % {"name": self._name} ) for entry in self._entries: self.PrintIndented(filep, " ", entry.CodeFree("tmp")) filep.write( """ free(tmp); } """ ) # Marshaling filep.write( """void %(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) { """ % {"name": self._name} ) for entry in self._entries: indent = " " # Optional entries do not have to be set if entry.Optional(): indent += " " filep.write(" if (tmp->%s_set) {\n" % entry.Name()) self.PrintIndented( filep, indent, entry.CodeMarshal( "evbuf", self.EntryTagName(entry), entry.GetVarName("tmp"), entry.GetVarLen("tmp"), ), ) if entry.Optional(): filep.write(" }\n") filep.write("}\n\n") # Unmarshaling filep.write( """int %(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { """ % {"name": self._name} ) for entry in self._entries: filep.write(" case %s:\n" % (self.EntryTagName(entry))) if not entry.Array(): filep.write( """ if (tmp->%s_set) return (-1); """ % (entry.Name()) ) self.PrintIndented( filep, " ", entry.CodeUnmarshal( "evbuf", self.EntryTagName(entry), entry.GetVarName("tmp"), entry.GetVarLen("tmp"), ), ) filep.write( """ tmp->%s_set = 1; break; """ % (entry.Name()) ) filep.write( """ default: return -1; } } """ ) # Check if it was decoded completely filep.write( """ if (%(name)s_complete(tmp) == -1) return (-1); return (0); } """ % {"name": self._name} ) # Checking if a structure has all the required data filep.write( """ int %(name)s_complete(struct %(name)s *msg) { """ % {"name": self._name} ) for entry in self._entries: if not entry.Optional(): code = [ """if (!msg->%(name)s_set) return (-1);""" ] code = TranslateList(code, entry.GetTranslation()) self.PrintIndented(filep, " ", code) self.PrintIndented( filep, " ", entry.CodeComplete("msg", entry.GetVarName("msg")) ) filep.write( """ return (0); } """ ) # Complete message unmarshaling filep.write( """ int evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag, struct %(name)s *msg) { ev_uint32_t tag; int res = -1; struct evbuffer *tmp = evbuffer_new(); if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag) goto error; if (%(name)s_unmarshal(msg, tmp) == -1) goto error; res = 0; error: evbuffer_free(tmp); return (res); } """ % {"name": self._name} ) # Complete message marshaling filep.write( """ void evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, const struct %(name)s *msg) { struct evbuffer *buf_ = evbuffer_new(); assert(buf_ != NULL); %(name)s_marshal(buf_, msg); evtag_marshal_buffer(evbuf, tag, buf_); evbuffer_free(buf_); } """ % {"name": self._name} ) class Entry(object): def __init__(self, ent_type, name, tag): self._type = ent_type self._name = name self._tag = int(tag) self._ctype = ent_type self._optional = False self._can_be_array = False self._array = False self._line_count = -1 self._struct = None self._refname = None self._optpointer = True self._optaddarg = True @staticmethod def GetInitializer(): raise NotImplementedError("Entry does not provide an initializer") def SetStruct(self, struct): self._struct = struct def LineCount(self): assert self._line_count != -1 return self._line_count def SetLineCount(self, number): self._line_count = number def Array(self): return self._array def Optional(self): return self._optional def Tag(self): return self._tag def Name(self): return self._name def Type(self): return self._type def MakeArray(self): self._array = True def MakeOptional(self): self._optional = True def Verify(self): if self.Array() and not self._can_be_array: raise RpcGenError( 'Entry "%s" cannot be created as an array ' "around line %d" % (self._name, self.LineCount()) ) if not self._struct: raise RpcGenError( 'Entry "%s" does not know which struct it belongs to ' "around line %d" % (self._name, self.LineCount()) ) if self._optional and self._array: raise RpcGenError( 'Entry "%s" has illegal combination of optional and array ' "around line %d" % (self._name, self.LineCount()) ) def GetTranslation(self, extradict=None): if extradict is None: extradict = {} mapping = { "parent_name": self._struct.Name(), "name": self._name, "ctype": self._ctype, "refname": self._refname, "optpointer": self._optpointer and "*" or "", "optreference": self._optpointer and "&" or "", "optaddarg": self._optaddarg and ", const %s value" % self._ctype or "", } for (k, v) in list(extradict.items()): mapping[k] = v return mapping def GetVarName(self, var): return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var}) def GetVarLen(self, _var): return "sizeof(%s)" % self._ctype def GetFuncName(self): return "%s_%s_get" % (self._struct.Name(), self._name) def GetDeclaration(self, funcname): code = [ "int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype) ] return code def CodeGet(self): code = """int %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value) { if (msg->%(name)s_set != 1) return (-1); *value = msg->%(name)s_data; return (0); }""" code = code % self.GetTranslation() return code.split("\n") def AssignFuncName(self): return "%s_%s_assign" % (self._struct.Name(), self._name) def AddFuncName(self): return "%s_%s_add" % (self._struct.Name(), self._name) def AssignDeclaration(self, funcname): code = [ "int %s(struct %s *, const %s);" % (funcname, self._struct.Name(), self._ctype) ] return code def CodeAssign(self): code = [ "int", "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg," " const %(ctype)s value)", "{", " msg->%(name)s_set = 1;", " msg->%(name)s_data = value;", " return (0);", "}", ] code = "\n".join(code) code = code % self.GetTranslation() return code.split("\n") def CodeClear(self, structname): code = ["%s->%s_set = 0;" % (structname, self.Name())] return code @staticmethod def CodeComplete(_structname, _var_name): return [] @staticmethod def CodeFree(_name): return [] def CodeBase(self): code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"] if self.Array(): code.append("%(parent_name)s_%(name)s_add,") code = "\n".join(code) code = code % self.GetTranslation() return code.split("\n") class EntryBytes(Entry): def __init__(self, ent_type, name, tag, length): # Init base class super(EntryBytes, self).__init__(ent_type, name, tag) self._length = length self._ctype = "ev_uint8_t" @staticmethod def GetInitializer(): return "NULL" def GetVarLen(self, _var): return "(%s)" % self._length @staticmethod def CodeArrayAdd(varname, _value): # XXX: copy here return ["%(varname)s = NULL;" % {"varname": varname}] def GetDeclaration(self, funcname): code = [ "int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype) ] return code def AssignDeclaration(self, funcname): code = [ "int %s(struct %s *, const %s *);" % (funcname, self._struct.Name(), self._ctype) ] return code def Declaration(self): dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)] return dcl def CodeGet(self): name = self._name code = [ "int", "%s_%s_get(struct %s *msg, %s **value)" % (self._struct.Name(), name, self._struct.Name(), self._ctype), "{", " if (msg->%s_set != 1)" % name, " return (-1);", " *value = msg->%s_data;" % name, " return (0);", "}", ] return code def CodeAssign(self): name = self._name code = [ "int", "%s_%s_assign(struct %s *msg, const %s *value)" % (self._struct.Name(), name, self._struct.Name(), self._ctype), "{", " msg->%s_set = 1;" % name, " memcpy(msg->%s_data, value, %s);" % (name, self._length), " return (0);", "}", ] return code def CodeUnmarshal(self, buf, tag_name, var_name, var_len): code = [ "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, " "%(var)s, %(varlen)s) == -1) {", ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', " return (-1);", "}", ] return TranslateList( code, self.GetTranslation( {"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name} ), ) @staticmethod def CodeMarshal(buf, tag_name, var_name, var_len): code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)] return code def CodeClear(self, structname): code = [ "%s->%s_set = 0;" % (structname, self.Name()), "memset(%s->%s_data, 0, sizeof(%s->%s_data));" % (structname, self._name, structname, self._name), ] return code def CodeInitialize(self, name): code = [ "memset(%s->%s_data, 0, sizeof(%s->%s_data));" % (name, self._name, name, self._name) ] return code def Verify(self): if not self._length: raise RpcGenError( 'Entry "%s" needs a length ' "around line %d" % (self._name, self.LineCount()) ) super(EntryBytes, self).Verify() class EntryInt(Entry): def __init__(self, ent_type, name, tag, bits=32): # Init base class super(EntryInt, self).__init__(ent_type, name, tag) self._can_be_array = True if bits == 32: self._ctype = "ev_uint32_t" self._marshal_type = "int" if bits == 64: self._ctype = "ev_uint64_t" self._marshal_type = "int64" @staticmethod def GetInitializer(): return "0" @staticmethod def CodeArrayFree(_var): return [] @staticmethod def CodeArrayAssign(varname, srcvar): return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}] @staticmethod def CodeArrayAdd(varname, value): """Returns a new entry of this type.""" return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}] def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): code = [ "if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {", ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', " return (-1);", "}", ] code = "\n".join(code) % self.GetTranslation( {"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name} ) return code.split("\n") def CodeMarshal(self, buf, tag_name, var_name, _var_len): code = [ "evtag_marshal_%s(%s, %s, %s);" % (self._marshal_type, buf, tag_name, var_name) ] return code def Declaration(self): dcl = ["%s %s_data;" % (self._ctype, self._name)] return dcl def CodeInitialize(self, name): code = ["%s->%s_data = 0;" % (name, self._name)] return code class EntryString(Entry): def __init__(self, ent_type, name, tag): # Init base class super(EntryString, self).__init__(ent_type, name, tag) self._can_be_array = True self._ctype = "char *" @staticmethod def GetInitializer(): return "NULL" @staticmethod def CodeArrayFree(varname): code = ["if (%(var)s != NULL) free(%(var)s);"] return TranslateList(code, {"var": varname}) @staticmethod def CodeArrayAssign(varname, srcvar): code = [ "if (%(var)s != NULL)", " free(%(var)s);", "%(var)s = strdup(%(srcvar)s);", "if (%(var)s == NULL) {", ' event_warnx("%%s: strdup", __func__);', " return (-1);", "}", ] return TranslateList(code, {"var": varname, "srcvar": srcvar}) @staticmethod def CodeArrayAdd(varname, value): code = [ "if (%(value)s != NULL) {", " %(var)s = strdup(%(value)s);", " if (%(var)s == NULL) {", " goto error;", " }", "} else {", " %(var)s = NULL;", "}", ] return TranslateList(code, {"var": varname, "value": value}) def GetVarLen(self, var): return "strlen(%s)" % self.GetVarName(var) @staticmethod def CodeMakeInitalize(varname): return "%(varname)s = NULL;" % {"varname": varname} def CodeAssign(self): code = """int %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, const %(ctype)s value) { if (msg->%(name)s_data != NULL) free(msg->%(name)s_data); if ((msg->%(name)s_data = strdup(value)) == NULL) return (-1); msg->%(name)s_set = 1; return (0); }""" % ( self.GetTranslation() ) return code.split("\n") def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): code = [ "if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {", ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', " return (-1);", "}", ] code = "\n".join(code) % self.GetTranslation( {"buf": buf, "tag": tag_name, "var": var_name} ) return code.split("\n") @staticmethod def CodeMarshal(buf, tag_name, var_name, _var_len): code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)] return code def CodeClear(self, structname): code = [ "if (%s->%s_set == 1) {" % (structname, self.Name()), " free(%s->%s_data);" % (structname, self.Name()), " %s->%s_data = NULL;" % (structname, self.Name()), " %s->%s_set = 0;" % (structname, self.Name()), "}", ] return code def CodeInitialize(self, name): code = ["%s->%s_data = NULL;" % (name, self._name)] return code def CodeFree(self, name): code = [ "if (%s->%s_data != NULL)" % (name, self._name), " free (%s->%s_data);" % (name, self._name), ] return code def Declaration(self): dcl = ["char *%s_data;" % self._name] return dcl class EntryStruct(Entry): def __init__(self, ent_type, name, tag, refname): # Init base class super(EntryStruct, self).__init__(ent_type, name, tag) self._optpointer = False self._can_be_array = True self._refname = refname self._ctype = "struct %s*" % refname self._optaddarg = False def GetInitializer(self): return "NULL" def GetVarLen(self, _var): return "-1" def CodeArrayAdd(self, varname, _value): code = [ "%(varname)s = %(refname)s_new();", "if (%(varname)s == NULL)", " goto error;", ] return TranslateList(code, self.GetTranslation({"varname": varname})) def CodeArrayFree(self, var): code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})] return code def CodeArrayAssign(self, var, srcvar): code = [ "int had_error = 0;", "struct evbuffer *tmp = NULL;", "%(refname)s_clear(%(var)s);", "if ((tmp = evbuffer_new()) == NULL) {", ' event_warn("%%s: evbuffer_new()", __func__);', " had_error = 1;", " goto done;", "}", "%(refname)s_marshal(tmp, %(srcvar)s);", "if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {", ' event_warnx("%%s: %(refname)s_unmarshal", __func__);', " had_error = 1;", " goto done;", "}", "done:", "if (tmp != NULL)", " evbuffer_free(tmp);", "if (had_error) {", " %(refname)s_clear(%(var)s);", " return (-1);", "}", ] return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar})) def CodeGet(self): name = self._name code = [ "int", "%s_%s_get(struct %s *msg, %s *value)" % (self._struct.Name(), name, self._struct.Name(), self._ctype), "{", " if (msg->%s_set != 1) {" % name, " msg->%s_data = %s_new();" % (name, self._refname), " if (msg->%s_data == NULL)" % name, " return (-1);", " msg->%s_set = 1;" % name, " }", " *value = msg->%s_data;" % name, " return (0);", "}", ] return code def CodeAssign(self): code = ( """int %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, const %(ctype)s value) { struct evbuffer *tmp = NULL; if (msg->%(name)s_set) { %(refname)s_clear(msg->%(name)s_data); msg->%(name)s_set = 0; } else { msg->%(name)s_data = %(refname)s_new(); if (msg->%(name)s_data == NULL) { event_warn("%%s: %(refname)s_new()", __func__); goto error; } } if ((tmp = evbuffer_new()) == NULL) { event_warn("%%s: evbuffer_new()", __func__); goto error; } %(refname)s_marshal(tmp, value); if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { event_warnx("%%s: %(refname)s_unmarshal", __func__); goto error; } msg->%(name)s_set = 1; evbuffer_free(tmp); return (0); error: if (tmp != NULL) evbuffer_free(tmp); if (msg->%(name)s_data != NULL) { %(refname)s_free(msg->%(name)s_data); msg->%(name)s_data = NULL; } return (-1); }""" % self.GetTranslation() ) return code.split("\n") def CodeComplete(self, structname, var_name): code = [ "if (%(structname)s->%(name)s_set && " "%(refname)s_complete(%(var)s) == -1)", " return (-1);", ] return TranslateList( code, self.GetTranslation({"structname": structname, "var": var_name}) ) def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): code = [ "%(var)s = %(refname)s_new();", "if (%(var)s == NULL)", " return (-1);", "if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ", " %(var)s) == -1) {", ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', " return (-1);", "}", ] code = "\n".join(code) % self.GetTranslation( {"buf": buf, "tag": tag_name, "var": var_name} ) return code.split("\n") def CodeMarshal(self, buf, tag_name, var_name, _var_len): code = [ "evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name) ] return code def CodeClear(self, structname): code = [ "if (%s->%s_set == 1) {" % (structname, self.Name()), " %s_free(%s->%s_data);" % (self._refname, structname, self.Name()), " %s->%s_data = NULL;" % (structname, self.Name()), " %s->%s_set = 0;" % (structname, self.Name()), "}", ] return code def CodeInitialize(self, name): code = ["%s->%s_data = NULL;" % (name, self._name)] return code def CodeFree(self, name): code = [ "if (%s->%s_data != NULL)" % (name, self._name), " %s_free(%s->%s_data);" % (self._refname, name, self._name), ] return code def Declaration(self): dcl = ["%s %s_data;" % (self._ctype, self._name)] return dcl class EntryVarBytes(Entry): def __init__(self, ent_type, name, tag): # Init base class super(EntryVarBytes, self).__init__(ent_type, name, tag) self._ctype = "ev_uint8_t *" @staticmethod def GetInitializer(): return "NULL" def GetVarLen(self, var): return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var}) @staticmethod def CodeArrayAdd(varname, _value): # xxx: copy return ["%(varname)s = NULL;" % {"varname": varname}] def GetDeclaration(self, funcname): code = [ "int %s(struct %s *, %s *, ev_uint32_t *);" % (funcname, self._struct.Name(), self._ctype) ] return code def AssignDeclaration(self, funcname): code = [ "int %s(struct %s *, const %s, ev_uint32_t);" % (funcname, self._struct.Name(), self._ctype) ] return code def CodeAssign(self): name = self._name code = [ "int", "%s_%s_assign(struct %s *msg, " "const %s value, ev_uint32_t len)" % (self._struct.Name(), name, self._struct.Name(), self._ctype), "{", " if (msg->%s_data != NULL)" % name, " free (msg->%s_data);" % name, " msg->%s_data = malloc(len);" % name, " if (msg->%s_data == NULL)" % name, " return (-1);", " msg->%s_set = 1;" % name, " msg->%s_length = len;" % name, " memcpy(msg->%s_data, value, len);" % name, " return (0);", "}", ] return code def CodeGet(self): name = self._name code = [ "int", "%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)" % (self._struct.Name(), name, self._struct.Name(), self._ctype), "{", " if (msg->%s_set != 1)" % name, " return (-1);", " *value = msg->%s_data;" % name, " *plen = msg->%s_length;" % name, " return (0);", "}", ] return code def CodeUnmarshal(self, buf, tag_name, var_name, var_len): code = [ "if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)", " return (-1);", # We do not want DoS opportunities "if (%(varlen)s > evbuffer_get_length(%(buf)s))", " return (-1);", "if ((%(var)s = malloc(%(varlen)s)) == NULL)", " return (-1);", "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, " "%(varlen)s) == -1) {", ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', " return (-1);", "}", ] code = "\n".join(code) % self.GetTranslation( {"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len} ) return code.split("\n") @staticmethod def CodeMarshal(buf, tag_name, var_name, var_len): code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)] return code def CodeClear(self, structname): code = [ "if (%s->%s_set == 1) {" % (structname, self.Name()), " free (%s->%s_data);" % (structname, self.Name()), " %s->%s_data = NULL;" % (structname, self.Name()), " %s->%s_length = 0;" % (structname, self.Name()), " %s->%s_set = 0;" % (structname, self.Name()), "}", ] return code def CodeInitialize(self, name): code = [ "%s->%s_data = NULL;" % (name, self._name), "%s->%s_length = 0;" % (name, self._name), ] return code def CodeFree(self, name): code = [ "if (%s->%s_data != NULL)" % (name, self._name), " free(%s->%s_data);" % (name, self._name), ] return code def Declaration(self): dcl = [ "ev_uint8_t *%s_data;" % self._name, "ev_uint32_t %s_length;" % self._name, ] return dcl class EntryArray(Entry): _index = None def __init__(self, entry): # Init base class super(EntryArray, self).__init__(entry._type, entry._name, entry._tag) self._entry = entry self._refname = entry._refname self._ctype = self._entry._ctype self._optional = True self._optpointer = self._entry._optpointer self._optaddarg = self._entry._optaddarg # provide a new function for accessing the variable name def GetVarName(var_name): return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation( {"var": var_name, "index": self._index} ) self._entry.GetVarName = GetVarName def GetInitializer(self): return "NULL" def GetVarName(self, var): return var def GetVarLen(self, _var_name): return "-1" def GetDeclaration(self, funcname): """Allows direct access to elements of the array.""" code = [ "int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);" % self.GetTranslation({"funcname": funcname}) ] return code def AssignDeclaration(self, funcname): code = [ "int %s(struct %s *, int, const %s);" % (funcname, self._struct.Name(), self._ctype) ] return code def AddDeclaration(self, funcname): code = [ "%(ctype)s %(optpointer)s " "%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);" % self.GetTranslation({"funcname": funcname}) ] return code def CodeGet(self): code = """int %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, %(ctype)s *value) { if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) return (-1); *value = msg->%(name)s_data[offset]; return (0); } """ % ( self.GetTranslation() ) return code.splitlines() def CodeAssign(self): code = [ "int", "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,", " const %(ctype)s value)", "{", " if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)", " return (-1);", "", " {", ] code = TranslateList(code, self.GetTranslation()) codearrayassign = self._entry.CodeArrayAssign( "msg->%(name)s_data[off]" % self.GetTranslation(), "value" ) code += [" " + x for x in codearrayassign] code += TranslateList([" }", " return (0);", "}"], self.GetTranslation()) return code def CodeAdd(self): codearrayadd = self._entry.CodeArrayAdd( "msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(), "value", ) code = [ "static int", "%(parent_name)s_%(name)s_expand_to_hold_more(" "struct %(parent_name)s *msg)", "{", " int tobe_allocated = msg->%(name)s_num_allocated;", " %(ctype)s* new_data = NULL;", " tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;", " new_data = (%(ctype)s*) realloc(msg->%(name)s_data,", " tobe_allocated * sizeof(%(ctype)s));", " if (new_data == NULL)", " return -1;", " msg->%(name)s_data = new_data;", " msg->%(name)s_num_allocated = tobe_allocated;", " return 0;", "}", "", "%(ctype)s %(optpointer)s", "%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)", "{", " if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {", " if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)", " goto error;", " }", ] code = TranslateList(code, self.GetTranslation()) code += [" " + x for x in codearrayadd] code += TranslateList( [ " msg->%(name)s_set = 1;", " return %(optreference)s(msg->%(name)s_data[" "msg->%(name)s_length - 1]);", "error:", " --msg->%(name)s_length;", " return (NULL);", "}", ], self.GetTranslation(), ) return code def CodeComplete(self, structname, var_name): self._index = "i" tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name)) # skip the whole loop if there is nothing to check if not tmp: return [] translate = self.GetTranslation({"structname": structname}) code = [ "{", " int i;", " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {", ] code = TranslateList(code, translate) code += [" " + x for x in tmp] code += [" }", "}"] return code def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): translate = self.GetTranslation( { "var": var_name, "buf": buf, "tag": tag_name, "init": self._entry.GetInitializer(), } ) code = [ "if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&", " %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {", ' puts("HEY NOW");', " return (-1);", "}", ] # the unmarshal code directly returns code = TranslateList(code, translate) self._index = "%(var)s->%(name)s_length" % translate code += self._entry.CodeUnmarshal( buf, tag_name, self._entry.GetVarName(var_name), self._entry.GetVarLen(var_name), ) code += ["++%(var)s->%(name)s_length;" % translate] return code def CodeMarshal(self, buf, tag_name, var_name, _var_len): code = ["{", " int i;", " for (i = 0; i < %(var)s->%(name)s_length; ++i) {"] self._index = "i" code += self._entry.CodeMarshal( buf, tag_name, self._entry.GetVarName(var_name), self._entry.GetVarLen(var_name), ) code += [" }", "}"] code = "\n".join(code) % self.GetTranslation({"var": var_name}) return code.split("\n") def CodeClear(self, structname): translate = self.GetTranslation({"structname": structname}) codearrayfree = self._entry.CodeArrayFree( "%(structname)s->%(name)s_data[i]" % self.GetTranslation({"structname": structname}) ) code = ["if (%(structname)s->%(name)s_set == 1) {"] if codearrayfree: code += [ " int i;", " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {", ] code = TranslateList(code, translate) if codearrayfree: code += [" " + x for x in codearrayfree] code += [" }"] code += TranslateList( [ " free(%(structname)s->%(name)s_data);", " %(structname)s->%(name)s_data = NULL;", " %(structname)s->%(name)s_set = 0;", " %(structname)s->%(name)s_length = 0;", " %(structname)s->%(name)s_num_allocated = 0;", "}", ], translate, ) return code def CodeInitialize(self, name): code = [ "%s->%s_data = NULL;" % (name, self._name), "%s->%s_length = 0;" % (name, self._name), "%s->%s_num_allocated = 0;" % (name, self._name), ] return code def CodeFree(self, structname): code = self.CodeClear(structname) code += TranslateList( ["free(%(structname)s->%(name)s_data);"], self.GetTranslation({"structname": structname}), ) return code def Declaration(self): dcl = [ "%s *%s_data;" % (self._ctype, self._name), "int %s_length;" % self._name, "int %s_num_allocated;" % self._name, ] return dcl def NormalizeLine(line): line = CPPCOMMENT_RE.sub("", line) line = line.strip() line = WHITESPACE_RE.sub(" ", line) return line ENTRY_NAME_RE = re.compile(r"(?P[^\[\]]+)(\[(?P.*)\])?") ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I) def ProcessOneEntry(factory, newstruct, entry): optional = False array = False entry_type = "" name = "" tag = "" tag_set = None separator = "" fixed_length = "" for token in entry.split(" "): if not entry_type: if not optional and token == "optional": optional = True continue if not array and token == "array": array = True continue if not entry_type: entry_type = token continue if not name: res = ENTRY_NAME_RE.match(token) if not res: raise RpcGenError( r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT) ) name = res.group("name") fixed_length = res.group("fixed_length") continue if not separator: separator = token if separator != "=": raise RpcGenError( r'''Expected "=" after name "%s" got "%s"''' % (name, token) ) continue if not tag_set: tag_set = 1 if not ENTRY_TAG_NUMBER_RE.match(token): raise RpcGenError(r'''Expected tag number: "%s"''' % (entry)) tag = int(token, 0) continue raise RpcGenError(r'''Cannot parse "%s"''' % (entry)) if not tag_set: raise RpcGenError(r'''Need tag number: "%s"''' % (entry)) # Create the right entry if entry_type == "bytes": if fixed_length: newentry = factory.EntryBytes(entry_type, name, tag, fixed_length) else: newentry = factory.EntryVarBytes(entry_type, name, tag) elif entry_type == "int" and not fixed_length: newentry = factory.EntryInt(entry_type, name, tag) elif entry_type == "int64" and not fixed_length: newentry = factory.EntryInt(entry_type, name, tag, bits=64) elif entry_type == "string" and not fixed_length: newentry = factory.EntryString(entry_type, name, tag) else: res = STRUCT_REF_RE.match(entry_type) if res: # References another struct defined in our file newentry = factory.EntryStruct(entry_type, name, tag, res.group("name")) else: raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry)) structs = [] if optional: newentry.MakeOptional() if array: newentry.MakeArray() newentry.SetStruct(newstruct) newentry.SetLineCount(LINE_COUNT) newentry.Verify() if array: # We need to encapsulate this entry into a struct newentry = factory.EntryArray(newentry) newentry.SetStruct(newstruct) newentry.SetLineCount(LINE_COUNT) newentry.MakeArray() newstruct.AddEntry(newentry) return structs def ProcessStruct(factory, data): tokens = data.split(" ") # First three tokens are: 'struct' 'name' '{' newstruct = factory.Struct(tokens[1]) inside = " ".join(tokens[3:-1]) tokens = inside.split(";") structs = [] for entry in tokens: entry = NormalizeLine(entry) if not entry: continue # It's possible that new structs get defined in here structs.extend(ProcessOneEntry(factory, newstruct, entry)) structs.append(newstruct) return structs C_COMMENT_START = "/*" C_COMMENT_END = "*/" C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START)) C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END)) C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START))) C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END))) C_MULTILINE_COMMENT_SUB_RE = re.compile( r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END)) ) CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)") INCLUDE_RE = re.compile(r'#include (".+"|<.+>)') def GetNextStruct(filep): global CPP_DIRECT global LINE_COUNT got_struct = False have_c_comment = False data = "" while True: line = filep.readline() if not line: break LINE_COUNT += 1 line = line[:-1] if not have_c_comment and C_COMMENT_START_RE.search(line): if C_MULTILINE_COMMENT_SUB_RE.search(line): line = C_MULTILINE_COMMENT_SUB_RE.sub("", line) else: line = C_COMMENT_START_SUB_RE.sub("", line) have_c_comment = True if have_c_comment: if not C_COMMENT_END_RE.search(line): continue have_c_comment = False line = C_COMMENT_END_SUB_RE.sub("", line) line = NormalizeLine(line) if not line: continue if not got_struct: if INCLUDE_RE.match(line): CPP_DIRECT.append(line) elif CPP_CONDITIONAL_BLOCK_RE.match(line): CPP_DIRECT.append(line) elif PREPROCESSOR_DEF_RE.match(line): HEADER_DIRECT.append(line) elif not STRUCT_DEF_RE.match(line): raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line)) else: got_struct = True data += line continue # We are inside the struct tokens = line.split("}") if len(tokens) == 1: data += " " + line continue if tokens[1]: raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT) # We found the end of the struct data += " %s}" % tokens[0] break # Remove any comments, that might be in there data = re.sub(r"/\*.*\*/", "", data) return data def Parse(factory, filep): """ Parses the input file and returns C code and corresponding header file. """ entities = [] while 1: # Just gets the whole struct nicely formatted data = GetNextStruct(filep) if not data: break entities.extend(ProcessStruct(factory, data)) return entities class CCodeGenerator(object): def __init__(self): pass @staticmethod def GuardName(name): # Use the complete provided path to the input file, with all # non-identifier characters replaced with underscores, to # reduce the chance of a collision between guard macros. return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper()) def HeaderPreamble(self, name): guard = self.GuardName(name) pre = """ /* * Automatically generated from %s */ #ifndef %s #define %s """ % ( name, guard, guard, ) if HEADER_DIRECT: for statement in HEADER_DIRECT: pre += "%s\n" % statement pre += "\n" pre += """ #include /* for ev_uint*_t */ #include """ return pre def HeaderPostamble(self, name): guard = self.GuardName(name) return "#endif /* %s */" % (guard) @staticmethod def BodyPreamble(name, header_file): global _NAME global _VERSION slash = header_file.rfind("/") if slash != -1: header_file = header_file[slash + 1 :] pre = """ /* * Automatically generated from %(name)s * by %(script_name)s/%(script_version)s. DO NOT EDIT THIS FILE. */ #include #include #include #include #include #include #include #if defined(EVENT__HAVE___func__) # ifndef __func__ # define __func__ __func__ # endif #elif defined(EVENT__HAVE___FUNCTION__) # define __func__ __FUNCTION__ #else # define __func__ __FILE__ #endif """ % { "name": name, "script_name": _NAME, "script_version": _VERSION, } for statement in CPP_DIRECT: pre += "%s\n" % statement pre += '\n#include "%s"\n\n' % header_file pre += "void event_warn(const char *fmt, ...);\n" pre += "void event_warnx(const char *fmt, ...);\n\n" return pre @staticmethod def HeaderFilename(filename): return ".".join(filename.split(".")[:-1]) + ".h" @staticmethod def CodeFilename(filename): return ".".join(filename.split(".")[:-1]) + ".gen.c" @staticmethod def Struct(name): return StructCCode(name) @staticmethod def EntryBytes(entry_type, name, tag, fixed_length): return EntryBytes(entry_type, name, tag, fixed_length) @staticmethod def EntryVarBytes(entry_type, name, tag): return EntryVarBytes(entry_type, name, tag) @staticmethod def EntryInt(entry_type, name, tag, bits=32): return EntryInt(entry_type, name, tag, bits) @staticmethod def EntryString(entry_type, name, tag): return EntryString(entry_type, name, tag) @staticmethod def EntryStruct(entry_type, name, tag, struct_name): return EntryStruct(entry_type, name, tag, struct_name) @staticmethod def EntryArray(entry): return EntryArray(entry) class CommandLine(object): def __init__(self, argv=None): """Initialize a command-line to launch event_rpcgen, as if from a command-line with CommandLine(sys.argv). If you're calling this directly, remember to provide a dummy value for sys.argv[0] """ global QUIETLY self.filename = None self.header_file = None self.impl_file = None self.factory = CCodeGenerator() parser = argparse.ArgumentParser( usage="%(prog)s [options] rpc-file [[h-file] c-file]" ) parser.add_argument("--quiet", action="store_true", default=False) parser.add_argument("rpc_file", type=argparse.FileType("r")) args, extra_args = parser.parse_known_args(args=argv) QUIETLY = args.quiet if extra_args: if len(extra_args) == 1: self.impl_file = extra_args[0].replace("\\", "/") elif len(extra_args) == 2: self.header_file = extra_args[0].replace("\\", "/") self.impl_file = extra_args[1].replace("\\", "/") else: parser.error("Spurious arguments provided") self.rpc_file = args.rpc_file if not self.impl_file: self.impl_file = self.factory.CodeFilename(self.rpc_file.name) if not self.header_file: self.header_file = self.factory.HeaderFilename(self.impl_file) if not self.impl_file.endswith(".c"): parser.error("can only generate C implementation files") if not self.header_file.endswith(".h"): parser.error("can only generate C header files") def run(self): filename = self.rpc_file.name header_file = self.header_file impl_file = self.impl_file factory = self.factory declare('Reading "%s"' % filename) with self.rpc_file: entities = Parse(factory, self.rpc_file) declare('... creating "%s"' % header_file) with open(header_file, "w") as header_fp: header_fp.write(factory.HeaderPreamble(filename)) # Create forward declarations: allows other structs to reference # each other for entry in entities: entry.PrintForwardDeclaration(header_fp) header_fp.write("\n") for entry in entities: entry.PrintTags(header_fp) entry.PrintDeclaration(header_fp) header_fp.write(factory.HeaderPostamble(filename)) declare('... creating "%s"' % impl_file) with open(impl_file, "w") as impl_fp: impl_fp.write(factory.BodyPreamble(filename, header_file)) for entry in entities: entry.PrintCode(impl_fp) def main(argv=None): try: CommandLine(argv=argv).run() return 0 except RpcGenError as e: sys.stderr.write(e) except EnvironmentError as e: if e.filename and e.strerror: sys.stderr.write("%s: %s" % (e.filename, e.strerror)) elif e.strerror: sys.stderr.write(e.strerror) else: raise return 1 if __name__ == "__main__": sys.exit(main(argv=sys.argv[1:])) lldpd-1.0.13/libevent/doxygen.am0000644000076400001440000000361414111362570017201 0ustar00bernatusers00000000000000# Doxygen documentation will not be generated with default configuration, # unless '--enable-doxygen-doc' is configured. # The following targets are all about doxygen: # make # 'make doxygen' would be auto executed # make doxygen # generating doxygen documentation # make doxygen-doc # same as 'make doxygen' # make clean # clean docs generated by doxygen # make install # install doxygen documentation # make uninstall # uninstall doxygen documentation if ENABLE_DOXYGEN # Add all needed rules defined in ax_prog_doxygen.m4 @DX_RULES@ # Use 'make clean' to clean docs generated by doxygen. clean-local: -rm -rf $(DX_CLEANFILES) # integrate doxygen with automake targets man3_MANS = @DX_DOCDIR@/man/man3/* $(man3_MANS): doxygen-doc # Docs will be installed. It may be one or more docs supported # by doxygen, but does not include 'man'. docdirs = $(DX_INSTALL_DOCS) # Rules for installing docs generated by doxygen into $(htmldir), # The typical value of $(htmldir) is '/usr/local/share/doc/$(PACKAGE)' install-data-local: @if ! test -d "$(DESTDIR)$(htmldir)"; then \ echo "$(mkinstalldirs) '$(DESTDIR)$(htmldir)'"; \ $(mkinstalldirs) '$(DESTDIR)$(htmldir)'; \ fi @for d in $(docdirs); do \ echo "cp -pR $$d '$(DESTDIR)$(htmldir)/'"; \ cp -pR $$d '$(DESTDIR)$(htmldir)/'; \ done # Rules for uninstalling docs generated by doxygen from $(htmldir) uninstall-local: @for d in $(docdirs); do \ d=`basename $$d`; \ echo "test ! -d '$(DESTDIR)$(htmldir)/'$$d || \ { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \ rm -rf '$(DESTDIR)$(htmldir)/'$$d; }"; \ test ! -d '$(DESTDIR)$(htmldir)/'$$d || \ { find '$(DESTDIR)$(htmldir)/'$$d -type d ! -perm -200 -exec chmod u+w '{}' ';' && \ rm -rf '$(DESTDIR)$(htmldir)/'$$d; }; \ done rmdir "$(DESTDIR)$(htmldir)/" || true doxygen: doxygen-doc endif ENABLE_DOXYGEN lldpd-1.0.13/libevent/evdns.c0000644000076400001440000040272114111362570016472 0ustar00bernatusers00000000000000/* Copyright 2006-2007 Niels Provos * Copyright 2007-2012 Nick Mathewson and Niels Provos * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Based on software by Adam Langly. Adam's original message: * * Async DNS Library * Adam Langley * http://www.imperialviolet.org/eventdns.html * Public Domain code * * This software is Public Domain. To view a copy of the public domain dedication, * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. * * I ask and expect, but do not require, that all derivative works contain an * attribution similar to: * Parts developed by Adam Langley * * You may wish to replace the word "Parts" with something else depending on * the amount of original code. * * (Derivative works does not include programs which link against, run or include * the source verbatim in their source distributions) * * Version: 0.1b */ #include "event2/event-config.h" #include "evconfig-private.h" #include #ifndef _FORTIFY_SOURCE #define _FORTIFY_SOURCE 3 #endif #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #ifdef EVENT__HAVE_STDINT_H #include #endif #include #include #include #ifdef EVENT__HAVE_UNISTD_H #include #endif #include #include #include #include #ifdef _WIN32 #include #include #include #ifndef _WIN32_IE #define _WIN32_IE 0x400 #endif #include #endif #include "event2/dns.h" #include "event2/dns_struct.h" #include "event2/dns_compat.h" #include "event2/util.h" #include "event2/event.h" #include "event2/event_struct.h" #include "event2/thread.h" #include "defer-internal.h" #include "log-internal.h" #include "mm-internal.h" #include "strlcpy-internal.h" #include "ipv6-internal.h" #include "util-internal.h" #include "evthread-internal.h" #ifdef _WIN32 #include #include #include #include #include #else #include #include #include #endif #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG #define EVDNS_LOG_WARN EVENT_LOG_WARN #define EVDNS_LOG_MSG EVENT_LOG_MSG #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 #endif #include #undef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #define ASSERT_VALID_REQUEST(req) \ EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req)) #define u64 ev_uint64_t #define u32 ev_uint32_t #define u16 ev_uint16_t #define u8 ev_uint8_t /* maximum number of addresses from a single packet */ /* that we bother recording */ #define MAX_V4_ADDRS 32 #define MAX_V6_ADDRS 32 #define TYPE_A EVDNS_TYPE_A #define TYPE_CNAME 5 #define TYPE_PTR EVDNS_TYPE_PTR #define TYPE_SOA EVDNS_TYPE_SOA #define TYPE_AAAA EVDNS_TYPE_AAAA #define CLASS_INET EVDNS_CLASS_INET /* Persistent handle. We keep this separate from 'struct request' since we * need some object to last for as long as an evdns_request is outstanding so * that it can be canceled, whereas a search request can lead to multiple * 'struct request' instances being created over its lifetime. */ struct evdns_request { struct request *current_req; struct evdns_base *base; int pending_cb; /* Waiting for its callback to be invoked; not * owned by event base any more. */ /* elements used by the searching code */ int search_index; struct search_state *search_state; char *search_origname; /* needs to be free()ed */ int search_flags; }; struct request { u8 *request; /* the dns packet data */ u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */ unsigned int request_len; int reissue_count; int tx_count; /* the number of times that this packet has been sent */ void *user_pointer; /* the pointer given to us for this request */ evdns_callback_type user_callback; struct nameserver *ns; /* the server which we last sent it */ /* these objects are kept in a circular list */ /* XXX We could turn this into a CIRCLEQ. */ struct request *next, *prev; struct event timeout_event; u16 trans_id; /* the transaction id */ unsigned request_appended :1; /* true if the request pointer is data which follows this struct */ unsigned transmit_me :1; /* needs to be transmitted */ /* XXXX This is a horrible hack. */ char **put_cname_in_ptr; /* store the cname here if we get one. */ struct evdns_base *base; struct evdns_request *handle; }; struct reply { unsigned int type; unsigned int have_answer : 1; union { struct { u32 addrcount; u32 addresses[MAX_V4_ADDRS]; } a; struct { u32 addrcount; struct in6_addr addresses[MAX_V6_ADDRS]; } aaaa; struct { char name[HOST_NAME_MAX]; } ptr; } data; }; struct nameserver { evutil_socket_t socket; /* a connected UDP socket */ struct sockaddr_storage address; ev_socklen_t addrlen; int failed_times; /* number of times which we have given this server a chance */ int timedout; /* number of times in a row a request has timed out */ struct event event; /* these objects are kept in a circular list */ struct nameserver *next, *prev; struct event timeout_event; /* used to keep the timeout for */ /* when we next probe this server. */ /* Valid if state == 0 */ /* Outstanding probe request for this nameserver, if any */ struct evdns_request *probe_request; char state; /* zero if we think that this server is down */ char choked; /* true if we have an EAGAIN from this server's socket */ char write_waiting; /* true if we are waiting for EV_WRITE events */ struct evdns_base *base; /* Number of currently inflight requests: used * to track when we should add/del the event. */ int requests_inflight; }; /* Represents a local port where we're listening for DNS requests. Right now, */ /* only UDP is supported. */ struct evdns_server_port { evutil_socket_t socket; /* socket we use to read queries and write replies. */ int refcnt; /* reference count. */ char choked; /* Are we currently blocked from writing? */ char closing; /* Are we trying to close this port, pending writes? */ evdns_request_callback_fn_type user_callback; /* Fn to handle requests */ void *user_data; /* Opaque pointer passed to user_callback */ struct event event; /* Read/write event */ /* circular list of replies that we want to write. */ struct server_request *pending_replies; struct event_base *event_base; #ifndef EVENT__DISABLE_THREAD_SUPPORT void *lock; #endif }; /* Represents part of a reply being built. (That is, a single RR.) */ struct server_reply_item { struct server_reply_item *next; /* next item in sequence. */ char *name; /* name part of the RR */ u16 type; /* The RR type */ u16 class; /* The RR class (usually CLASS_INET) */ u32 ttl; /* The RR TTL */ char is_name; /* True iff data is a label */ u16 datalen; /* Length of data; -1 if data is a label */ void *data; /* The contents of the RR */ }; /* Represents a request that we've received as a DNS server, and holds */ /* the components of the reply as we're constructing it. */ struct server_request { /* Pointers to the next and previous entries on the list of replies */ /* that we're waiting to write. Only set if we have tried to respond */ /* and gotten EAGAIN. */ struct server_request *next_pending; struct server_request *prev_pending; u16 trans_id; /* Transaction id. */ struct evdns_server_port *port; /* Which port received this request on? */ struct sockaddr_storage addr; /* Where to send the response */ ev_socklen_t addrlen; /* length of addr */ int n_answer; /* how many answer RRs have been set? */ int n_authority; /* how many authority RRs have been set? */ int n_additional; /* how many additional RRs have been set? */ struct server_reply_item *answer; /* linked list of answer RRs */ struct server_reply_item *authority; /* linked list of authority RRs */ struct server_reply_item *additional; /* linked list of additional RRs */ /* Constructed response. Only set once we're ready to send a reply. */ /* Once this is set, the RR fields are cleared, and no more should be set. */ char *response; size_t response_len; /* Caller-visible fields: flags, questions. */ struct evdns_server_request base; }; struct evdns_base { /* An array of n_req_heads circular lists for inflight requests. * Each inflight request req is in req_heads[req->trans_id % n_req_heads]. */ struct request **req_heads; /* A circular list of requests that we're waiting to send, but haven't * sent yet because there are too many requests inflight */ struct request *req_waiting_head; /* A circular list of nameservers. */ struct nameserver *server_head; int n_req_heads; struct event_base *event_base; /* The number of good nameservers that we have */ int global_good_nameservers; /* inflight requests are contained in the req_head list */ /* and are actually going out across the network */ int global_requests_inflight; /* requests which aren't inflight are in the waiting list */ /* and are counted here */ int global_requests_waiting; int global_max_requests_inflight; struct timeval global_timeout; /* 5 seconds by default */ int global_max_reissues; /* a reissue occurs when we get some errors from the server */ int global_max_retransmits; /* number of times we'll retransmit a request which timed out */ /* number of timeouts in a row before we consider this server to be down */ int global_max_nameserver_timeout; /* true iff we will use the 0x20 hack to prevent poisoning attacks. */ int global_randomize_case; /* The first time that a nameserver fails, how long do we wait before * probing to see if it has returned? */ struct timeval global_nameserver_probe_initial_timeout; /** Port to bind to for outgoing DNS packets. */ struct sockaddr_storage global_outgoing_address; /** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */ ev_socklen_t global_outgoing_addrlen; struct timeval global_getaddrinfo_allow_skew; int so_rcvbuf; int so_sndbuf; int getaddrinfo_ipv4_timeouts; int getaddrinfo_ipv6_timeouts; int getaddrinfo_ipv4_answered; int getaddrinfo_ipv6_answered; struct search_state *global_search_state; TAILQ_HEAD(hosts_list, hosts_entry) hostsdb; #ifndef EVENT__DISABLE_THREAD_SUPPORT void *lock; #endif int disable_when_inactive; }; struct hosts_entry { TAILQ_ENTRY(hosts_entry) next; union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; } addr; int addrlen; char hostname[1]; }; static struct evdns_base *current_base = NULL; struct evdns_base * evdns_get_global_base(void) { return current_base; } /* Given a pointer to an evdns_server_request, get the corresponding */ /* server_request. */ #define TO_SERVER_REQUEST(base_ptr) \ ((struct server_request*) \ (((char*)(base_ptr) - evutil_offsetof(struct server_request, base)))) #define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads]) static struct nameserver *nameserver_pick(struct evdns_base *base); static void evdns_request_insert(struct request *req, struct request **head); static void evdns_request_remove(struct request *req, struct request **head); static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg); static int evdns_transmit(struct evdns_base *base); static int evdns_request_transmit(struct request *req); static void nameserver_send_probe(struct nameserver *const ns); static void search_request_finished(struct evdns_request *const); static int search_try_next(struct evdns_request *const req); static struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg); static void evdns_requests_pump_waiting_queue(struct evdns_base *base); static u16 transaction_id_pick(struct evdns_base *base); static struct request *request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *ptr); static void request_submit(struct request *const req); static int server_request_free(struct server_request *req); static void server_request_free_answers(struct server_request *req); static void server_port_free(struct evdns_server_port *port); static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg); static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename); static int evdns_base_set_option_impl(struct evdns_base *base, const char *option, const char *val, int flags); static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests); static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg); static int strtoint(const char *const str); #ifdef EVENT__DISABLE_THREAD_SUPPORT #define EVDNS_LOCK(base) EVUTIL_NIL_STMT_ #define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_ #define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_ #else #define EVDNS_LOCK(base) \ EVLOCK_LOCK((base)->lock, 0) #define EVDNS_UNLOCK(base) \ EVLOCK_UNLOCK((base)->lock, 0) #define ASSERT_LOCKED(base) \ EVLOCK_ASSERT_LOCKED((base)->lock) #endif static evdns_debug_log_fn_type evdns_log_fn = NULL; void evdns_set_log_fn(evdns_debug_log_fn_type fn) { evdns_log_fn = fn; } #ifdef __GNUC__ #define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3))) #else #define EVDNS_LOG_CHECK #endif static void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK; static void evdns_log_(int severity, const char *fmt, ...) { va_list args; va_start(args,fmt); if (evdns_log_fn) { char buf[512]; int is_warn = (severity == EVDNS_LOG_WARN); evutil_vsnprintf(buf, sizeof(buf), fmt, args); evdns_log_fn(is_warn, buf); } else { event_logv_(severity, NULL, fmt, args); } va_end(args); } #define log evdns_log_ /* This walks the list of inflight requests to find the */ /* one with a matching transaction id. Returns NULL on */ /* failure */ static struct request * request_find_from_trans_id(struct evdns_base *base, u16 trans_id) { struct request *req = REQ_HEAD(base, trans_id); struct request *const started_at = req; ASSERT_LOCKED(base); if (req) { do { if (req->trans_id == trans_id) return req; req = req->next; } while (req != started_at); } return NULL; } /* a libevent callback function which is called when a nameserver */ /* has gone down and we want to test if it has came back to life yet */ static void nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) { struct nameserver *const ns = (struct nameserver *) arg; (void)fd; (void)events; EVDNS_LOCK(ns->base); nameserver_send_probe(ns); EVDNS_UNLOCK(ns->base); } /* a libevent callback which is called when a nameserver probe (to see if */ /* it has come back to life) times out. We increment the count of failed_times */ /* and wait longer to send the next probe packet. */ static void nameserver_probe_failed(struct nameserver *const ns) { struct timeval timeout; int i; ASSERT_LOCKED(ns->base); (void) evtimer_del(&ns->timeout_event); if (ns->state == 1) { /* This can happen if the nameserver acts in a way which makes us mark */ /* it as bad and then starts sending good replies. */ return; } #define MAX_PROBE_TIMEOUT 3600 #define TIMEOUT_BACKOFF_FACTOR 3 memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout, sizeof(struct timeval)); for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) { timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR; timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR; if (timeout.tv_usec > 1000000) { timeout.tv_sec += timeout.tv_usec / 1000000; timeout.tv_usec %= 1000000; } } if (timeout.tv_sec > MAX_PROBE_TIMEOUT) { timeout.tv_sec = MAX_PROBE_TIMEOUT; timeout.tv_usec = 0; } ns->failed_times++; if (evtimer_add(&ns->timeout_event, &timeout) < 0) { char addrbuf[128]; log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf))); } } static void request_swap_ns(struct request *req, struct nameserver *ns) { if (ns && req->ns != ns) { EVUTIL_ASSERT(req->ns->requests_inflight > 0); req->ns->requests_inflight--; ns->requests_inflight++; req->ns = ns; } } /* called when a nameserver has been deemed to have failed. For example, too */ /* many packets have timed out etc */ static void nameserver_failed(struct nameserver *const ns, const char *msg) { struct request *req, *started_at; struct evdns_base *base = ns->base; int i; char addrbuf[128]; ASSERT_LOCKED(base); /* if this nameserver has already been marked as failed */ /* then don't do anything */ if (!ns->state) return; log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf)), msg); base->global_good_nameservers--; EVUTIL_ASSERT(base->global_good_nameservers >= 0); if (base->global_good_nameservers == 0) { log(EVDNS_LOG_MSG, "All nameservers have failed"); } ns->state = 0; ns->failed_times = 1; if (evtimer_add(&ns->timeout_event, &base->global_nameserver_probe_initial_timeout) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf))); /* ???? Do more? */ } /* walk the list of inflight requests to see if any can be reassigned to */ /* a different server. Requests in the waiting queue don't have a */ /* nameserver assigned yet */ /* if we don't have *any* good nameservers then there's no point */ /* trying to reassign requests to one */ if (!base->global_good_nameservers) return; for (i = 0; i < base->n_req_heads; ++i) { req = started_at = base->req_heads[i]; if (req) { do { if (req->tx_count == 0 && req->ns == ns) { /* still waiting to go out, can be moved */ /* to another server */ request_swap_ns(req, nameserver_pick(base)); } req = req->next; } while (req != started_at); } } } static void nameserver_up(struct nameserver *const ns) { char addrbuf[128]; ASSERT_LOCKED(ns->base); if (ns->state) return; log(EVDNS_LOG_MSG, "Nameserver %s is back up", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf))); evtimer_del(&ns->timeout_event); if (ns->probe_request) { evdns_cancel_request(ns->base, ns->probe_request); ns->probe_request = NULL; } ns->state = 1; ns->failed_times = 0; ns->timedout = 0; ns->base->global_good_nameservers++; } static void request_trans_id_set(struct request *const req, const u16 trans_id) { req->trans_id = trans_id; *((u16 *) req->request) = htons(trans_id); } /* Called to remove a request from a list and dealloc it. */ /* head is a pointer to the head of the list it should be */ /* removed from or NULL if the request isn't in a list. */ /* when free_handle is one, free the handle as well. */ static void request_finished(struct request *const req, struct request **head, int free_handle) { struct evdns_base *base = req->base; int was_inflight = (head != &base->req_waiting_head); EVDNS_LOCK(base); ASSERT_VALID_REQUEST(req); if (head) evdns_request_remove(req, head); log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req); if (was_inflight) { evtimer_del(&req->timeout_event); base->global_requests_inflight--; req->ns->requests_inflight--; } else { base->global_requests_waiting--; } /* it was initialized during request_new / evtimer_assign */ event_debug_unassign(&req->timeout_event); if (req->ns && req->ns->requests_inflight == 0 && req->base->disable_when_inactive) { event_del(&req->ns->event); evtimer_del(&req->ns->timeout_event); } if (!req->request_appended) { /* need to free the request data on it's own */ mm_free(req->request); } else { /* the request data is appended onto the header */ /* so everything gets free()ed when we: */ } if (req->handle) { EVUTIL_ASSERT(req->handle->current_req == req); if (free_handle) { search_request_finished(req->handle); req->handle->current_req = NULL; if (! req->handle->pending_cb) { /* If we're planning to run the callback, * don't free the handle until later. */ mm_free(req->handle); } req->handle = NULL; /* If we have a bug, let's crash * early */ } else { req->handle->current_req = NULL; } } mm_free(req); evdns_requests_pump_waiting_queue(base); EVDNS_UNLOCK(base); } /* This is called when a server returns a funny error code. */ /* We try the request again with another server. */ /* */ /* return: */ /* 0 ok */ /* 1 failed/reissue is pointless */ static int request_reissue(struct request *req) { const struct nameserver *const last_ns = req->ns; ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); /* the last nameserver should have been marked as failing */ /* by the caller of this function, therefore pick will try */ /* not to return it */ request_swap_ns(req, nameserver_pick(req->base)); if (req->ns == last_ns) { /* ... but pick did return it */ /* not a lot of point in trying again with the */ /* same server */ return 1; } req->reissue_count++; req->tx_count = 0; req->transmit_me = 1; return 0; } /* this function looks for space on the inflight queue and promotes */ /* requests from the waiting queue if it can. */ /* */ /* TODO: */ /* add return code, see at nameserver_pick() and other functions. */ static void evdns_requests_pump_waiting_queue(struct evdns_base *base) { ASSERT_LOCKED(base); while (base->global_requests_inflight < base->global_max_requests_inflight && base->global_requests_waiting) { struct request *req; EVUTIL_ASSERT(base->req_waiting_head); req = base->req_waiting_head; req->ns = nameserver_pick(base); if (!req->ns) return; /* move a request from the waiting queue to the inflight queue */ req->ns->requests_inflight++; evdns_request_remove(req, &base->req_waiting_head); base->global_requests_waiting--; base->global_requests_inflight++; request_trans_id_set(req, transaction_id_pick(base)); evdns_request_insert(req, &REQ_HEAD(base, req->trans_id)); evdns_request_transmit(req); evdns_transmit(base); } } /* TODO(nickm) document */ struct deferred_reply_callback { struct event_callback deferred; struct evdns_request *handle; u8 request_type; u8 have_reply; u32 ttl; u32 err; evdns_callback_type user_callback; struct reply reply; }; static void reply_run_callback(struct event_callback *d, void *user_pointer) { struct deferred_reply_callback *cb = EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred); switch (cb->request_type) { case TYPE_A: if (cb->have_reply) cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A, cb->reply.data.a.addrcount, cb->ttl, cb->reply.data.a.addresses, user_pointer); else cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); break; case TYPE_PTR: if (cb->have_reply) { char *name = cb->reply.data.ptr.name; cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl, &name, user_pointer); } else { cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); } break; case TYPE_AAAA: if (cb->have_reply) cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA, cb->reply.data.aaaa.addrcount, cb->ttl, cb->reply.data.aaaa.addresses, user_pointer); else cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); break; default: EVUTIL_ASSERT(0); } if (cb->handle && cb->handle->pending_cb) { mm_free(cb->handle); } mm_free(cb); } static void reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) { struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d)); if (!d) { event_warn("%s: Couldn't allocate space for deferred callback.", __func__); return; } ASSERT_LOCKED(req->base); d->request_type = req->request_type; d->user_callback = req->user_callback; d->ttl = ttl; d->err = err; if (reply) { d->have_reply = 1; memcpy(&d->reply, reply, sizeof(struct reply)); } if (req->handle) { req->handle->pending_cb = 1; d->handle = req->handle; } event_deferred_cb_init_( &d->deferred, event_get_priority(&req->timeout_event), reply_run_callback, req->user_pointer); event_deferred_cb_schedule_( req->base->event_base, &d->deferred); } #define _QR_MASK 0x8000U #define _OP_MASK 0x7800U #define _AA_MASK 0x0400U #define _TC_MASK 0x0200U #define _RD_MASK 0x0100U #define _RA_MASK 0x0080U #define _Z_MASK 0x0040U #define _AD_MASK 0x0020U #define _CD_MASK 0x0010U #define _RCODE_MASK 0x000fU #define _Z_MASK_DEPRECATED 0x0070U /* this processes a parsed reply packet */ static void reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) { int error; char addrbuf[128]; static const int error_codes[] = { DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED }; ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); if (flags & (_RCODE_MASK | _TC_MASK) || !reply || !reply->have_answer) { /* there was an error */ if (flags & _TC_MASK) { error = DNS_ERR_TRUNCATED; } else if (flags & _RCODE_MASK) { u16 error_code = (flags & _RCODE_MASK) - 1; if (error_code > 4) { error = DNS_ERR_UNKNOWN; } else { error = error_codes[error_code]; } } else if (reply && !reply->have_answer) { error = DNS_ERR_NODATA; } else { error = DNS_ERR_UNKNOWN; } switch (error) { case DNS_ERR_NOTIMPL: case DNS_ERR_REFUSED: /* we regard these errors as marking a bad nameserver */ if (req->reissue_count < req->base->global_max_reissues) { char msg[64]; evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)", error, evdns_err_to_string(error)); nameserver_failed(req->ns, msg); if (!request_reissue(req)) return; } break; case DNS_ERR_SERVERFAILED: /* rcode 2 (servfailed) sometimes means "we * are broken" and sometimes (with some binds) * means "that request was very confusing." * Treat this as a timeout, not a failure. */ log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver" "at %s; will allow the request to time out.", evutil_format_sockaddr_port_( (struct sockaddr *)&req->ns->address, addrbuf, sizeof(addrbuf))); /* Call the timeout function */ evdns_request_timeout_callback(0, 0, req); return; default: /* we got a good reply from the nameserver: it is up. */ if (req->handle == req->ns->probe_request) { /* Avoid double-free */ req->ns->probe_request = NULL; } nameserver_up(req->ns); } if (req->handle->search_state && req->request_type != TYPE_PTR) { /* if we have a list of domains to search in, * try the next one */ if (!search_try_next(req->handle)) { /* a new request was issued so this * request is finished and */ /* the user callback will be made when * that request (or a */ /* child of it) finishes. */ return; } } /* all else failed. Pass the failure up */ reply_schedule_callback(req, ttl, error, NULL); request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); } else { /* all ok, tell the user */ reply_schedule_callback(req, ttl, 0, reply); if (req->handle == req->ns->probe_request) req->ns->probe_request = NULL; /* Avoid double-free */ nameserver_up(req->ns); request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); } } static int name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { int name_end = -1; int j = *idx; int ptr_count = 0; #define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0) #define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0) #define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0) char *cp = name_out; const char *const end = name_out + name_out_len; /* Normally, names are a series of length prefixed strings terminated */ /* with a length of 0 (the lengths are u8's < 63). */ /* However, the length can start with a pair of 1 bits and that */ /* means that the next 14 bits are a pointer within the current */ /* packet. */ for (;;) { u8 label_len; GET8(label_len); if (!label_len) break; if (label_len & 0xc0) { u8 ptr_low; GET8(ptr_low); if (name_end < 0) name_end = j; j = (((int)label_len & 0x3f) << 8) + ptr_low; /* Make sure that the target offset is in-bounds. */ if (j < 0 || j >= length) return -1; /* If we've jumped more times than there are characters in the * message, we must have a loop. */ if (++ptr_count > length) return -1; continue; } if (label_len > 63) return -1; if (cp != name_out) { if (cp + 1 >= end) return -1; *cp++ = '.'; } if (cp + label_len >= end) return -1; if (j + label_len > length) return -1; memcpy(cp, packet + j, label_len); cp += label_len; j += label_len; } if (cp >= end) return -1; *cp = '\0'; if (name_end < 0) *idx = j; else *idx = name_end; return 0; err: return -1; } /* parses a raw request from a nameserver */ static int reply_parse(struct evdns_base *base, u8 *packet, int length) { int j = 0, k = 0; /* index into packet */ u16 t_; /* used by the macros */ u32 t32_; /* used by the macros */ char tmp_name[256], cmp_name[256]; /* used by the macros */ int name_matches = 0; u16 trans_id, questions, answers, authority, additional, datalength; u16 flags = 0; u32 ttl, ttl_r = 0xffffffff; struct reply reply; struct request *req = NULL; unsigned int i; ASSERT_LOCKED(base); GET16(trans_id); GET16(flags); GET16(questions); GET16(answers); GET16(authority); GET16(additional); (void) authority; /* suppress "unused variable" warnings. */ (void) additional; /* suppress "unused variable" warnings. */ req = request_find_from_trans_id(base, trans_id); if (!req) return -1; EVUTIL_ASSERT(req->base == base); memset(&reply, 0, sizeof(reply)); /* If it's not an answer, it doesn't correspond to any request. */ if (!(flags & _QR_MASK)) return -1; /* must be an answer */ if ((flags & (_RCODE_MASK|_TC_MASK)) && (flags & (_RCODE_MASK|_TC_MASK)) != DNS_ERR_NOTEXIST) { /* there was an error and it's not NXDOMAIN */ goto err; } /* if (!answers) return; */ /* must have an answer of some form */ /* This macro skips a name in the DNS reply. */ #define SKIP_NAME \ do { tmp_name[0] = '\0'; \ if (name_parse(packet, length, &j, tmp_name, \ sizeof(tmp_name))<0) \ goto err; \ } while (0) reply.type = req->request_type; /* skip over each question in the reply */ for (i = 0; i < questions; ++i) { /* the question looks like * */ tmp_name[0] = '\0'; cmp_name[0] = '\0'; k = j; if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0) goto err; if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0) goto err; if (!base->global_randomize_case) { if (strcmp(tmp_name, cmp_name) == 0) name_matches = 1; } else { if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) name_matches = 1; } j += 4; if (j > length) goto err; } if (!name_matches) goto err; /* now we have the answer section which looks like * */ for (i = 0; i < answers; ++i) { u16 type, class; SKIP_NAME; GET16(type); GET16(class); GET32(ttl); GET16(datalength); if (type == TYPE_A && class == CLASS_INET) { int addrcount, addrtocopy; if (req->request_type != TYPE_A) { j += datalength; continue; } if ((datalength & 3) != 0) /* not an even number of As. */ goto err; addrcount = datalength >> 2; addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount); ttl_r = MIN(ttl_r, ttl); /* we only bother with the first four addresses. */ if (j + 4*addrtocopy > length) goto err; memcpy(&reply.data.a.addresses[reply.data.a.addrcount], packet + j, 4*addrtocopy); j += 4*addrtocopy; reply.data.a.addrcount += addrtocopy; reply.have_answer = 1; if (reply.data.a.addrcount == MAX_V4_ADDRS) break; } else if (type == TYPE_PTR && class == CLASS_INET) { if (req->request_type != TYPE_PTR) { j += datalength; continue; } if (name_parse(packet, length, &j, reply.data.ptr.name, sizeof(reply.data.ptr.name))<0) goto err; ttl_r = MIN(ttl_r, ttl); reply.have_answer = 1; break; } else if (type == TYPE_CNAME) { char cname[HOST_NAME_MAX]; if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) { j += datalength; continue; } if (name_parse(packet, length, &j, cname, sizeof(cname))<0) goto err; *req->put_cname_in_ptr = mm_strdup(cname); } else if (type == TYPE_AAAA && class == CLASS_INET) { int addrcount, addrtocopy; if (req->request_type != TYPE_AAAA) { j += datalength; continue; } if ((datalength & 15) != 0) /* not an even number of AAAAs. */ goto err; addrcount = datalength >> 4; /* each address is 16 bytes long */ addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount); ttl_r = MIN(ttl_r, ttl); /* we only bother with the first four addresses. */ if (j + 16*addrtocopy > length) goto err; memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount], packet + j, 16*addrtocopy); reply.data.aaaa.addrcount += addrtocopy; j += 16*addrtocopy; reply.have_answer = 1; if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break; } else { /* skip over any other type of resource */ j += datalength; } } if (!reply.have_answer) { for (i = 0; i < authority; ++i) { u16 type, class; SKIP_NAME; GET16(type); GET16(class); GET32(ttl); GET16(datalength); if (type == TYPE_SOA && class == CLASS_INET) { u32 serial, refresh, retry, expire, minimum; SKIP_NAME; SKIP_NAME; GET32(serial); GET32(refresh); GET32(retry); GET32(expire); GET32(minimum); (void)expire; (void)retry; (void)refresh; (void)serial; ttl_r = MIN(ttl_r, ttl); ttl_r = MIN(ttl_r, minimum); } else { /* skip over any other type of resource */ j += datalength; } } } if (ttl_r == 0xffffffff) ttl_r = 0; reply_handle(req, flags, ttl_r, &reply); return 0; err: if (req) reply_handle(req, flags, 0, NULL); return -1; } /* Parse a raw request (packet,length) sent to a nameserver port (port) from */ /* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */ /* callback. */ static int request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen) { int j = 0; /* index into packet */ u16 t_; /* used by the macros */ char tmp_name[256]; /* used by the macros */ int i; u16 trans_id, flags, questions, answers, authority, additional; struct server_request *server_req = NULL; ASSERT_LOCKED(port); /* Get the header fields */ GET16(trans_id); GET16(flags); GET16(questions); GET16(answers); GET16(authority); GET16(additional); (void)answers; (void)additional; (void)authority; if (flags & _QR_MASK) return -1; /* Must not be an answer. */ flags &= (_RD_MASK|_CD_MASK); /* Only RD and CD get preserved. */ server_req = mm_malloc(sizeof(struct server_request)); if (server_req == NULL) return -1; memset(server_req, 0, sizeof(struct server_request)); server_req->trans_id = trans_id; memcpy(&server_req->addr, addr, addrlen); server_req->addrlen = addrlen; server_req->base.flags = flags; server_req->base.nquestions = 0; server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions); if (server_req->base.questions == NULL) goto err; for (i = 0; i < questions; ++i) { u16 type, class; struct evdns_server_question *q; int namelen; if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) goto err; GET16(type); GET16(class); namelen = (int)strlen(tmp_name); q = mm_malloc(sizeof(struct evdns_server_question) + namelen); if (!q) goto err; q->type = type; q->dns_question_class = class; memcpy(q->name, tmp_name, namelen+1); server_req->base.questions[server_req->base.nquestions++] = q; } /* Ignore answers, authority, and additional. */ server_req->port = port; port->refcnt++; /* Only standard queries are supported. */ if (flags & _OP_MASK) { evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL); return -1; } port->user_callback(&(server_req->base), port->user_data); return 0; err: if (server_req->base.questions) { for (i = 0; i < server_req->base.nquestions; ++i) mm_free(server_req->base.questions[i]); mm_free(server_req->base.questions); } mm_free(server_req); return -1; #undef SKIP_NAME #undef GET32 #undef GET16 #undef GET8 } void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)) { } void evdns_set_random_bytes_fn(void (*fn)(char *, size_t)) { } /* Try to choose a strong transaction id which isn't already in flight */ static u16 transaction_id_pick(struct evdns_base *base) { ASSERT_LOCKED(base); for (;;) { u16 trans_id; evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id)); if (trans_id == 0xffff) continue; /* now check to see if that id is already inflight */ if (request_find_from_trans_id(base, trans_id) == NULL) return trans_id; } } /* choose a namesever to use. This function will try to ignore */ /* nameservers which we think are down and load balance across the rest */ /* by updating the server_head global each time. */ static struct nameserver * nameserver_pick(struct evdns_base *base) { struct nameserver *started_at = base->server_head, *picked; ASSERT_LOCKED(base); if (!base->server_head) return NULL; /* if we don't have any good nameservers then there's no */ /* point in trying to find one. */ if (!base->global_good_nameservers) { base->server_head = base->server_head->next; return base->server_head; } /* remember that nameservers are in a circular list */ for (;;) { if (base->server_head->state) { /* we think this server is currently good */ picked = base->server_head; base->server_head = base->server_head->next; return picked; } base->server_head = base->server_head->next; if (base->server_head == started_at) { /* all the nameservers seem to be down */ /* so we just return this one and hope for the */ /* best */ EVUTIL_ASSERT(base->global_good_nameservers == 0); picked = base->server_head; base->server_head = base->server_head->next; return picked; } } } /* this is called when a namesever socket is ready for reading */ static void nameserver_read(struct nameserver *ns) { struct sockaddr_storage ss; ev_socklen_t addrlen = sizeof(ss); u8 packet[1500]; char addrbuf[128]; ASSERT_LOCKED(ns->base); for (;;) { const int r = recvfrom(ns->socket, (void*)packet, sizeof(packet), 0, (struct sockaddr*)&ss, &addrlen); if (r < 0) { int err = evutil_socket_geterror(ns->socket); if (EVUTIL_ERR_RW_RETRIABLE(err)) return; nameserver_failed(ns, evutil_socket_error_to_string(err)); return; } if (evutil_sockaddr_cmp((struct sockaddr*)&ss, (struct sockaddr*)&ns->address, 0)) { log(EVDNS_LOG_WARN, "Address mismatch on received " "DNS packet. Apparent source was %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ss, addrbuf, sizeof(addrbuf))); return; } ns->timedout = 0; reply_parse(ns->base, packet, r); } } /* Read a packet from a DNS client on a server port s, parse it, and */ /* act accordingly. */ static void server_port_read(struct evdns_server_port *s) { u8 packet[1500]; struct sockaddr_storage addr; ev_socklen_t addrlen; int r; ASSERT_LOCKED(s); for (;;) { addrlen = sizeof(struct sockaddr_storage); r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0, (struct sockaddr*) &addr, &addrlen); if (r < 0) { int err = evutil_socket_geterror(s->socket); if (EVUTIL_ERR_RW_RETRIABLE(err)) return; log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.", evutil_socket_error_to_string(err), err); return; } request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen); } } /* Try to write all pending replies on a given DNS server port. */ static void server_port_flush(struct evdns_server_port *port) { struct server_request *req = port->pending_replies; ASSERT_LOCKED(port); while (req) { int r = sendto(port->socket, req->response, (int)req->response_len, 0, (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen); if (r < 0) { int err = evutil_socket_geterror(port->socket); if (EVUTIL_ERR_RW_RETRIABLE(err)) return; log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err); } if (server_request_free(req)) { /* we released the last reference to req->port. */ return; } else { EVUTIL_ASSERT(req != port->pending_replies); req = port->pending_replies; } } /* We have no more pending requests; stop listening for 'writeable' events. */ (void) event_del(&port->event); event_assign(&port->event, port->event_base, port->socket, EV_READ | EV_PERSIST, server_port_ready_callback, port); if (event_add(&port->event, NULL) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); /* ???? Do more? */ } } /* set if we are waiting for the ability to write to this server. */ /* if waiting is true then we ask libevent for EV_WRITE events, otherwise */ /* we stop these events. */ static void nameserver_write_waiting(struct nameserver *ns, char waiting) { ASSERT_LOCKED(ns->base); if (ns->write_waiting == waiting) return; ns->write_waiting = waiting; (void) event_del(&ns->event); event_assign(&ns->event, ns->base->event_base, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST, nameserver_ready_callback, ns); if (event_add(&ns->event, NULL) < 0) { char addrbuf[128]; log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf))); /* ???? Do more? */ } } /* a callback function. Called by libevent when the kernel says that */ /* a nameserver socket is ready for writing or reading */ static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) { struct nameserver *ns = (struct nameserver *) arg; (void)fd; EVDNS_LOCK(ns->base); if (events & EV_WRITE) { ns->choked = 0; if (!evdns_transmit(ns->base)) { nameserver_write_waiting(ns, 0); } } if (events & EV_READ) { nameserver_read(ns); } EVDNS_UNLOCK(ns->base); } /* a callback function. Called by libevent when the kernel says that */ /* a server socket is ready for writing or reading. */ static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg) { struct evdns_server_port *port = (struct evdns_server_port *) arg; (void) fd; EVDNS_LOCK(port); if (events & EV_WRITE) { port->choked = 0; server_port_flush(port); } if (events & EV_READ) { server_port_read(port); } EVDNS_UNLOCK(port); } /* This is an inefficient representation; only use it via the dnslabel_table_* * functions, so that is can be safely replaced with something smarter later. */ #define MAX_LABELS 128 /* Structures used to implement name compression */ struct dnslabel_entry { char *v; off_t pos; }; struct dnslabel_table { int n_labels; /* number of current entries */ /* map from name to position in message */ struct dnslabel_entry labels[MAX_LABELS]; }; /* Initialize dnslabel_table. */ static void dnslabel_table_init(struct dnslabel_table *table) { table->n_labels = 0; } /* Free all storage held by table, but not the table itself. */ static void dnslabel_clear(struct dnslabel_table *table) { int i; for (i = 0; i < table->n_labels; ++i) mm_free(table->labels[i].v); table->n_labels = 0; } /* return the position of the label in the current message, or -1 if the label */ /* hasn't been used yet. */ static int dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label) { int i; for (i = 0; i < table->n_labels; ++i) { if (!strcmp(label, table->labels[i].v)) return table->labels[i].pos; } return -1; } /* remember that we've used the label at position pos */ static int dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos) { char *v; int p; if (table->n_labels == MAX_LABELS) return (-1); v = mm_strdup(label); if (v == NULL) return (-1); p = table->n_labels++; table->labels[p].v = v; table->labels[p].pos = pos; return (0); } /* Converts a string to a length-prefixed set of DNS labels, starting */ /* at buf[j]. name and buf must not overlap. name_len should be the length */ /* of name. table is optional, and is used for compression. */ /* */ /* Input: abc.def */ /* Output: <3>abc<3>def<0> */ /* */ /* Returns the first index after the encoded name, or negative on error. */ /* -1 label was > 63 bytes */ /* -2 name too long to fit in buffer. */ /* */ static off_t dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j, const char *name, const size_t name_len, struct dnslabel_table *table) { const char *end = name + name_len; int ref = 0; u16 t_; #define APPEND16(x) do { \ if (j + 2 > (off_t)buf_len) \ goto overflow; \ t_ = htons(x); \ memcpy(buf + j, &t_, 2); \ j += 2; \ } while (0) #define APPEND32(x) do { \ if (j + 4 > (off_t)buf_len) \ goto overflow; \ t32_ = htonl(x); \ memcpy(buf + j, &t32_, 4); \ j += 4; \ } while (0) if (name_len > 255) return -2; for (;;) { const char *const start = name; if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) { APPEND16(ref | 0xc000); return j; } name = strchr(name, '.'); if (!name) { const size_t label_len = end - start; if (label_len > 63) return -1; if ((size_t)(j+label_len+1) > buf_len) return -2; if (table) dnslabel_table_add(table, start, j); buf[j++] = (ev_uint8_t)label_len; memcpy(buf + j, start, label_len); j += (int) label_len; break; } else { /* append length of the label. */ const size_t label_len = name - start; if (label_len > 63) return -1; if ((size_t)(j+label_len+1) > buf_len) return -2; if (table) dnslabel_table_add(table, start, j); buf[j++] = (ev_uint8_t)label_len; memcpy(buf + j, start, label_len); j += (int) label_len; /* hop over the '.' */ name++; } } /* the labels must be terminated by a 0. */ /* It's possible that the name ended in a . */ /* in which case the zero is already there */ if (!j || buf[j-1]) buf[j++] = 0; return j; overflow: return (-2); } /* Finds the length of a dns request for a DNS name of the given */ /* length. The actual request may be smaller than the value returned */ /* here */ static size_t evdns_request_len(const size_t name_len) { return 96 + /* length of the DNS standard header */ name_len + 2 + 4; /* space for the resource type */ } /* build a dns request packet into buf. buf should be at least as long */ /* as evdns_request_len told you it should be. */ /* */ /* Returns the amount of space used. Negative on error. */ static int evdns_request_data_build(const char *const name, const size_t name_len, const u16 trans_id, const u16 type, const u16 class, u8 *const buf, size_t buf_len) { off_t j = 0; /* current offset into buf */ u16 t_; /* used by the macros */ APPEND16(trans_id); APPEND16(0x0100); /* standard query, recusion needed */ APPEND16(1); /* one question */ APPEND16(0); /* no answers */ APPEND16(0); /* no authority */ APPEND16(0); /* no additional */ j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL); if (j < 0) { return (int)j; } APPEND16(type); APPEND16(class); return (int)j; overflow: return (-1); } /* exported function */ struct evdns_server_port * evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data) { struct evdns_server_port *port; if (flags) return NULL; /* flags not yet implemented */ if (!(port = mm_malloc(sizeof(struct evdns_server_port)))) return NULL; memset(port, 0, sizeof(struct evdns_server_port)); port->socket = socket; port->refcnt = 1; port->choked = 0; port->closing = 0; port->user_callback = cb; port->user_data = user_data; port->pending_replies = NULL; port->event_base = base; event_assign(&port->event, port->event_base, port->socket, EV_READ | EV_PERSIST, server_port_ready_callback, port); if (event_add(&port->event, NULL) < 0) { mm_free(port); return NULL; } EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE); return port; } struct evdns_server_port * evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data) { return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data); } /* exported function */ void evdns_close_server_port(struct evdns_server_port *port) { EVDNS_LOCK(port); if (--port->refcnt == 0) { EVDNS_UNLOCK(port); server_port_free(port); } else { port->closing = 1; EVDNS_UNLOCK(port); } } /* exported function */ int evdns_server_request_add_reply(struct evdns_server_request *req_, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data) { struct server_request *req = TO_SERVER_REQUEST(req_); struct server_reply_item **itemp, *item; int *countp; int result = -1; EVDNS_LOCK(req->port); if (req->response) /* have we already answered? */ goto done; switch (section) { case EVDNS_ANSWER_SECTION: itemp = &req->answer; countp = &req->n_answer; break; case EVDNS_AUTHORITY_SECTION: itemp = &req->authority; countp = &req->n_authority; break; case EVDNS_ADDITIONAL_SECTION: itemp = &req->additional; countp = &req->n_additional; break; default: goto done; } while (*itemp) { itemp = &((*itemp)->next); } item = mm_malloc(sizeof(struct server_reply_item)); if (!item) goto done; item->next = NULL; if (!(item->name = mm_strdup(name))) { mm_free(item); goto done; } item->type = type; item->dns_question_class = class; item->ttl = ttl; item->is_name = is_name != 0; item->datalen = 0; item->data = NULL; if (data) { if (item->is_name) { if (!(item->data = mm_strdup(data))) { mm_free(item->name); mm_free(item); goto done; } item->datalen = (u16)-1; } else { if (!(item->data = mm_malloc(datalen))) { mm_free(item->name); mm_free(item); goto done; } item->datalen = datalen; memcpy(item->data, data, datalen); } } *itemp = item; ++(*countp); result = 0; done: EVDNS_UNLOCK(req->port); return result; } /* exported function */ int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl) { return evdns_server_request_add_reply( req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, ttl, n*4, 0, addrs); } /* exported function */ int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl) { return evdns_server_request_add_reply( req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET, ttl, n*16, 0, addrs); } /* exported function */ int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl) { u32 a; char buf[32]; if (in && inaddr_name) return -1; else if (!in && !inaddr_name) return -1; if (in) { a = ntohl(in->s_addr); evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", (int)(u8)((a )&0xff), (int)(u8)((a>>8 )&0xff), (int)(u8)((a>>16)&0xff), (int)(u8)((a>>24)&0xff)); inaddr_name = buf; } return evdns_server_request_add_reply( req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET, ttl, -1, 1, hostname); } /* exported function */ int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl) { return evdns_server_request_add_reply( req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET, ttl, -1, 1, cname); } /* exported function */ void evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags) { struct server_request *req = TO_SERVER_REQUEST(exreq); req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD); req->base.flags |= flags; } static int evdns_server_request_format_response(struct server_request *req, int err) { unsigned char buf[1500]; size_t buf_len = sizeof(buf); off_t j = 0, r; u16 t_; u32 t32_; int i; u16 flags; struct dnslabel_table table; if (err < 0 || err > 15) return -1; /* Set response bit and error code; copy OPCODE and RD fields from * question; copy RA and AA if set by caller. */ flags = req->base.flags; flags |= (_QR_MASK | err); dnslabel_table_init(&table); APPEND16(req->trans_id); APPEND16(flags); APPEND16(req->base.nquestions); APPEND16(req->n_answer); APPEND16(req->n_authority); APPEND16(req->n_additional); /* Add questions. */ for (i=0; i < req->base.nquestions; ++i) { const char *s = req->base.questions[i]->name; j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table); if (j < 0) { dnslabel_clear(&table); return (int) j; } APPEND16(req->base.questions[i]->type); APPEND16(req->base.questions[i]->dns_question_class); } /* Add answer, authority, and additional sections. */ for (i=0; i<3; ++i) { struct server_reply_item *item; if (i==0) item = req->answer; else if (i==1) item = req->authority; else item = req->additional; while (item) { r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table); if (r < 0) goto overflow; j = r; APPEND16(item->type); APPEND16(item->dns_question_class); APPEND32(item->ttl); if (item->is_name) { off_t len_idx = j, name_start; j += 2; name_start = j; r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table); if (r < 0) goto overflow; j = r; t_ = htons( (short) (j-name_start) ); memcpy(buf+len_idx, &t_, 2); } else { APPEND16(item->datalen); if (j+item->datalen > (off_t)buf_len) goto overflow; memcpy(buf+j, item->data, item->datalen); j += item->datalen; } item = item->next; } } if (j > 512) { overflow: j = 512; buf[2] |= 0x02; /* set the truncated bit. */ } req->response_len = j; if (!(req->response = mm_malloc(req->response_len))) { server_request_free_answers(req); dnslabel_clear(&table); return (-1); } memcpy(req->response, buf, req->response_len); server_request_free_answers(req); dnslabel_clear(&table); return (0); } /* exported function */ int evdns_server_request_respond(struct evdns_server_request *req_, int err) { struct server_request *req = TO_SERVER_REQUEST(req_); struct evdns_server_port *port = req->port; int r = -1; EVDNS_LOCK(port); if (!req->response) { if ((r = evdns_server_request_format_response(req, err))<0) goto done; } r = sendto(port->socket, req->response, (int)req->response_len, 0, (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen); if (r<0) { int sock_err = evutil_socket_geterror(port->socket); if (EVUTIL_ERR_RW_RETRIABLE(sock_err)) goto done; if (port->pending_replies) { req->prev_pending = port->pending_replies->prev_pending; req->next_pending = port->pending_replies; req->prev_pending->next_pending = req->next_pending->prev_pending = req; } else { req->prev_pending = req->next_pending = req; port->pending_replies = req; port->choked = 1; (void) event_del(&port->event); event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port); if (event_add(&port->event, NULL) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); } } r = 1; goto done; } if (server_request_free(req)) { r = 0; goto done; } if (port->pending_replies) server_port_flush(port); r = 0; done: EVDNS_UNLOCK(port); return r; } /* Free all storage held by RRs in req. */ static void server_request_free_answers(struct server_request *req) { struct server_reply_item *victim, *next, **list; int i; for (i = 0; i < 3; ++i) { if (i==0) list = &req->answer; else if (i==1) list = &req->authority; else list = &req->additional; victim = *list; while (victim) { next = victim->next; mm_free(victim->name); if (victim->data) mm_free(victim->data); mm_free(victim); victim = next; } *list = NULL; } } /* Free all storage held by req, and remove links to it. */ /* return true iff we just wound up freeing the server_port. */ static int server_request_free(struct server_request *req) { int i, rc=1, lock=0; if (req->base.questions) { for (i = 0; i < req->base.nquestions; ++i) mm_free(req->base.questions[i]); mm_free(req->base.questions); } if (req->port) { EVDNS_LOCK(req->port); lock=1; if (req->port->pending_replies == req) { if (req->next_pending && req->next_pending != req) req->port->pending_replies = req->next_pending; else req->port->pending_replies = NULL; } rc = --req->port->refcnt; } if (req->response) { mm_free(req->response); } server_request_free_answers(req); if (req->next_pending && req->next_pending != req) { req->next_pending->prev_pending = req->prev_pending; req->prev_pending->next_pending = req->next_pending; } if (rc == 0) { EVDNS_UNLOCK(req->port); /* ????? nickm */ server_port_free(req->port); mm_free(req); return (1); } if (lock) EVDNS_UNLOCK(req->port); mm_free(req); return (0); } /* Free all storage held by an evdns_server_port. Only called when */ static void server_port_free(struct evdns_server_port *port) { EVUTIL_ASSERT(port); EVUTIL_ASSERT(!port->refcnt); EVUTIL_ASSERT(!port->pending_replies); if (port->socket > 0) { evutil_closesocket(port->socket); port->socket = -1; } (void) event_del(&port->event); event_debug_unassign(&port->event); EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE); mm_free(port); } /* exported function */ int evdns_server_request_drop(struct evdns_server_request *req_) { struct server_request *req = TO_SERVER_REQUEST(req_); server_request_free(req); return 0; } /* exported function */ int evdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len) { struct server_request *req = TO_SERVER_REQUEST(req_); if (addr_len < (int)req->addrlen) return -1; memcpy(sa, &(req->addr), req->addrlen); return req->addrlen; } #undef APPEND16 #undef APPEND32 /* this is a libevent callback function which is called when a request */ /* has timed out. */ static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) { struct request *const req = (struct request *) arg; struct evdns_base *base = req->base; (void) fd; (void) events; log(EVDNS_LOG_DEBUG, "Request %p timed out", arg); EVDNS_LOCK(base); if (req->tx_count >= req->base->global_max_retransmits) { struct nameserver *ns = req->ns; /* this request has failed */ log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d", arg, req->tx_count); reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL); request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); nameserver_failed(ns, "request timed out."); } else { /* retransmit it */ log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d", arg, req->tx_count); (void) evtimer_del(&req->timeout_event); request_swap_ns(req, nameserver_pick(base)); evdns_request_transmit(req); req->ns->timedout++; if (req->ns->timedout > req->base->global_max_nameserver_timeout) { req->ns->timedout = 0; nameserver_failed(req->ns, "request timed out."); } } EVDNS_UNLOCK(base); } /* try to send a request to a given server. */ /* */ /* return: */ /* 0 ok */ /* 1 temporary failure */ /* 2 other failure */ static int evdns_request_transmit_to(struct request *req, struct nameserver *server) { int r; ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); if (server->requests_inflight == 1 && req->base->disable_when_inactive && event_add(&server->event, NULL) < 0) { return 1; } r = sendto(server->socket, (void*)req->request, req->request_len, 0, (struct sockaddr *)&server->address, server->addrlen); if (r < 0) { int err = evutil_socket_geterror(server->socket); if (EVUTIL_ERR_RW_RETRIABLE(err)) return 1; nameserver_failed(req->ns, evutil_socket_error_to_string(err)); return 2; } else if (r != (int)req->request_len) { return 1; /* short write */ } else { return 0; } } /* try to send a request, updating the fields of the request */ /* as needed */ /* */ /* return: */ /* 0 ok */ /* 1 failed */ static int evdns_request_transmit(struct request *req) { int retcode = 0, r; ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); /* if we fail to send this packet then this flag marks it */ /* for evdns_transmit */ req->transmit_me = 1; EVUTIL_ASSERT(req->trans_id != 0xffff); if (!req->ns) { /* unable to transmit request if no nameservers */ return 1; } if (req->ns->choked) { /* don't bother trying to write to a socket */ /* which we have had EAGAIN from */ return 1; } r = evdns_request_transmit_to(req, req->ns); switch (r) { case 1: /* temp failure */ req->ns->choked = 1; nameserver_write_waiting(req->ns, 1); return 1; case 2: /* failed to transmit the request entirely. we can fallthrough since * we'll set a timeout, which will time out, and make us retransmit the * request anyway. */ retcode = 1; EVUTIL_FALLTHROUGH; default: /* all ok */ log(EVDNS_LOG_DEBUG, "Setting timeout for request %p, sent to nameserver %p", req, req->ns); if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding timer for request %p", req); /* ???? Do more? */ } req->tx_count++; req->transmit_me = 0; return retcode; } } static void nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { struct nameserver *const ns = (struct nameserver *) arg; (void) type; (void) count; (void) ttl; (void) addresses; if (result == DNS_ERR_CANCEL) { /* We canceled this request because the nameserver came up * for some other reason. Do not change our opinion about * the nameserver. */ return; } EVDNS_LOCK(ns->base); ns->probe_request = NULL; if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) { /* this is a good reply */ nameserver_up(ns); } else { nameserver_probe_failed(ns); } EVDNS_UNLOCK(ns->base); } static void nameserver_send_probe(struct nameserver *const ns) { struct evdns_request *handle; struct request *req; char addrbuf[128]; /* here we need to send a probe to a given nameserver */ /* in the hope that it is up now. */ ASSERT_LOCKED(ns->base); log(EVDNS_LOG_DEBUG, "Sending probe to %s", evutil_format_sockaddr_port_( (struct sockaddr *)&ns->address, addrbuf, sizeof(addrbuf))); handle = mm_calloc(1, sizeof(*handle)); if (!handle) return; req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns); if (!req) { mm_free(handle); return; } ns->probe_request = handle; /* we force this into the inflight queue no matter what */ request_trans_id_set(req, transaction_id_pick(ns->base)); req->ns = ns; request_submit(req); } /* returns: */ /* 0 didn't try to transmit anything */ /* 1 tried to transmit something */ static int evdns_transmit(struct evdns_base *base) { char did_try_to_transmit = 0; int i; ASSERT_LOCKED(base); for (i = 0; i < base->n_req_heads; ++i) { if (base->req_heads[i]) { struct request *const started_at = base->req_heads[i], *req = started_at; /* first transmit all the requests which are currently waiting */ do { if (req->transmit_me) { did_try_to_transmit = 1; evdns_request_transmit(req); } req = req->next; } while (req != started_at); } } return did_try_to_transmit; } /* exported function */ int evdns_base_count_nameservers(struct evdns_base *base) { const struct nameserver *server; int n = 0; EVDNS_LOCK(base); server = base->server_head; if (!server) goto done; do { ++n; server = server->next; } while (server != base->server_head); done: EVDNS_UNLOCK(base); return n; } int evdns_count_nameservers(void) { return evdns_base_count_nameservers(current_base); } /* exported function */ int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base) { struct nameserver *server, *started_at; int i; EVDNS_LOCK(base); server = base->server_head; started_at = base->server_head; if (!server) { EVDNS_UNLOCK(base); return 0; } while (1) { struct nameserver *next = server->next; (void) event_del(&server->event); if (evtimer_initialized(&server->timeout_event)) (void) evtimer_del(&server->timeout_event); if (server->probe_request) { evdns_cancel_request(server->base, server->probe_request); server->probe_request = NULL; } if (server->socket >= 0) evutil_closesocket(server->socket); mm_free(server); if (next == started_at) break; server = next; } base->server_head = NULL; base->global_good_nameservers = 0; for (i = 0; i < base->n_req_heads; ++i) { struct request *req, *req_started_at; req = req_started_at = base->req_heads[i]; while (req) { struct request *next = req->next; req->tx_count = req->reissue_count = 0; req->ns = NULL; /* ???? What to do about searches? */ (void) evtimer_del(&req->timeout_event); req->trans_id = 0; req->transmit_me = 0; base->global_requests_waiting++; evdns_request_insert(req, &base->req_waiting_head); /* We want to insert these suspended elements at the front of * the waiting queue, since they were pending before any of * the waiting entries were added. This is a circular list, * so we can just shift the start back by one.*/ base->req_waiting_head = base->req_waiting_head->prev; if (next == req_started_at) break; req = next; } base->req_heads[i] = NULL; } base->global_requests_inflight = 0; EVDNS_UNLOCK(base); return 0; } int evdns_clear_nameservers_and_suspend(void) { return evdns_base_clear_nameservers_and_suspend(current_base); } /* exported function */ int evdns_base_resume(struct evdns_base *base) { EVDNS_LOCK(base); evdns_requests_pump_waiting_queue(base); EVDNS_UNLOCK(base); return 0; } int evdns_resume(void) { return evdns_base_resume(current_base); } static int evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) { /* first check to see if we already have this nameserver */ const struct nameserver *server = base->server_head, *const started_at = base->server_head; struct nameserver *ns; int err = 0; char addrbuf[128]; ASSERT_LOCKED(base); if (server) { do { if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3; server = server->next; } while (server != started_at); } if (addrlen > (int)sizeof(ns->address)) { log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen); return 2; } ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver)); if (!ns) return -1; memset(ns, 0, sizeof(struct nameserver)); ns->base = base; evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns); ns->socket = evutil_socket_(address->sa_family, SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0); if (ns->socket < 0) { err = 1; goto out1; } if (base->global_outgoing_addrlen && !evutil_sockaddr_is_loopback_(address)) { if (bind(ns->socket, (struct sockaddr*)&base->global_outgoing_address, base->global_outgoing_addrlen) < 0) { log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address"); err = 2; goto out2; } } if (base->so_rcvbuf) { if (setsockopt(ns->socket, SOL_SOCKET, SO_RCVBUF, (void *)&base->so_rcvbuf, sizeof(base->so_rcvbuf))) { log(EVDNS_LOG_WARN, "Couldn't set SO_RCVBUF to %i", base->so_rcvbuf); err = -SO_RCVBUF; goto out2; } } if (base->so_sndbuf) { if (setsockopt(ns->socket, SOL_SOCKET, SO_SNDBUF, (void *)&base->so_sndbuf, sizeof(base->so_sndbuf))) { log(EVDNS_LOG_WARN, "Couldn't set SO_SNDBUF to %i", base->so_sndbuf); err = -SO_SNDBUF; goto out2; } } memcpy(&ns->address, address, addrlen); ns->addrlen = addrlen; ns->state = 1; event_assign(&ns->event, ns->base->event_base, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns); if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) { err = 2; goto out2; } log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p", evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns); /* insert this nameserver into the list of them */ if (!base->server_head) { ns->next = ns->prev = ns; base->server_head = ns; } else { ns->next = base->server_head->next; ns->prev = base->server_head; base->server_head->next = ns; ns->next->prev = ns; } base->global_good_nameservers++; return 0; out2: evutil_closesocket(ns->socket); out1: event_debug_unassign(&ns->event); mm_free(ns); log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err); return err; } /* exported function */ int evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address) { struct sockaddr_in sin; int res; memset(&sin, 0, sizeof(sin)); sin.sin_addr.s_addr = address; sin.sin_port = htons(53); sin.sin_family = AF_INET; EVDNS_LOCK(base); res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin)); EVDNS_UNLOCK(base); return res; } int evdns_nameserver_add(unsigned long int address) { if (!current_base) current_base = evdns_base_new(NULL, 0); return evdns_base_nameserver_add(current_base, address); } static void sockaddr_setport(struct sockaddr *sa, ev_uint16_t port) { if (sa->sa_family == AF_INET) { ((struct sockaddr_in *)sa)->sin_port = htons(port); } else if (sa->sa_family == AF_INET6) { ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); } } static ev_uint16_t sockaddr_getport(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return ntohs(((struct sockaddr_in *)sa)->sin_port); } else if (sa->sa_family == AF_INET6) { return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); } else { return 0; } } /* exported function */ int evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) { struct sockaddr_storage ss; struct sockaddr *sa; int len = sizeof(ss); int res; if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss, &len)) { log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s", ip_as_string); return 4; } sa = (struct sockaddr *) &ss; if (sockaddr_getport(sa) == 0) sockaddr_setport(sa, 53); EVDNS_LOCK(base); res = evdns_nameserver_add_impl_(base, sa, len); EVDNS_UNLOCK(base); return res; } int evdns_nameserver_ip_add(const char *ip_as_string) { if (!current_base) current_base = evdns_base_new(NULL, 0); return evdns_base_nameserver_ip_add(current_base, ip_as_string); } int evdns_base_nameserver_sockaddr_add(struct evdns_base *base, const struct sockaddr *sa, ev_socklen_t len, unsigned flags) { int res; EVUTIL_ASSERT(base); EVDNS_LOCK(base); res = evdns_nameserver_add_impl_(base, sa, len); EVDNS_UNLOCK(base); return res; } int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx, struct sockaddr *sa, ev_socklen_t len) { int result = -1; int i; struct nameserver *server; EVDNS_LOCK(base); server = base->server_head; for (i = 0; i < idx && server; ++i, server = server->next) { if (server->next == base->server_head) goto done; } if (! server) goto done; if (server->addrlen > len) { result = (int) server->addrlen; goto done; } memcpy(sa, &server->address, server->addrlen); result = (int) server->addrlen; done: EVDNS_UNLOCK(base); return result; } /* remove from the queue */ static void evdns_request_remove(struct request *req, struct request **head) { ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); #if 0 { struct request *ptr; int found = 0; EVUTIL_ASSERT(*head != NULL); ptr = *head; do { if (ptr == req) { found = 1; break; } ptr = ptr->next; } while (ptr != *head); EVUTIL_ASSERT(found); EVUTIL_ASSERT(req->next); } #endif if (req->next == req) { /* only item in the list */ *head = NULL; } else { req->next->prev = req->prev; req->prev->next = req->next; if (*head == req) *head = req->next; } req->next = req->prev = NULL; } /* insert into the tail of the queue */ static void evdns_request_insert(struct request *req, struct request **head) { ASSERT_LOCKED(req->base); ASSERT_VALID_REQUEST(req); if (!*head) { *head = req; req->next = req->prev = req; return; } req->prev = (*head)->prev; req->prev->next = req; req->next = *head; (*head)->prev = req; } static int string_num_dots(const char *s) { int count = 0; while ((s = strchr(s, '.'))) { s++; count++; } return count; } static struct request * request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *user_ptr) { const char issuing_now = (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0; const size_t name_len = strlen(name); const size_t request_max_len = evdns_request_len(name_len); const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff; /* the request data is alloced in a single block with the header */ struct request *const req = mm_malloc(sizeof(struct request) + request_max_len); int rlen; char namebuf[256]; (void) flags; ASSERT_LOCKED(base); if (!req) return NULL; if (name_len >= sizeof(namebuf)) { mm_free(req); return NULL; } memset(req, 0, sizeof(struct request)); req->base = base; evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req); if (base->global_randomize_case) { unsigned i; char randbits[(sizeof(namebuf)+7)/8]; strlcpy(namebuf, name, sizeof(namebuf)); evutil_secure_rng_get_bytes(randbits, (name_len+7)/8); for (i = 0; i < name_len; ++i) { if (EVUTIL_ISALPHA_(namebuf[i])) { if ((randbits[i >> 3] & (1<<(i & 7)))) namebuf[i] |= 0x20; else namebuf[i] &= ~0x20; } } name = namebuf; } /* request data lives just after the header */ req->request = ((u8 *) req) + sizeof(struct request); /* denotes that the request data shouldn't be free()ed */ req->request_appended = 1; rlen = evdns_request_data_build(name, name_len, trans_id, type, CLASS_INET, req->request, request_max_len); if (rlen < 0) goto err1; req->request_len = rlen; req->trans_id = trans_id; req->tx_count = 0; req->request_type = type; req->user_pointer = user_ptr; req->user_callback = callback; req->ns = issuing_now ? nameserver_pick(base) : NULL; req->next = req->prev = NULL; req->handle = handle; if (handle) { handle->current_req = req; handle->base = base; } return req; err1: mm_free(req); return NULL; } static void request_submit(struct request *const req) { struct evdns_base *base = req->base; ASSERT_LOCKED(base); ASSERT_VALID_REQUEST(req); if (req->ns) { /* if it has a nameserver assigned then this is going */ /* straight into the inflight queue */ evdns_request_insert(req, &REQ_HEAD(base, req->trans_id)); base->global_requests_inflight++; req->ns->requests_inflight++; evdns_request_transmit(req); } else { evdns_request_insert(req, &base->req_waiting_head); base->global_requests_waiting++; } } /* exported function */ void evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle) { struct request *req; if (!handle->current_req) return; if (!base) { /* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */ base = handle->base; if (!base) base = handle->current_req->base; } EVDNS_LOCK(base); if (handle->pending_cb) { EVDNS_UNLOCK(base); return; } req = handle->current_req; ASSERT_VALID_REQUEST(req); reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL); if (req->ns) { /* remove from inflight queue */ request_finished(req, &REQ_HEAD(base, req->trans_id), 1); } else { /* remove from global_waiting head */ request_finished(req, &base->req_waiting_head, 1); } EVDNS_UNLOCK(base); } /* exported function */ struct evdns_request * evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr) { struct evdns_request *handle; struct request *req; log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); handle = mm_calloc(1, sizeof(*handle)); if (handle == NULL) return NULL; EVDNS_LOCK(base); if (flags & DNS_QUERY_NO_SEARCH) { req = request_new(base, handle, TYPE_A, name, flags, callback, ptr); if (req) request_submit(req); } else { search_request_new(base, handle, TYPE_A, name, flags, callback, ptr); } if (handle->current_req == NULL) { mm_free(handle); handle = NULL; } EVDNS_UNLOCK(base); return handle; } int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr) { return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr) ? 0 : -1; } /* exported function */ struct evdns_request * evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr) { struct evdns_request *handle; struct request *req; log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); handle = mm_calloc(1, sizeof(*handle)); if (handle == NULL) return NULL; EVDNS_LOCK(base); if (flags & DNS_QUERY_NO_SEARCH) { req = request_new(base, handle, TYPE_AAAA, name, flags, callback, ptr); if (req) request_submit(req); } else { search_request_new(base, handle, TYPE_AAAA, name, flags, callback, ptr); } if (handle->current_req == NULL) { mm_free(handle); handle = NULL; } EVDNS_UNLOCK(base); return handle; } int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr) { return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr) ? 0 : -1; } struct evdns_request * evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { char buf[32]; struct evdns_request *handle; struct request *req; u32 a; EVUTIL_ASSERT(in); a = ntohl(in->s_addr); evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", (int)(u8)((a )&0xff), (int)(u8)((a>>8 )&0xff), (int)(u8)((a>>16)&0xff), (int)(u8)((a>>24)&0xff)); handle = mm_calloc(1, sizeof(*handle)); if (handle == NULL) return NULL; log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); EVDNS_LOCK(base); req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr); if (req) request_submit(req); if (handle->current_req == NULL) { mm_free(handle); handle = NULL; } EVDNS_UNLOCK(base); return (handle); } int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr) ? 0 : -1; } struct evdns_request * evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */ char buf[73]; char *cp; struct evdns_request *handle; struct request *req; int i; EVUTIL_ASSERT(in); cp = buf; for (i=15; i >= 0; --i) { u8 byte = in->s6_addr[i]; *cp++ = "0123456789abcdef"[byte & 0x0f]; *cp++ = '.'; *cp++ = "0123456789abcdef"[byte >> 4]; *cp++ = '.'; } EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf)); memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1); handle = mm_calloc(1, sizeof(*handle)); if (handle == NULL) return NULL; log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); EVDNS_LOCK(base); req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr); if (req) request_submit(req); if (handle->current_req == NULL) { mm_free(handle); handle = NULL; } EVDNS_UNLOCK(base); return (handle); } int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr) ? 0 : -1; } /* ================================================================= */ /* Search support */ /* */ /* the libc resolver has support for searching a number of domains */ /* to find a name. If nothing else then it takes the single domain */ /* from the gethostname() call. */ /* */ /* It can also be configured via the domain and search options in a */ /* resolv.conf. */ /* */ /* The ndots option controls how many dots it takes for the resolver */ /* to decide that a name is non-local and so try a raw lookup first. */ struct search_domain { int len; struct search_domain *next; /* the text string is appended to this structure */ }; struct search_state { int refcount; int ndots; int num_domains; struct search_domain *head; }; static void search_state_decref(struct search_state *const state) { if (!state) return; state->refcount--; if (!state->refcount) { struct search_domain *next, *dom; for (dom = state->head; dom; dom = next) { next = dom->next; mm_free(dom); } mm_free(state); } } static struct search_state * search_state_new(void) { struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state)); if (!state) return NULL; memset(state, 0, sizeof(struct search_state)); state->refcount = 1; state->ndots = 1; return state; } static void search_postfix_clear(struct evdns_base *base) { search_state_decref(base->global_search_state); base->global_search_state = search_state_new(); } /* exported function */ void evdns_base_search_clear(struct evdns_base *base) { EVDNS_LOCK(base); search_postfix_clear(base); EVDNS_UNLOCK(base); } void evdns_search_clear(void) { evdns_base_search_clear(current_base); } static void search_postfix_add(struct evdns_base *base, const char *domain) { size_t domain_len; struct search_domain *sdomain; while (domain[0] == '.') domain++; domain_len = strlen(domain); ASSERT_LOCKED(base); if (!base->global_search_state) base->global_search_state = search_state_new(); if (!base->global_search_state) return; base->global_search_state->num_domains++; sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len); if (!sdomain) return; memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len); sdomain->next = base->global_search_state->head; sdomain->len = (int) domain_len; base->global_search_state->head = sdomain; } /* reverse the order of members in the postfix list. This is needed because, */ /* when parsing resolv.conf we push elements in the wrong order */ static void search_reverse(struct evdns_base *base) { struct search_domain *cur, *prev = NULL, *next; ASSERT_LOCKED(base); cur = base->global_search_state->head; while (cur) { next = cur->next; cur->next = prev; prev = cur; cur = next; } base->global_search_state->head = prev; } /* exported function */ void evdns_base_search_add(struct evdns_base *base, const char *domain) { EVDNS_LOCK(base); search_postfix_add(base, domain); EVDNS_UNLOCK(base); } void evdns_search_add(const char *domain) { evdns_base_search_add(current_base, domain); } /* exported function */ void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) { EVDNS_LOCK(base); if (!base->global_search_state) base->global_search_state = search_state_new(); if (base->global_search_state) base->global_search_state->ndots = ndots; EVDNS_UNLOCK(base); } void evdns_search_ndots_set(const int ndots) { evdns_base_search_ndots_set(current_base, ndots); } static void search_set_from_hostname(struct evdns_base *base) { char hostname[HOST_NAME_MAX + 1], *domainname; ASSERT_LOCKED(base); search_postfix_clear(base); if (gethostname(hostname, sizeof(hostname))) return; domainname = strchr(hostname, '.'); if (!domainname) return; search_postfix_add(base, domainname); } /* warning: returns malloced string */ static char * search_make_new(const struct search_state *const state, int n, const char *const base_name) { const size_t base_len = strlen(base_name); char need_to_append_dot; struct search_domain *dom; if (!base_len) return NULL; need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1; for (dom = state->head; dom; dom = dom->next) { if (!n--) { /* this is the postfix we want */ /* the actual postfix string is kept at the end of the structure */ const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain); const int postfix_len = dom->len; char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1); if (!newname) return NULL; memcpy(newname, base_name, base_len); if (need_to_append_dot) newname[base_len] = '.'; memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len); newname[base_len + need_to_append_dot + postfix_len] = 0; return newname; } } /* we ran off the end of the list and still didn't find the requested string */ EVUTIL_ASSERT(0); return NULL; /* unreachable; stops warnings in some compilers. */ } static struct request * search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) { ASSERT_LOCKED(base); EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA); EVUTIL_ASSERT(handle->current_req == NULL); if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) && base->global_search_state && base->global_search_state->num_domains) { /* we have some domains to search */ struct request *req; if (string_num_dots(name) >= base->global_search_state->ndots) { req = request_new(base, handle, type, name, flags, user_callback, user_arg); if (!req) return NULL; handle->search_index = -1; } else { char *const new_name = search_make_new(base->global_search_state, 0, name); if (!new_name) return NULL; req = request_new(base, handle, type, new_name, flags, user_callback, user_arg); mm_free(new_name); if (!req) return NULL; handle->search_index = 0; } EVUTIL_ASSERT(handle->search_origname == NULL); handle->search_origname = mm_strdup(name); if (handle->search_origname == NULL) { /* XXX Should we dealloc req? If yes, how? */ if (req) mm_free(req); return NULL; } handle->search_state = base->global_search_state; handle->search_flags = flags; base->global_search_state->refcount++; request_submit(req); return req; } else { struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg); if (!req) return NULL; request_submit(req); return req; } } /* this is called when a request has failed to find a name. We need to check */ /* if it is part of a search and, if so, try the next name in the list */ /* returns: */ /* 0 another request has been submitted */ /* 1 no more requests needed */ static int search_try_next(struct evdns_request *const handle) { struct request *req = handle->current_req; struct evdns_base *base = req->base; struct request *newreq; ASSERT_LOCKED(base); if (handle->search_state) { /* it is part of a search */ char *new_name; handle->search_index++; if (handle->search_index >= handle->search_state->num_domains) { /* no more postfixes to try, however we may need to try */ /* this name without a postfix */ if (string_num_dots(handle->search_origname) < handle->search_state->ndots) { /* yep, we need to try it raw */ newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer); log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname); if (newreq) { search_request_finished(handle); goto submit_next; } } return 1; } new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname); if (!new_name) return 1; log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index); newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer); mm_free(new_name); if (!newreq) return 1; goto submit_next; } return 1; submit_next: request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0); handle->current_req = newreq; newreq->handle = handle; request_submit(newreq); return 0; } static void search_request_finished(struct evdns_request *const handle) { ASSERT_LOCKED(handle->current_req->base); if (handle->search_state) { search_state_decref(handle->search_state); handle->search_state = NULL; } if (handle->search_origname) { mm_free(handle->search_origname); handle->search_origname = NULL; } } /* ================================================================= */ /* Parsing resolv.conf files */ static void evdns_resolv_set_defaults(struct evdns_base *base, int flags) { int add_default = flags & DNS_OPTION_NAMESERVERS; if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT) add_default = 0; /* if the file isn't found then we assume a local resolver */ ASSERT_LOCKED(base); if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base); if (add_default) evdns_base_nameserver_ip_add(base, "127.0.0.1"); } #ifndef EVENT__HAVE_STRTOK_R static char * strtok_r(char *s, const char *delim, char **state) { char *cp, *start; start = cp = s ? s : *state; if (!cp) return NULL; while (*cp && !strchr(delim, *cp)) ++cp; if (!*cp) { if (cp == start) return NULL; *state = NULL; return start; } else { *cp++ = '\0'; *state = cp; return start; } } #endif /* helper version of atoi which returns -1 on error */ static int strtoint(const char *const str) { char *endptr; const int r = strtol(str, &endptr, 10); if (*endptr) return -1; return r; } /* Parse a number of seconds into a timeval; return -1 on error. */ static int evdns_strtotimeval(const char *const str, struct timeval *out) { double d; char *endptr; d = strtod(str, &endptr); if (*endptr) return -1; if (d < 0) return -1; out->tv_sec = (int) d; out->tv_usec = (int) ((d - (int) d)*1000000); if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */ return -1; return 0; } /* helper version of atoi that returns -1 on error and clips to bounds. */ static int strtoint_clipped(const char *const str, int min, int max) { int r = strtoint(str); if (r == -1) return r; else if (rmax) return max; else return r; } static int evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight) { int old_n_heads = base->n_req_heads, n_heads; struct request **old_heads = base->req_heads, **new_heads, *req; int i; ASSERT_LOCKED(base); if (maxinflight < 1) maxinflight = 1; n_heads = (maxinflight+4) / 5; EVUTIL_ASSERT(n_heads > 0); new_heads = mm_calloc(n_heads, sizeof(struct request*)); if (!new_heads) return (-1); if (old_heads) { for (i = 0; i < old_n_heads; ++i) { while (old_heads[i]) { req = old_heads[i]; evdns_request_remove(req, &old_heads[i]); evdns_request_insert(req, &new_heads[req->trans_id % n_heads]); } } mm_free(old_heads); } base->req_heads = new_heads; base->n_req_heads = n_heads; base->global_max_requests_inflight = maxinflight; return (0); } /* exported function */ int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val) { int res; EVDNS_LOCK(base); res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL); EVDNS_UNLOCK(base); return res; } static inline int str_matches_option(const char *s1, const char *optionname) { /* Option names are given as "option:" We accept either 'option' in * s1, or 'option:randomjunk'. The latter form is to implement the * resolv.conf parser. */ size_t optlen = strlen(optionname); size_t slen = strlen(s1); if (slen == optlen || slen == optlen - 1) return !strncmp(s1, optionname, slen); else if (slen > optlen) return !strncmp(s1, optionname, optlen); else return 0; } static int evdns_base_set_option_impl(struct evdns_base *base, const char *option, const char *val, int flags) { ASSERT_LOCKED(base); if (str_matches_option(option, "ndots:")) { const int ndots = strtoint(val); if (ndots == -1) return -1; if (!(flags & DNS_OPTION_SEARCH)) return 0; log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); if (!base->global_search_state) base->global_search_state = search_state_new(); if (!base->global_search_state) return -1; base->global_search_state->ndots = ndots; } else if (str_matches_option(option, "timeout:")) { struct timeval tv; if (evdns_strtotimeval(val, &tv) == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val); memcpy(&base->global_timeout, &tv, sizeof(struct timeval)); } else if (str_matches_option(option, "getaddrinfo-allow-skew:")) { struct timeval tv; if (evdns_strtotimeval(val, &tv) == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s", val); memcpy(&base->global_getaddrinfo_allow_skew, &tv, sizeof(struct timeval)); } else if (str_matches_option(option, "max-timeouts:")) { const int maxtimeout = strtoint_clipped(val, 1, 255); if (maxtimeout == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", maxtimeout); base->global_max_nameserver_timeout = maxtimeout; } else if (str_matches_option(option, "max-inflight:")) { const int maxinflight = strtoint_clipped(val, 1, 65000); if (maxinflight == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", maxinflight); evdns_base_set_max_requests_inflight(base, maxinflight); } else if (str_matches_option(option, "attempts:")) { int retries = strtoint(val); if (retries == -1) return -1; if (retries > 255) retries = 255; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); base->global_max_retransmits = retries; } else if (str_matches_option(option, "randomize-case:")) { int randcase = strtoint(val); if (randcase == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; base->global_randomize_case = randcase; } else if (str_matches_option(option, "bind-to:")) { /* XXX This only applies to successive nameservers, not * to already-configured ones. We might want to fix that. */ int len = sizeof(base->global_outgoing_address); if (!(flags & DNS_OPTION_NAMESERVERS)) return 0; if (evutil_parse_sockaddr_port(val, (struct sockaddr*)&base->global_outgoing_address, &len)) return -1; base->global_outgoing_addrlen = len; } else if (str_matches_option(option, "initial-probe-timeout:")) { struct timeval tv; if (evdns_strtotimeval(val, &tv) == -1) return -1; if (tv.tv_sec > 3600) tv.tv_sec = 3600; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s", val); memcpy(&base->global_nameserver_probe_initial_timeout, &tv, sizeof(tv)); } else if (str_matches_option(option, "so-rcvbuf:")) { int buf = strtoint(val); if (buf == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting SO_RCVBUF to %s", val); base->so_rcvbuf = buf; } else if (str_matches_option(option, "so-sndbuf:")) { int buf = strtoint(val); if (buf == -1) return -1; if (!(flags & DNS_OPTION_MISC)) return 0; log(EVDNS_LOG_DEBUG, "Setting SO_SNDBUF to %s", val); base->so_sndbuf = buf; } return 0; } int evdns_set_option(const char *option, const char *val, int flags) { if (!current_base) current_base = evdns_base_new(NULL, 0); return evdns_base_set_option(current_base, option, val); } static void resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) { char *strtok_state; static const char *const delims = " \t"; #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) char *const first_token = strtok_r(start, delims, &strtok_state); ASSERT_LOCKED(base); if (!first_token) return; if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) { const char *const nameserver = NEXT_TOKEN; if (nameserver) evdns_base_nameserver_ip_add(base, nameserver); } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) { const char *const domain = NEXT_TOKEN; if (domain) { search_postfix_clear(base); search_postfix_add(base, domain); } } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) { const char *domain; search_postfix_clear(base); while ((domain = NEXT_TOKEN)) { search_postfix_add(base, domain); } search_reverse(base); } else if (!strcmp(first_token, "options")) { const char *option; while ((option = NEXT_TOKEN)) { const char *val = strchr(option, ':'); evdns_base_set_option_impl(base, option, val ? val+1 : "", flags); } } #undef NEXT_TOKEN } /* exported function */ /* returns: */ /* 0 no errors */ /* 1 failed to open file */ /* 2 failed to stat file */ /* 3 file too large */ /* 4 out of memory */ /* 5 short read from file */ int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) { int res; EVDNS_LOCK(base); res = evdns_base_resolv_conf_parse_impl(base, flags, filename); EVDNS_UNLOCK(base); return res; } static char * evdns_get_default_hosts_filename(void) { #ifdef _WIN32 /* Windows is a little coy about where it puts its configuration * files. Sure, they're _usually_ in C:\windows\system32, but * there's no reason in principle they couldn't be in * W:\hoboken chicken emergency\ */ char path[MAX_PATH+1]; static const char hostfile[] = "\\drivers\\etc\\hosts"; char *path_out; size_t len_out; if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0)) return NULL; len_out = strlen(path)+strlen(hostfile)+1; path_out = mm_malloc(len_out); evutil_snprintf(path_out, len_out, "%s%s", path, hostfile); return path_out; #else return mm_strdup("/etc/hosts"); #endif } static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) { size_t n; char *resolv; char *start; int err = 0; int add_default; log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); add_default = flags & DNS_OPTION_NAMESERVERS; if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT) add_default = 0; if (flags & DNS_OPTION_HOSTSFILE) { char *fname = evdns_get_default_hosts_filename(); evdns_base_load_hosts(base, fname); if (fname) mm_free(fname); } if (!filename) { evdns_resolv_set_defaults(base, flags); return 1; } if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) { if (err == -1) { /* No file. */ evdns_resolv_set_defaults(base, flags); return 1; } else { return 2; } } start = resolv; for (;;) { char *const newline = strchr(start, '\n'); if (!newline) { resolv_conf_parse_line(base, start, flags); break; } else { *newline = 0; resolv_conf_parse_line(base, start, flags); start = newline + 1; } } if (!base->server_head && add_default) { /* no nameservers were configured. */ evdns_base_nameserver_ip_add(base, "127.0.0.1"); err = 6; } if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) { search_set_from_hostname(base); } mm_free(resolv); return err; } int evdns_resolv_conf_parse(int flags, const char *const filename) { if (!current_base) current_base = evdns_base_new(NULL, 0); return evdns_base_resolv_conf_parse(current_base, flags, filename); } #ifdef _WIN32 /* Add multiple nameservers from a space-or-comma-separated list. */ static int evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) { const char *addr; char *buf; int r; ASSERT_LOCKED(base); while (*ips) { while (isspace(*ips) || *ips == ',' || *ips == '\t') ++ips; addr = ips; while (isdigit(*ips) || *ips == '.' || *ips == ':' || *ips=='[' || *ips==']') ++ips; buf = mm_malloc(ips-addr+1); if (!buf) return 4; memcpy(buf, addr, ips-addr); buf[ips-addr] = '\0'; r = evdns_base_nameserver_ip_add(base, buf); mm_free(buf); if (r) return r; } return 0; } typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*); /* Use the windows GetNetworkParams interface in iphlpapi.dll to */ /* figure out what our nameservers are. */ static int load_nameservers_with_getnetworkparams(struct evdns_base *base) { /* Based on MSDN examples and inspection of c-ares code. */ FIXED_INFO *fixed; HMODULE handle = 0; ULONG size = sizeof(FIXED_INFO); void *buf = NULL; int status = 0, r, added_any; IP_ADDR_STRING *ns; GetNetworkParams_fn_t fn; ASSERT_LOCKED(base); if (!(handle = evutil_load_windows_system_library_( TEXT("iphlpapi.dll")))) { log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); status = -1; goto done; } if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) { log(EVDNS_LOG_WARN, "Could not get address of function."); status = -1; goto done; } buf = mm_malloc(size); if (!buf) { status = 4; goto done; } fixed = buf; r = fn(fixed, &size); if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) { status = -1; goto done; } if (r != ERROR_SUCCESS) { mm_free(buf); buf = mm_malloc(size); if (!buf) { status = 4; goto done; } fixed = buf; r = fn(fixed, &size); if (r != ERROR_SUCCESS) { log(EVDNS_LOG_DEBUG, "fn() failed."); status = -1; goto done; } } EVUTIL_ASSERT(fixed); added_any = 0; ns = &(fixed->DnsServerList); while (ns) { r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String); if (r) { log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d", (ns->IpAddress.String),(int)GetLastError()); status = r; } else { ++added_any; log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String); } ns = ns->Next; } if (!added_any) { log(EVDNS_LOG_DEBUG, "No nameservers added."); if (status == 0) status = -1; } else { status = 0; } done: if (buf) mm_free(buf); if (handle) FreeLibrary(handle); return status; } static int config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey) { char *buf; DWORD bufsz = 0, type = 0; int status = 0; ASSERT_LOCKED(base); if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz) != ERROR_MORE_DATA) return -1; if (!(buf = mm_malloc(bufsz))) return -1; if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz) == ERROR_SUCCESS && bufsz > 1) { status = evdns_nameserver_ip_add_line(base,buf); } mm_free(buf); return status; } #define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\") #define WIN_NS_9X_KEY SERVICES_KEY TEXT("VxD\\MSTCP") #define WIN_NS_NT_KEY SERVICES_KEY TEXT("Tcpip\\Parameters") static int load_nameservers_from_registry(struct evdns_base *base) { int found = 0; int r; #define TRY(k, name) \ if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \ log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ found = 1; \ } else if (!found) { \ log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ #k,#name); \ } ASSERT_LOCKED(base); if (((int)GetVersion()) > 0) { /* NT */ HKEY nt_key = 0, interfaces_key = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &nt_key) != ERROR_SUCCESS) { log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); return -1; } r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &interfaces_key); if (r != ERROR_SUCCESS) { log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); return -1; } TRY(nt_key, "NameServer"); TRY(nt_key, "DhcpNameServer"); TRY(interfaces_key, "NameServer"); TRY(interfaces_key, "DhcpNameServer"); RegCloseKey(interfaces_key); RegCloseKey(nt_key); } else { HKEY win_key = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0, KEY_READ, &win_key) != ERROR_SUCCESS) { log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); return -1; } TRY(win_key, "NameServer"); RegCloseKey(win_key); } if (found == 0) { log(EVDNS_LOG_WARN,"Didn't find any nameservers."); } return found ? 0 : -1; #undef TRY } int evdns_base_config_windows_nameservers(struct evdns_base *base) { int r; char *fname; if (base == NULL) base = current_base; if (base == NULL) return -1; EVDNS_LOCK(base); fname = evdns_get_default_hosts_filename(); log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname); evdns_base_load_hosts(base, fname); if (fname) mm_free(fname); if (load_nameservers_with_getnetworkparams(base) == 0) { EVDNS_UNLOCK(base); return 0; } r = load_nameservers_from_registry(base); EVDNS_UNLOCK(base); return r; } int evdns_config_windows_nameservers(void) { if (!current_base) { current_base = evdns_base_new(NULL, 1); return current_base == NULL ? -1 : 0; } else { return evdns_base_config_windows_nameservers(current_base); } } #endif struct evdns_base * evdns_base_new(struct event_base *event_base, int flags) { struct evdns_base *base; if (evutil_secure_rng_init() < 0) { log(EVDNS_LOG_WARN, "Unable to seed random number generator; " "DNS can't run."); return NULL; } /* Give the evutil library a hook into its evdns-enabled * functionality. We can't just call evdns_getaddrinfo directly or * else libevent-core will depend on libevent-extras. */ evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo); evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel); base = mm_malloc(sizeof(struct evdns_base)); if (base == NULL) return (NULL); memset(base, 0, sizeof(struct evdns_base)); base->req_waiting_head = NULL; EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE); EVDNS_LOCK(base); /* Set max requests inflight and allocate req_heads. */ base->req_heads = NULL; evdns_base_set_max_requests_inflight(base, 64); base->server_head = NULL; base->event_base = event_base; base->global_good_nameservers = base->global_requests_inflight = base->global_requests_waiting = 0; base->global_timeout.tv_sec = 5; base->global_timeout.tv_usec = 0; base->global_max_reissues = 1; base->global_max_retransmits = 3; base->global_max_nameserver_timeout = 3; base->global_search_state = NULL; base->global_randomize_case = 1; base->global_getaddrinfo_allow_skew.tv_sec = 3; base->global_getaddrinfo_allow_skew.tv_usec = 0; base->global_nameserver_probe_initial_timeout.tv_sec = 10; base->global_nameserver_probe_initial_timeout.tv_usec = 0; TAILQ_INIT(&base->hostsdb); #define EVDNS_BASE_ALL_FLAGS ( \ EVDNS_BASE_INITIALIZE_NAMESERVERS | \ EVDNS_BASE_DISABLE_WHEN_INACTIVE | \ EVDNS_BASE_NAMESERVERS_NO_DEFAULT | \ 0) if (flags & ~EVDNS_BASE_ALL_FLAGS) { flags = EVDNS_BASE_INITIALIZE_NAMESERVERS; log(EVDNS_LOG_WARN, "Unrecognized flag passed to evdns_base_new(). Assuming " "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS."); } #undef EVDNS_BASE_ALL_FLAGS if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) { int r; int opts = DNS_OPTIONS_ALL; if (flags & EVDNS_BASE_NAMESERVERS_NO_DEFAULT) { opts |= DNS_OPTION_NAMESERVERS_NO_DEFAULT; } #ifdef _WIN32 r = evdns_base_config_windows_nameservers(base); #else r = evdns_base_resolv_conf_parse(base, opts, "/etc/resolv.conf"); #endif if (r) { evdns_base_free_and_unlock(base, 0); return NULL; } } if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) { base->disable_when_inactive = 1; } EVDNS_UNLOCK(base); return base; } int evdns_init(void) { struct evdns_base *base = evdns_base_new(NULL, 1); if (base) { current_base = base; return 0; } else { return -1; } } const char * evdns_err_to_string(int err) { switch (err) { case DNS_ERR_NONE: return "no error"; case DNS_ERR_FORMAT: return "misformatted query"; case DNS_ERR_SERVERFAILED: return "server failed"; case DNS_ERR_NOTEXIST: return "name does not exist"; case DNS_ERR_NOTIMPL: return "query not implemented"; case DNS_ERR_REFUSED: return "refused"; case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed"; case DNS_ERR_UNKNOWN: return "unknown"; case DNS_ERR_TIMEOUT: return "request timed out"; case DNS_ERR_SHUTDOWN: return "dns subsystem shut down"; case DNS_ERR_CANCEL: return "dns request canceled"; case DNS_ERR_NODATA: return "no records in the reply"; default: return "[Unknown error code]"; } } static void evdns_nameserver_free(struct nameserver *server) { if (server->socket >= 0) evutil_closesocket(server->socket); (void) event_del(&server->event); event_debug_unassign(&server->event); if (server->state == 0) (void) event_del(&server->timeout_event); if (server->probe_request) { evdns_cancel_request(server->base, server->probe_request); server->probe_request = NULL; } event_debug_unassign(&server->timeout_event); mm_free(server); } static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests) { struct nameserver *server, *server_next; struct search_domain *dom, *dom_next; int i; /* Requires that we hold the lock. */ /* TODO(nickm) we might need to refcount here. */ while (base->req_waiting_head) { if (fail_requests) reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL); request_finished(base->req_waiting_head, &base->req_waiting_head, 1); } for (i = 0; i < base->n_req_heads; ++i) { while (base->req_heads[i]) { if (fail_requests) reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL); request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1); } } base->global_requests_inflight = base->global_requests_waiting = 0; for (server = base->server_head; server; server = server_next) { server_next = server->next; /** already done something before */ server->probe_request = NULL; evdns_nameserver_free(server); if (server_next == base->server_head) break; } base->server_head = NULL; base->global_good_nameservers = 0; if (base->global_search_state) { for (dom = base->global_search_state->head; dom; dom = dom_next) { dom_next = dom->next; mm_free(dom); } mm_free(base->global_search_state); base->global_search_state = NULL; } { struct hosts_entry *victim; while ((victim = TAILQ_FIRST(&base->hostsdb))) { TAILQ_REMOVE(&base->hostsdb, victim, next); mm_free(victim); } } mm_free(base->req_heads); EVDNS_UNLOCK(base); EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE); mm_free(base); } void evdns_base_free(struct evdns_base *base, int fail_requests) { EVDNS_LOCK(base); evdns_base_free_and_unlock(base, fail_requests); } void evdns_base_clear_host_addresses(struct evdns_base *base) { struct hosts_entry *victim; EVDNS_LOCK(base); while ((victim = TAILQ_FIRST(&base->hostsdb))) { TAILQ_REMOVE(&base->hostsdb, victim, next); mm_free(victim); } EVDNS_UNLOCK(base); } void evdns_shutdown(int fail_requests) { if (current_base) { struct evdns_base *b = current_base; current_base = NULL; evdns_base_free(b, fail_requests); } evdns_log_fn = NULL; } static int evdns_base_parse_hosts_line(struct evdns_base *base, char *line) { char *strtok_state; static const char *const delims = " \t"; char *const addr = strtok_r(line, delims, &strtok_state); char *hostname, *hash; struct sockaddr_storage ss; int socklen = sizeof(ss); ASSERT_LOCKED(base); #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) if (!addr || *addr == '#') return 0; memset(&ss, 0, sizeof(ss)); if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0) return -1; if (socklen > (int)sizeof(struct sockaddr_in6)) return -1; if (sockaddr_getport((struct sockaddr*)&ss)) return -1; while ((hostname = NEXT_TOKEN)) { struct hosts_entry *he; size_t namelen; if ((hash = strchr(hostname, '#'))) { if (hash == hostname) return 0; *hash = '\0'; } namelen = strlen(hostname); he = mm_calloc(1, sizeof(struct hosts_entry)+namelen); if (!he) return -1; EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr)); memcpy(&he->addr, &ss, socklen); memcpy(he->hostname, hostname, namelen+1); he->addrlen = socklen; TAILQ_INSERT_TAIL(&base->hostsdb, he, next); if (hash) return 0; } return 0; #undef NEXT_TOKEN } static int evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname) { char *str=NULL, *cp, *eol; size_t len; int err=0; ASSERT_LOCKED(base); if (hosts_fname == NULL || (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) { char tmp[64]; strlcpy(tmp, "127.0.0.1 localhost", sizeof(tmp)); evdns_base_parse_hosts_line(base, tmp); strlcpy(tmp, "::1 localhost", sizeof(tmp)); evdns_base_parse_hosts_line(base, tmp); return err ? -1 : 0; } /* This will break early if there is a NUL in the hosts file. * Probably not a problem.*/ cp = str; for (;;) { eol = strchr(cp, '\n'); if (eol) { *eol = '\0'; evdns_base_parse_hosts_line(base, cp); cp = eol+1; } else { evdns_base_parse_hosts_line(base, cp); break; } } mm_free(str); return 0; } int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname) { int res; if (!base) base = current_base; EVDNS_LOCK(base); res = evdns_base_load_hosts_impl(base, hosts_fname); EVDNS_UNLOCK(base); return res; } /* A single request for a getaddrinfo, either v4 or v6. */ struct getaddrinfo_subrequest { struct evdns_request *r; ev_uint32_t type; }; /* State data used to implement an in-progress getaddrinfo. */ struct evdns_getaddrinfo_request { struct evdns_base *evdns_base; /* Copy of the modified 'hints' data that we'll use to build * answers. */ struct evutil_addrinfo hints; /* The callback to invoke when we're done */ evdns_getaddrinfo_cb user_cb; /* User-supplied data to give to the callback. */ void *user_data; /* The port to use when building sockaddrs. */ ev_uint16_t port; /* The sub_request for an A record (if any) */ struct getaddrinfo_subrequest ipv4_request; /* The sub_request for an AAAA record (if any) */ struct getaddrinfo_subrequest ipv6_request; /* The cname result that we were told (if any) */ char *cname_result; /* If we have one request answered and one request still inflight, * then this field holds the answer from the first request... */ struct evutil_addrinfo *pending_result; /* And this event is a timeout that will tell us to cancel the second * request if it's taking a long time. */ struct event timeout; /* And this field holds the error code from the first request... */ int pending_error; /* If this is set, the user canceled this request. */ unsigned user_canceled : 1; /* If this is set, the user can no longer cancel this request; we're * just waiting for the free. */ unsigned request_done : 1; }; /* Convert an evdns errors to the equivalent getaddrinfo error. */ static int evdns_err_to_getaddrinfo_err(int e1) { /* XXX Do this better! */ if (e1 == DNS_ERR_NONE) return 0; else if (e1 == DNS_ERR_NOTEXIST) return EVUTIL_EAI_NONAME; else return EVUTIL_EAI_FAIL; } /* Return the more informative of two getaddrinfo errors. */ static int getaddrinfo_merge_err(int e1, int e2) { /* XXXX be cleverer here. */ if (e1 == 0) return e2; else return e1; } static void free_getaddrinfo_request(struct evdns_getaddrinfo_request *data) { /* DO NOT CALL this if either of the requests is pending. Only once * both callbacks have been invoked is it safe to free the request */ if (data->pending_result) evutil_freeaddrinfo(data->pending_result); if (data->cname_result) mm_free(data->cname_result); event_del(&data->timeout); mm_free(data); return; } static void add_cname_to_reply(struct evdns_getaddrinfo_request *data, struct evutil_addrinfo *ai) { if (data->cname_result && ai) { ai->ai_canonname = data->cname_result; data->cname_result = NULL; } } /* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo * request has finished, but the other one took too long to answer. Pass * along the answer we got, and cancel the other request. */ static void evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr) { int v4_timedout = 0, v6_timedout = 0; struct evdns_getaddrinfo_request *data = ptr; /* Cancel any pending requests, and note which one */ if (data->ipv4_request.r) { /* XXXX This does nothing if the request's callback is already * running (pending_cb is set). */ evdns_cancel_request(NULL, data->ipv4_request.r); v4_timedout = 1; EVDNS_LOCK(data->evdns_base); ++data->evdns_base->getaddrinfo_ipv4_timeouts; EVDNS_UNLOCK(data->evdns_base); } if (data->ipv6_request.r) { /* XXXX This does nothing if the request's callback is already * running (pending_cb is set). */ evdns_cancel_request(NULL, data->ipv6_request.r); v6_timedout = 1; EVDNS_LOCK(data->evdns_base); ++data->evdns_base->getaddrinfo_ipv6_timeouts; EVDNS_UNLOCK(data->evdns_base); } /* We only use this timeout callback when we have an answer for * one address. */ EVUTIL_ASSERT(!v4_timedout || !v6_timedout); /* Report the outcome of the other request that didn't time out. */ if (data->pending_result) { add_cname_to_reply(data, data->pending_result); data->user_cb(0, data->pending_result, data->user_data); data->pending_result = NULL; } else { int e = data->pending_error; if (!e) e = EVUTIL_EAI_AGAIN; data->user_cb(e, NULL, data->user_data); } data->user_cb = NULL; /* prevent double-call if evdns callbacks are * in-progress. XXXX It would be better if this * weren't necessary. */ if (!v4_timedout && !v6_timedout) { /* should be impossible? XXXX */ free_getaddrinfo_request(data); } } static int evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base, struct evdns_getaddrinfo_request *data) { return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew); } static inline int evdns_result_is_answer(int result) { return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED && result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL); } static void evdns_getaddrinfo_gotresolve(int result, char type, int count, int ttl, void *addresses, void *arg) { int i; struct getaddrinfo_subrequest *req = arg; struct getaddrinfo_subrequest *other_req; struct evdns_getaddrinfo_request *data; struct evutil_addrinfo *res; struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr *sa; int socklen, addrlen; void *addrp; int err; int user_canceled; EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA); if (req->type == DNS_IPv4_A) { data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request); other_req = &data->ipv6_request; } else { data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request); other_req = &data->ipv4_request; } /** Called from evdns_base_free() with @fail_requests == 1 */ if (result != DNS_ERR_SHUTDOWN) { EVDNS_LOCK(data->evdns_base); if (evdns_result_is_answer(result)) { if (req->type == DNS_IPv4_A) ++data->evdns_base->getaddrinfo_ipv4_answered; else ++data->evdns_base->getaddrinfo_ipv6_answered; } user_canceled = data->user_canceled; if (other_req->r == NULL) data->request_done = 1; EVDNS_UNLOCK(data->evdns_base); } else { data->evdns_base = NULL; user_canceled = data->user_canceled; } req->r = NULL; if (result == DNS_ERR_CANCEL && ! user_canceled) { /* Internal cancel request from timeout or internal error. * we already answered the user. */ if (other_req->r == NULL) free_getaddrinfo_request(data); return; } if (data->user_cb == NULL) { /* We already answered. XXXX This shouldn't be needed; see * comments in evdns_getaddrinfo_timeout_cb */ free_getaddrinfo_request(data); return; } if (result == DNS_ERR_NONE) { if (count == 0) err = EVUTIL_EAI_NODATA; else err = 0; } else { err = evdns_err_to_getaddrinfo_err(result); } if (err) { /* Looks like we got an error. */ if (other_req->r) { /* The other request is still working; maybe it will * succeed. */ /* XXXX handle failure from set_timeout */ if (result != DNS_ERR_SHUTDOWN) { evdns_getaddrinfo_set_timeout(data->evdns_base, data); } data->pending_error = err; return; } if (user_canceled) { data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data); } else if (data->pending_result) { /* If we have an answer waiting, and we weren't * canceled, ignore this error. */ add_cname_to_reply(data, data->pending_result); data->user_cb(0, data->pending_result, data->user_data); data->pending_result = NULL; } else { if (data->pending_error) err = getaddrinfo_merge_err(err, data->pending_error); data->user_cb(err, NULL, data->user_data); } free_getaddrinfo_request(data); return; } else if (user_canceled) { if (other_req->r) { /* The other request is still working; let it hit this * callback with EVUTIL_EAI_CANCEL callback and report * the failure. */ return; } data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data); free_getaddrinfo_request(data); return; } /* Looks like we got some answers. We should turn them into addrinfos * and then either queue those or return them all. */ EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA); if (type == DNS_IPv4_A) { memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(data->port); sa = (struct sockaddr *)&sin; socklen = sizeof(sin); addrlen = 4; addrp = &sin.sin_addr.s_addr; } else { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(data->port); sa = (struct sockaddr *)&sin6; socklen = sizeof(sin6); addrlen = 16; addrp = &sin6.sin6_addr.s6_addr; } res = NULL; for (i=0; i < count; ++i) { struct evutil_addrinfo *ai; memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen); ai = evutil_new_addrinfo_(sa, socklen, &data->hints); if (!ai) { if (other_req->r) { evdns_cancel_request(NULL, other_req->r); } data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data); if (res) evutil_freeaddrinfo(res); if (other_req->r == NULL) free_getaddrinfo_request(data); return; } res = evutil_addrinfo_append_(res, ai); } if (other_req->r) { /* The other request is still in progress; wait for it */ /* XXXX handle failure from set_timeout */ evdns_getaddrinfo_set_timeout(data->evdns_base, data); data->pending_result = res; return; } else { /* The other request is done or never started; append its * results (if any) and return them. */ if (data->pending_result) { if (req->type == DNS_IPv4_A) res = evutil_addrinfo_append_(res, data->pending_result); else res = evutil_addrinfo_append_( data->pending_result, res); data->pending_result = NULL; } /* Call the user callback. */ add_cname_to_reply(data, res); data->user_cb(0, res, data->user_data); /* Free data. */ free_getaddrinfo_request(data); } } static struct hosts_entry * find_hosts_entry(struct evdns_base *base, const char *hostname, struct hosts_entry *find_after) { struct hosts_entry *e; if (find_after) e = TAILQ_NEXT(find_after, next); else e = TAILQ_FIRST(&base->hostsdb); for (; e; e = TAILQ_NEXT(e, next)) { if (!evutil_ascii_strcasecmp(e->hostname, hostname)) return e; } return NULL; } static int evdns_getaddrinfo_fromhosts(struct evdns_base *base, const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port, struct evutil_addrinfo **res) { int n_found = 0; struct hosts_entry *e; struct evutil_addrinfo *ai=NULL; int f = hints->ai_family; EVDNS_LOCK(base); for (e = find_hosts_entry(base, nodename, NULL); e; e = find_hosts_entry(base, nodename, e)) { struct evutil_addrinfo *ai_new; ++n_found; if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) || (e->addr.sa.sa_family == AF_INET6 && f == PF_INET)) continue; ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints); if (!ai_new) { n_found = 0; goto out; } sockaddr_setport(ai_new->ai_addr, port); ai = evutil_addrinfo_append_(ai, ai_new); } EVDNS_UNLOCK(base); out: if (n_found) { /* Note that we return an empty answer if we found entries for * this hostname but none were of the right address type. */ *res = ai; return 0; } else { if (ai) evutil_freeaddrinfo(ai); return -1; } } struct evdns_getaddrinfo_request * evdns_getaddrinfo(struct evdns_base *dns_base, const char *nodename, const char *servname, const struct evutil_addrinfo *hints_in, evdns_getaddrinfo_cb cb, void *arg) { struct evdns_getaddrinfo_request *data; struct evutil_addrinfo hints; struct evutil_addrinfo *res = NULL; int err; int port = 0; int want_cname = 0; int started = 0; if (!dns_base) { dns_base = current_base; if (!dns_base) { log(EVDNS_LOG_WARN, "Call to getaddrinfo_async with no " "evdns_base configured."); cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */ return NULL; } } /* If we _must_ answer this immediately, do so. */ if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) { res = NULL; err = evutil_getaddrinfo(nodename, servname, hints_in, &res); cb(err, res, arg); return NULL; } if (hints_in) { memcpy(&hints, hints_in, sizeof(hints)); } else { memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; } evutil_adjust_hints_for_addrconfig_(&hints); /* Now try to see if we _can_ answer immediately. */ /* (It would be nice to do this by calling getaddrinfo directly, with * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't * a reliable way to distinguish the "that wasn't a numeric host!" case * from any other EAI_NONAME cases.) */ err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port); if (err != EVUTIL_EAI_NEED_RESOLVE) { cb(err, res, arg); return NULL; } /* If there is an entry in the hosts file, we should give it now. */ if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) { cb(0, res, arg); return NULL; } /* Okay, things are serious now. We're going to need to actually * launch a request. */ data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request)); if (!data) { cb(EVUTIL_EAI_MEMORY, NULL, arg); return NULL; } memcpy(&data->hints, &hints, sizeof(data->hints)); data->port = (ev_uint16_t)port; data->ipv4_request.type = DNS_IPv4_A; data->ipv6_request.type = DNS_IPv6_AAAA; data->user_cb = cb; data->user_data = arg; data->evdns_base = dns_base; want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME); /* If we are asked for a PF_UNSPEC address, we launch two requests in * parallel: one for an A address and one for an AAAA address. We * can't send just one request, since many servers only answer one * question per DNS request. * * Once we have the answer to one request, we allow for a short * timeout before we report it, to see if the other one arrives. If * they both show up in time, then we report both the answers. * * If too many addresses of one type time out or fail, we should stop * launching those requests. (XXX we don't do that yet.) */ EVDNS_LOCK(dns_base); if (hints.ai_family != PF_INET6) { log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p", nodename, &data->ipv4_request); data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base, nodename, 0, evdns_getaddrinfo_gotresolve, &data->ipv4_request); if (want_cname && data->ipv4_request.r) data->ipv4_request.r->current_req->put_cname_in_ptr = &data->cname_result; } if (hints.ai_family != PF_INET) { log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p", nodename, &data->ipv6_request); data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base, nodename, 0, evdns_getaddrinfo_gotresolve, &data->ipv6_request); if (want_cname && data->ipv6_request.r) data->ipv6_request.r->current_req->put_cname_in_ptr = &data->cname_result; } evtimer_assign(&data->timeout, dns_base->event_base, evdns_getaddrinfo_timeout_cb, data); started = (data->ipv4_request.r || data->ipv6_request.r); EVDNS_UNLOCK(dns_base); if (started) { return data; } else { mm_free(data); cb(EVUTIL_EAI_FAIL, NULL, arg); return NULL; } } void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data) { EVDNS_LOCK(data->evdns_base); if (data->request_done) { EVDNS_UNLOCK(data->evdns_base); return; } event_del(&data->timeout); data->user_canceled = 1; if (data->ipv4_request.r) evdns_cancel_request(data->evdns_base, data->ipv4_request.r); if (data->ipv6_request.r) evdns_cancel_request(data->evdns_base, data->ipv6_request.r); EVDNS_UNLOCK(data->evdns_base); } lldpd-1.0.13/libevent/test/0000755000076400001440000000000014143730656016171 5ustar00bernatusers00000000000000lldpd-1.0.13/libevent/test/regress_dns.c0000644000076400001440000021470014111362571020647 0ustar00bernatusers00000000000000/* * Copyright (c) 2003-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../util-internal.h" #ifdef _WIN32 #include #include #include #endif #include "event2/event-config.h" #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #ifndef _WIN32 #include #include #include #include #include #endif #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_NETDB_H #include #endif #include #include #include #include #include #ifdef EVENT__HAVE_SYS_RESOURCE_H #include #endif #include "event2/dns.h" #include "event2/dns_compat.h" #include "event2/dns_struct.h" #include "event2/event.h" #include "event2/event_compat.h" #include "event2/event_struct.h" #include "event2/util.h" #include "event2/listener.h" #include "event2/bufferevent.h" #include #include "log-internal.h" #include "evthread-internal.h" #include "regress.h" #include "regress_testutils.h" #include "regress_thread.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) static int dns_ok = 0; static int dns_got_cancel = 0; static int dns_err = 0; static void dns_gethostbyname_cb(int result, char type, int count, int ttl, void *addresses, void *arg) { dns_ok = dns_err = 0; if (result == DNS_ERR_TIMEOUT) { printf("[Timed out] "); dns_err = result; goto out; } if (result != DNS_ERR_NONE) { printf("[Error code %d] ", result); goto out; } TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl)); switch (type) { case DNS_IPv6_AAAA: { #if defined(EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) struct in6_addr *in6_addrs = addresses; char buf[INET6_ADDRSTRLEN+1]; int i; /* a resolution that's not valid does not help */ if (ttl < 0) goto out; for (i = 0; i < count; ++i) { const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf)); if (b) TT_BLATHER(("%s ", b)); else TT_BLATHER(("%s ", strerror(errno))); } #endif break; } case DNS_IPv4_A: { struct in_addr *in_addrs = addresses; int i; /* a resolution that's not valid does not help */ if (ttl < 0) goto out; for (i = 0; i < count; ++i) TT_BLATHER(("%s ", inet_ntoa(in_addrs[i]))); break; } case DNS_PTR: /* may get at most one PTR */ if (count != 1) goto out; TT_BLATHER(("%s ", *(char **)addresses)); break; default: goto out; } dns_ok = type; out: if (arg == NULL) event_loopexit(NULL); else event_base_loopexit((struct event_base *)arg, NULL); } static void dns_gethostbyname(void) { dns_ok = 0; evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); event_dispatch(); tt_int_op(dns_ok, ==, DNS_IPv4_A); test_ok = dns_ok; end: ; } static void dns_gethostbyname6(void) { dns_ok = 0; evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); event_dispatch(); if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { tt_skip(); } tt_int_op(dns_ok, ==, DNS_IPv6_AAAA); test_ok = 1; end: ; } static void dns_gethostbyaddr(void) { struct in_addr in; in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ dns_ok = 0; evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); event_dispatch(); tt_int_op(dns_ok, ==, DNS_PTR); test_ok = dns_ok; end: ; } static void dns_resolve_reverse(void *ptr) { struct in_addr in; struct event_base *base = event_base_new(); struct evdns_base *dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS); struct evdns_request *req = NULL; tt_assert(base); tt_assert(dns); in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ dns_ok = 0; req = evdns_base_resolve_reverse( dns, &in, 0, dns_gethostbyname_cb, base); tt_assert(req); event_base_dispatch(base); tt_int_op(dns_ok, ==, DNS_PTR); end: if (dns) evdns_base_free(dns, 0); if (base) event_base_free(base); } static int n_server_responses = 0; static void dns_server_request_cb(struct evdns_server_request *req, void *data) { int i, r; const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; const char TEST_IN6[] = "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1." "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa"; for (i = 0; i < req->nquestions; ++i) { const int qtype = req->questions[i]->type; const int qclass = req->questions[i]->dns_question_class; const char *qname = req->questions[i]->name; struct in_addr ans; ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ if (qtype == EVDNS_TYPE_A && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, "zz.example.com")) { r = evdns_server_request_add_a_reply(req, qname, 1, &ans.s_addr, 12345); if (r<0) dns_ok = 0; } else if (qtype == EVDNS_TYPE_AAAA && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, "zz.example.com")) { char addr6[17] = "abcdefghijklmnop"; r = evdns_server_request_add_aaaa_reply(req, qname, 1, addr6, 123); if (r<0) dns_ok = 0; } else if (qtype == EVDNS_TYPE_PTR && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, TEST_ARPA)) { r = evdns_server_request_add_ptr_reply(req, NULL, qname, "ZZ.EXAMPLE.COM", 54321); if (r<0) dns_ok = 0; } else if (qtype == EVDNS_TYPE_PTR && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, TEST_IN6)){ r = evdns_server_request_add_ptr_reply(req, NULL, qname, "ZZ-INET6.EXAMPLE.COM", 54322); if (r<0) dns_ok = 0; } else if (qtype == EVDNS_TYPE_A && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, "drop.example.com")) { if (evdns_server_request_drop(req)<0) dns_ok = 0; return; } else { printf("Unexpected question %d %d \"%s\" ", qtype, qclass, qname); dns_ok = 0; } } r = evdns_server_request_respond(req, 0); if (r<0) { printf("Couldn't send reply. "); dns_ok = 0; } } static void dns_server_gethostbyname_cb(int result, char type, int count, int ttl, void *addresses, void *arg) { if (result == DNS_ERR_CANCEL) { if (arg != (void*)(char*)90909) { printf("Unexpected cancelation"); dns_ok = 0; } dns_got_cancel = 1; goto out; } if (result != DNS_ERR_NONE) { printf("Unexpected result %d. ", result); dns_ok = 0; goto out; } if (count != 1) { printf("Unexpected answer count %d. ", count); dns_ok = 0; goto out; } switch (type) { case DNS_IPv4_A: { struct in_addr *in_addrs = addresses; if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { printf("Bad IPv4 response \"%s\" %d. ", inet_ntoa(in_addrs[0]), ttl); dns_ok = 0; goto out; } break; } case DNS_IPv6_AAAA: { #if defined (EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) struct in6_addr *in6_addrs = addresses; char buf[INET6_ADDRSTRLEN+1]; if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) || ttl != 123) { const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf)); printf("Bad IPv6 response \"%s\" %d. ", b, ttl); dns_ok = 0; goto out; } #endif break; } case DNS_PTR: { char **addrs = addresses; if (arg != (void*)6) { if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) { printf("Bad PTR response \"%s\" %d. ", addrs[0], ttl); dns_ok = 0; goto out; } } else { if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") || ttl != 54322) { printf("Bad ipv6 PTR response \"%s\" %d. ", addrs[0], ttl); dns_ok = 0; goto out; } } break; } default: printf("Bad response type %d. ", type); dns_ok = 0; } out: if (++n_server_responses == 3) { event_loopexit(NULL); } } static void dns_server(void) { evutil_socket_t sock=-1; struct sockaddr_in my_addr; struct sockaddr_storage ss; ev_socklen_t slen; struct evdns_server_port *port=NULL; struct in_addr resolve_addr; struct in6_addr resolve_addr6; struct evdns_base *base=NULL; struct evdns_request *req=NULL; dns_ok = 1; base = evdns_base_new(NULL, 0); /* Now configure a nameserver port. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock<0) { tt_abort_perror("socket"); } evutil_make_socket_nonblocking(sock); memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = 0; /* kernel picks */ my_addr.sin_addr.s_addr = htonl(0x7f000001UL); if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { tt_abort_perror("bind"); } slen = sizeof(ss); if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) { tt_abort_perror("getsockname"); } port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); /* Add ourself as the only nameserver, and make sure we really are * the only nameserver. */ evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0); tt_int_op(evdns_base_count_nameservers(base), ==, 1); { struct sockaddr_storage ss2; int slen2; memset(&ss2, 0, sizeof(ss2)); slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, 3); tt_int_op(slen2, ==, slen); tt_int_op(ss2.ss_family, ==, 0); slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, sizeof(ss2)); tt_int_op(slen2, ==, slen); tt_mem_op(&ss2, ==, &ss, slen); slen2 = evdns_base_get_nameserver_addr(base, 1, (struct sockaddr *)&ss2, sizeof(ss2)); tt_int_op(-1, ==, slen2); } /* Send some queries. */ evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH, dns_server_gethostbyname_cb, NULL); evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH, dns_server_gethostbyname_cb, NULL); resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ evdns_base_resolve_reverse(base, &resolve_addr, 0, dns_server_gethostbyname_cb, NULL); memcpy(resolve_addr6.s6_addr, "\xff\xf0\x00\x00\x00\x00\xaa\xaa" "\x11\x11\x00\x00\x00\x00\xef\xef", 16); evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0, dns_server_gethostbyname_cb, (void*)6); req = evdns_base_resolve_ipv4(base, "drop.example.com", DNS_QUERY_NO_SEARCH, dns_server_gethostbyname_cb, (void*)(char*)90909); evdns_cancel_request(base, req); event_dispatch(); tt_assert(dns_got_cancel); test_ok = dns_ok; end: if (port) evdns_close_server_port(port); if (sock >= 0) evutil_closesocket(sock); if (base) evdns_base_free(base, 0); } static int n_replies_left; static struct event_base *exit_base; static struct evdns_server_port *exit_port; struct generic_dns_callback_result { int result; char type; int count; int ttl; size_t addrs_len; void *addrs; char addrs_buf[256]; }; static void generic_dns_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { size_t len; struct generic_dns_callback_result *res = arg; res->result = result; res->type = type; res->count = count; res->ttl = ttl; if (type == DNS_IPv4_A) len = count * 4; else if (type == DNS_IPv6_AAAA) len = count * 16; else if (type == DNS_PTR) len = strlen(addresses)+1; else { res->addrs_len = len = 0; res->addrs = NULL; } if (len) { res->addrs_len = len; if (len > 256) len = 256; memcpy(res->addrs_buf, addresses, len); res->addrs = res->addrs_buf; } --n_replies_left; if (n_replies_left == 0) { if (exit_port) { evdns_close_server_port(exit_port); exit_port = NULL; } else event_base_loopexit(exit_base, NULL); } } static struct regress_dns_server_table search_table[] = { { "host.a.example.com", "err", "3", 0, 0 }, { "host.b.example.com", "err", "3", 0, 0 }, { "host.c.example.com", "A", "11.22.33.44", 0, 0 }, { "host2.a.example.com", "err", "3", 0, 0 }, { "host2.b.example.com", "A", "200.100.0.100", 0, 0 }, { "host2.c.example.com", "err", "3", 0, 0 }, { "hostn.a.example.com", "errsoa", "0", 0, 0 }, { "hostn.b.example.com", "errsoa", "3", 0, 0 }, { "hostn.c.example.com", "err", "0", 0, 0 }, { "host", "err", "3", 0, 0 }, { "host2", "err", "3", 0, 0 }, { "*", "err", "3", 0, 0 }, { NULL, NULL, NULL, 0, 0 } }; static void dns_search_test_impl(void *arg, int lower) { struct regress_dns_server_table table[ARRAY_SIZE(search_table)]; struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r[8]; size_t i; for (i = 0; i < ARRAY_SIZE(table); ++i) { table[i] = search_table[i]; table[i].lower = lower; } tt_assert(regress_dnsserver(base, &portnum, table)); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, 0); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); evdns_base_search_add(dns, "a.example.com"); evdns_base_search_add(dns, "b.example.com"); evdns_base_search_add(dns, "c.example.com"); n_replies_left = ARRAY_SIZE(r); exit_base = base; evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]); evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]); evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]); evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]); evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]); evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]); evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]); evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]); event_base_dispatch(base); tt_int_op(r[0].type, ==, DNS_IPv4_A); tt_int_op(r[0].count, ==, 1); tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c)); tt_int_op(r[1].type, ==, DNS_IPv4_A); tt_int_op(r[1].count, ==, 1); tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064)); tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST); tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST); tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST); tt_int_op(r[5].result, ==, DNS_ERR_NODATA); tt_int_op(r[5].ttl, ==, 42); tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST); tt_int_op(r[6].ttl, ==, 42); tt_int_op(r[7].result, ==, DNS_ERR_NODATA); tt_int_op(r[7].ttl, ==, 0); end: if (dns) evdns_base_free(dns, 0); regress_clean_dnsserver(); } static void dns_search_empty_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; dns = evdns_base_new(base, 0); evdns_base_search_add(dns, "whatever.example.com"); n_replies_left = 1; exit_base = base; tt_ptr_op(evdns_base_resolve_ipv4(dns, "", 0, generic_dns_callback, NULL), ==, NULL); end: if (dns) evdns_base_free(dns, 0); } static void dns_search_test(void *arg) { dns_search_test_impl(arg, 0); } static void dns_search_lower_test(void *arg) { dns_search_test_impl(arg, 1); } static int request_count = 0; static struct evdns_request *current_req = NULL; static void search_cancel_server_cb(struct evdns_server_request *req, void *data) { const char *question; if (req->nquestions != 1) TT_DIE(("Only handling one question at a time; got %d", req->nquestions)); question = req->questions[0]->name; TT_BLATHER(("got question, %s", question)); tt_assert(request_count > 0); tt_assert(!evdns_server_request_respond(req, 3)); if (!--request_count) evdns_cancel_request(NULL, current_req); end: ; } static void dns_search_cancel_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; struct evdns_server_port *port = NULL; ev_uint16_t portnum = 0; struct generic_dns_callback_result r1; char buf[64]; port = regress_get_dnsserver(base, &portnum, NULL, search_cancel_server_cb, NULL); tt_assert(port); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, 0); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); evdns_base_search_add(dns, "a.example.com"); evdns_base_search_add(dns, "b.example.com"); evdns_base_search_add(dns, "c.example.com"); evdns_base_search_add(dns, "d.example.com"); exit_base = base; request_count = 3; n_replies_left = 1; current_req = evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r1); event_base_dispatch(base); tt_int_op(r1.result, ==, DNS_ERR_CANCEL); end: if (port) evdns_close_server_port(port); if (dns) evdns_base_free(dns, 0); } static void fail_server_cb(struct evdns_server_request *req, void *data) { const char *question; int *count = data; struct in_addr in; /* Drop the first N requests that we get. */ if (*count > 0) { --*count; tt_want(! evdns_server_request_drop(req)); return; } if (req->nquestions != 1) TT_DIE(("Only handling one question at a time; got %d", req->nquestions)); question = req->questions[0]->name; if (!evutil_ascii_strcasecmp(question, "google.com")) { /* Detect a probe, and get out of the loop. */ event_base_loopexit(exit_base, NULL); } tt_assert(evutil_inet_pton(AF_INET, "16.32.64.128", &in)); evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, 100); tt_assert(! evdns_server_request_respond(req, 0)) return; end: tt_want(! evdns_server_request_drop(req)); } static void dns_retry_test_impl(void *arg, int flags) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_server_port *port = NULL; struct evdns_base *dns = NULL; int drop_count = 2; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r1; port = regress_get_dnsserver(base, &portnum, NULL, fail_server_cb, &drop_count); tt_assert(port); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, flags); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); tt_assert(! evdns_base_set_option(dns, "timeout", "0.2")); tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10")); tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.1")); evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r1); n_replies_left = 1; exit_base = base; event_base_dispatch(base); tt_int_op(drop_count, ==, 0); tt_int_op(r1.type, ==, DNS_IPv4_A); tt_int_op(r1.count, ==, 1); tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); /* Now try again, but this time have the server get treated as * failed, so we can send it a test probe. */ drop_count = 4; tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2")); tt_assert(! evdns_base_set_option(dns, "attempts:", "3")); memset(&r1, 0, sizeof(r1)); evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r1); n_replies_left = 2; /* This will run until it answers the "google.com" probe request. */ event_base_dispatch(base); /* We'll treat the server as failed here. */ tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT); /* It should work this time. */ tt_int_op(drop_count, ==, 0); evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r1); event_base_dispatch(base); tt_int_op(r1.result, ==, DNS_ERR_NONE); tt_int_op(r1.type, ==, DNS_IPv4_A); tt_int_op(r1.count, ==, 1); tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); end: if (dns) evdns_base_free(dns, 0); if (port) evdns_close_server_port(port); } static void dns_retry_test(void *arg) { dns_retry_test_impl(arg, 0); } static void dns_retry_disable_when_inactive_test(void *arg) { dns_retry_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); } static struct regress_dns_server_table internal_error_table[] = { /* Error 4 (NOTIMPL) makes us reissue the request to another server if we can. XXXX we should reissue under a much wider set of circumstances! */ { "foof.example.com", "err", "4", 0, 0 }, { NULL, NULL, NULL, 0, 0 } }; static struct regress_dns_server_table reissue_table[] = { { "foof.example.com", "A", "240.15.240.15", 0, 0 }, { NULL, NULL, NULL, 0, 0 } }; static void dns_reissue_test_impl(void *arg, int flags) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_server_port *port1 = NULL, *port2 = NULL; struct evdns_base *dns = NULL; struct generic_dns_callback_result r1; ev_uint16_t portnum1 = 0, portnum2=0; char buf1[64], buf2[64]; port1 = regress_get_dnsserver(base, &portnum1, NULL, regress_dns_server_cb, internal_error_table); tt_assert(port1); port2 = regress_get_dnsserver(base, &portnum2, NULL, regress_dns_server_cb, reissue_table); tt_assert(port2); evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1); evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2); dns = evdns_base_new(base, flags); tt_assert(!evdns_base_nameserver_ip_add(dns, buf1)); tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3")); tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2")); tt_assert(! evdns_base_set_option(dns, "attempts:", "5")); memset(&r1, 0, sizeof(r1)); evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r1); /* Add this after, so that we are sure to get a reissue. */ tt_assert(!evdns_base_nameserver_ip_add(dns, buf2)); n_replies_left = 1; exit_base = base; event_base_dispatch(base); tt_int_op(r1.result, ==, DNS_ERR_NONE); tt_int_op(r1.type, ==, DNS_IPv4_A); tt_int_op(r1.count, ==, 1); tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f)); /* Make sure we dropped at least once. */ tt_int_op(internal_error_table[0].seen, >, 0); end: if (dns) evdns_base_free(dns, 0); if (port1) evdns_close_server_port(port1); if (port2) evdns_close_server_port(port2); } static void dns_reissue_test(void *arg) { dns_reissue_test_impl(arg, 0); } static void dns_reissue_disable_when_inactive_test(void *arg) { dns_reissue_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); } #if 0 static void dumb_bytes_fn(char *p, size_t n) { unsigned i; /* This gets us 6 bits of entropy per transaction ID, which means we * will have probably have collisions and need to pick again. */ for (i=0;ibase; struct evdns_base *dns = NULL; struct evdns_server_port *dns_port = NULL; ev_uint16_t portnum = 0; char buf[64]; int disable_when_inactive = flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE; struct generic_dns_callback_result r[20]; int i; dns_port = regress_get_dnsserver(base, &portnum, NULL, regress_dns_server_cb, reissue_table); tt_assert(dns_port); if (disable_when_inactive) { exit_port = dns_port; } evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, flags); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3")); tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0")); for (i=0;i<20;++i) evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]); n_replies_left = 20; exit_base = base; event_base_dispatch(base); for (i=0;i<20;++i) { tt_int_op(r[i].type, ==, DNS_IPv4_A); tt_int_op(r[i].count, ==, 1); tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f)); } end: if (dns) evdns_base_free(dns, 0); if (exit_port) { evdns_close_server_port(exit_port); exit_port = NULL; } else if (! disable_when_inactive) { evdns_close_server_port(dns_port); } } static void dns_inflight_test(void *arg) { dns_inflight_test_impl(arg, 0); } static void dns_disable_when_inactive_test(void *arg) { dns_inflight_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE); } static void dns_disable_when_inactive_no_ns_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base, *inactive_base; struct evdns_base *dns = NULL; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r; inactive_base = event_base_new(); tt_assert(inactive_base); /** Create dns server with inactive base, to avoid replying to clients */ tt_assert(regress_dnsserver(inactive_base, &portnum, search_table)); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); tt_assert(! evdns_base_set_option(dns, "timeout:", "0.1")); evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r); n_replies_left = 1; exit_base = base; event_base_dispatch(base); tt_int_op(n_replies_left, ==, 0); tt_int_op(r.result, ==, DNS_ERR_TIMEOUT); tt_int_op(r.count, ==, 0); tt_ptr_op(r.addrs, ==, NULL); end: if (dns) evdns_base_free(dns, 0); regress_clean_dnsserver(); if (inactive_base) event_base_free(inactive_base); } static void dns_initialize_nameservers_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; dns = evdns_base_new(base, 0); tt_assert(dns); tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); evdns_base_free(dns, 0); dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS); tt_assert(dns); tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr)); end: if (dns) evdns_base_free(dns, 0); } #ifndef _WIN32 #define RESOLV_FILE "empty-resolv.conf" static void dns_nameservers_no_default_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; int ok = access(RESOLV_FILE, R_OK); tt_assert(ok); dns = evdns_base_new(base, 0); tt_assert(dns); tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); /* We cannot test * EVDNS_BASE_INITIALIZE_NAMESERVERS|EVDNS_BASE_NAMESERVERS_NO_DEFAULT * because we cannot mock "/etc/resolv.conf" (yet). */ evdns_base_resolv_conf_parse(dns, DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT, RESOLV_FILE); tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); evdns_base_resolv_conf_parse(dns, DNS_OPTIONS_ALL, RESOLV_FILE); tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr)); end: if (dns) evdns_base_free(dns, 0); } #endif /* === Test for bufferevent_socket_connect_hostname */ static int total_connected_or_failed = 0; static int total_n_accepted = 0; static struct event_base *be_connect_hostname_base = NULL; /* Implements a DNS server for the connect_hostname test and the * getaddrinfo_async test */ static void be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data) { int i; int *n_got_p=data; int added_any=0; ++*n_got_p; for (i = 0; i < req->nquestions; ++i) { const int qtype = req->questions[i]->type; const int qclass = req->questions[i]->dns_question_class; const char *qname = req->questions[i]->name; struct in_addr ans; struct in6_addr ans6; memset(&ans6, 0, sizeof(ans6)); TT_BLATHER(("Got question about %s, type=%d", qname, qtype)); if (qtype == EVDNS_TYPE_A && qclass == EVDNS_CLASS_INET && !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) { ans.s_addr = htonl(0x7f000001); evdns_server_request_add_a_reply(req, qname, 1, &ans.s_addr, 2000); added_any = 1; } else if (!evutil_ascii_strcasecmp(qname, "nosuchplace.example.com")) { /* ok, just say notfound. */ } else if (!evutil_ascii_strcasecmp(qname, "both.example.com")) { if (qtype == EVDNS_TYPE_A) { ans.s_addr = htonl(0x50502020); evdns_server_request_add_a_reply(req, qname, 1, &ans.s_addr, 2000); added_any = 1; } else if (qtype == EVDNS_TYPE_AAAA) { ans6.s6_addr[0] = 0x80; ans6.s6_addr[1] = 0xff; ans6.s6_addr[14] = 0xbb; ans6.s6_addr[15] = 0xbb; evdns_server_request_add_aaaa_reply(req, qname, 1, &ans6.s6_addr, 2000); added_any = 1; } evdns_server_request_add_cname_reply(req, qname, "both-canonical.example.com", 1000); } else if (!evutil_ascii_strcasecmp(qname, "v4only.example.com") || !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) { if (qtype == EVDNS_TYPE_A) { ans.s_addr = htonl(0x12345678); evdns_server_request_add_a_reply(req, qname, 1, &ans.s_addr, 2000); added_any = 1; } else if (!evutil_ascii_strcasecmp(qname, "v4assert.example.com")) { TT_FAIL(("Got an AAAA request for v4assert")); } } else if (!evutil_ascii_strcasecmp(qname, "v6only.example.com") || !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) { if (qtype == EVDNS_TYPE_AAAA) { ans6.s6_addr[0] = 0x0b; ans6.s6_addr[1] = 0x0b; ans6.s6_addr[14] = 0xf0; ans6.s6_addr[15] = 0x0d; evdns_server_request_add_aaaa_reply(req, qname, 1, &ans6.s6_addr, 2000); added_any = 1; } else if (!evutil_ascii_strcasecmp(qname, "v6assert.example.com")) { TT_FAIL(("Got a A request for v6assert")); } } else if (!evutil_ascii_strcasecmp(qname, "v6timeout.example.com")) { if (qtype == EVDNS_TYPE_A) { ans.s_addr = htonl(0xabcdef01); evdns_server_request_add_a_reply(req, qname, 1, &ans.s_addr, 2000); added_any = 1; } else if (qtype == EVDNS_TYPE_AAAA) { /* Let the v6 request time out.*/ evdns_server_request_drop(req); return; } } else if (!evutil_ascii_strcasecmp(qname, "v4timeout.example.com")) { if (qtype == EVDNS_TYPE_AAAA) { ans6.s6_addr[0] = 0x0a; ans6.s6_addr[1] = 0x0a; ans6.s6_addr[14] = 0xff; ans6.s6_addr[15] = 0x01; evdns_server_request_add_aaaa_reply(req, qname, 1, &ans6.s6_addr, 2000); added_any = 1; } else if (qtype == EVDNS_TYPE_A) { /* Let the v4 request time out.*/ evdns_server_request_drop(req); return; } } else if (!evutil_ascii_strcasecmp(qname, "v6timeout-nonexist.example.com")) { if (qtype == EVDNS_TYPE_A) { /* Fall through, give an nexist. */ } else if (qtype == EVDNS_TYPE_AAAA) { /* Let the v6 request time out.*/ evdns_server_request_drop(req); return; } } else if (!evutil_ascii_strcasecmp(qname, "all-timeout.example.com")) { /* drop all requests */ evdns_server_request_drop(req); return; } else { TT_GRIPE(("Got weird request for %s",qname)); } } if (added_any) { TT_BLATHER(("answering")); evdns_server_request_respond(req, 0); } else { TT_BLATHER(("saying nexist.")); evdns_server_request_respond(req, 3); } } /* Implements a listener for connect_hostname test. */ static void nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s, int socklen, void *arg) { int *p = arg; (*p)++; ++total_n_accepted; /* don't do anything with the socket; let it close when we exit() */ if (total_n_accepted >= 3 && total_connected_or_failed >= 5) event_base_loopexit(be_connect_hostname_base, NULL); } struct be_conn_hostname_result { int dnserr; int what; }; /* Bufferevent event callback for the connect_hostname test: remembers what * event we got. */ static void be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx) { struct be_conn_hostname_result *got = ctx; if (got->what) { TT_FAIL(("Two events on one bufferevent. %d,%d", got->what, (int)what)); } TT_BLATHER(("Got a bufferevent event %d", what)); got->what = what; if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) { int expected = 3; int r = bufferevent_socket_get_dns_error(bev); if (r) { got->dnserr = r; TT_BLATHER(("DNS error %d: %s", r, evutil_gai_strerror(r))); } ++total_connected_or_failed; TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed)); /** emfile test */ if (errno == EMFILE) { expected = 0; } if (total_n_accepted >= expected && total_connected_or_failed >= 5) event_base_loopexit(be_connect_hostname_base, NULL); } } static void test_bufferevent_connect_hostname(void *arg) { struct basic_test_data *data = arg; struct evconnlistener *listener = NULL; struct bufferevent *be[5]; struct be_conn_hostname_result be_outcome[ARRAY_SIZE(be)]; int expect_err; struct evdns_base *dns=NULL; struct evdns_server_port *port=NULL; struct sockaddr_in sin; int listener_port=-1; ev_uint16_t dns_port=0; int n_accept=0, n_dns=0; char buf[128]; int emfile = data->setup_data && !strcmp(data->setup_data, "emfile"); unsigned i; int ret; be_connect_hostname_base = data->base; /* Bind an address and figure out what port it's on. */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; listener = evconnlistener_new_bind(data->base, nil_accept_cb, &n_accept, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener); listener_port = regress_get_socket_port( evconnlistener_get_fd(listener)); port = regress_get_dnsserver(data->base, &dns_port, NULL, be_getaddrinfo_server_cb, &n_dns); tt_assert(port); tt_int_op(dns_port, >=, 0); /* Start an evdns_base that uses the server as its resolver. */ dns = evdns_base_new(data->base, 0); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port); evdns_base_nameserver_ip_add(dns, buf); #ifdef EVENT__HAVE_SETRLIMIT if (emfile) { int fd = socket(AF_INET, SOCK_STREAM, 0); struct rlimit file = { fd, fd }; tt_int_op(fd, >=, 0); tt_assert(!close(fd)); tt_assert(!setrlimit(RLIMIT_NOFILE, &file)); } #endif /* Now, finally, at long last, launch the bufferevents. One should do * a failing lookup IP, one should do a successful lookup by IP, * and one should do a successful lookup by hostname. */ for (i = 0; i < ARRAY_SIZE(be); ++i) { memset(&be_outcome[i], 0, sizeof(be_outcome[i])); be[i] = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(be[i], NULL, NULL, be_connect_hostname_event_cb, &be_outcome[i]); } /* Use the blocking resolver. This one will fail if your resolver * can't resolve localhost to 127.0.0.1 */ tt_assert(!bufferevent_socket_connect_hostname(be[3], NULL, AF_INET, "localhost", listener_port)); /* Use the blocking resolver with a nonexistent hostname. */ tt_assert(!bufferevent_socket_connect_hostname(be[4], NULL, AF_INET, "nonesuch.nowhere.example.com", 80)); { /* The blocking resolver will use the system nameserver, which * might tell us anything. (Yes, some twits even pretend that * example.com is real.) Let's see what answer to expect. */ struct evutil_addrinfo hints, *ai = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; expect_err = evutil_getaddrinfo( "nonesuch.nowhere.example.com", "80", &hints, &ai); } /* Launch an async resolve that will fail. */ tt_assert(!bufferevent_socket_connect_hostname(be[0], dns, AF_INET, "nosuchplace.example.com", listener_port)); /* Connect to the IP without resolving. */ tt_assert(!bufferevent_socket_connect_hostname(be[1], dns, AF_INET, "127.0.0.1", listener_port)); /* Launch an async resolve that will succeed. */ tt_assert(!bufferevent_socket_connect_hostname(be[2], dns, AF_INET, "nobodaddy.example.com", listener_port)); ret = event_base_dispatch(data->base); #ifdef __sun__ if (emfile && !strcmp(event_base_get_method(data->base), "devpoll")) { tt_int_op(ret, ==, -1); /** DP_POLL failed */ tt_skip(); } else #endif { tt_int_op(ret, ==, 0); } tt_int_op(be_outcome[0].what, ==, BEV_EVENT_ERROR); tt_int_op(be_outcome[0].dnserr, ==, EVUTIL_EAI_NONAME); tt_int_op(be_outcome[1].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR); tt_int_op(be_outcome[1].dnserr, ==, 0); tt_int_op(be_outcome[2].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR); tt_int_op(be_outcome[2].dnserr, ==, 0); tt_int_op(be_outcome[3].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR); if (!emfile) { tt_int_op(be_outcome[3].dnserr, ==, 0); } else { tt_int_op(be_outcome[3].dnserr, !=, 0); } if (expect_err) { tt_int_op(be_outcome[4].what, ==, BEV_EVENT_ERROR); tt_int_op(be_outcome[4].dnserr, ==, expect_err); } if (emfile) { tt_int_op(n_accept, ==, 0); } else { tt_int_op(n_accept, ==, 3); } tt_int_op(n_dns, ==, 2); end: if (listener) evconnlistener_free(listener); if (port) evdns_close_server_port(port); if (dns) evdns_base_free(dns, 0); for (i = 0; i < ARRAY_SIZE(be); ++i) { if (be[i]) bufferevent_free(be[i]); } } struct gai_outcome { int err; struct evutil_addrinfo *ai; }; static int n_gai_results_pending = 0; static struct event_base *exit_base_on_no_pending_results = NULL; static void gai_cb(int err, struct evutil_addrinfo *res, void *ptr) { struct gai_outcome *go = ptr; go->err = err; go->ai = res; if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results) event_base_loopexit(exit_base_on_no_pending_results, NULL); if (n_gai_results_pending < 900) TT_BLATHER(("Got an answer; expecting %d more.", n_gai_results_pending)); } static void cancel_gai_cb(evutil_socket_t fd, short what, void *ptr) { struct evdns_getaddrinfo_request *r = ptr; evdns_getaddrinfo_cancel(r); } static void test_getaddrinfo_async(void *arg) { struct basic_test_data *data = arg; struct evutil_addrinfo hints, *a; struct gai_outcome local_outcome; struct gai_outcome a_out[12]; unsigned i; struct evdns_getaddrinfo_request *r; char buf[128]; struct evdns_server_port *port = NULL; ev_uint16_t dns_port = 0; int n_dns_questions = 0; struct evdns_base *dns_base; memset(a_out, 0, sizeof(a_out)); memset(&local_outcome, 0, sizeof(local_outcome)); dns_base = evdns_base_new(data->base, 0); tt_assert(dns_base); /* for localhost */ evdns_base_load_hosts(dns_base, NULL); tt_assert(! evdns_base_set_option(dns_base, "timeout", "0.3")); tt_assert(! evdns_base_set_option(dns_base, "getaddrinfo-allow-skew", "0.2")); n_gai_results_pending = 10000; /* don't think about exiting yet. */ /* 1. Try some cases that will never hit the asynchronous resolver. */ /* 1a. Simple case with a symbolic service name */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; memset(&local_outcome, 0, sizeof(local_outcome)); r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http", &hints, gai_cb, &local_outcome); tt_assert(! r); if (!local_outcome.err) { tt_ptr_op(local_outcome.ai,!=,NULL); test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; } else { TT_BLATHER(("Apparently we have no getservbyname.")); } /* 1b. EVUTIL_AI_NUMERICHOST is set */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = EVUTIL_AI_NUMERICHOST; memset(&local_outcome, 0, sizeof(local_outcome)); r = evdns_getaddrinfo(dns_base, "www.google.com", "80", &hints, gai_cb, &local_outcome); tt_ptr_op(r,==,NULL); tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME); tt_ptr_op(local_outcome.ai,==,NULL); /* 1c. We give a numeric address (ipv6) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_UNSPEC; hints.ai_protocol = IPPROTO_TCP; r = evdns_getaddrinfo(dns_base, "f::f", "8008", &hints, gai_cb, &local_outcome); tt_assert(!r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); tt_ptr_op(local_outcome.ai->ai_next,==,NULL); test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 1d. We give a numeric address (ipv4) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_UNSPEC; r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL, &hints, gai_cb, &local_outcome); tt_assert(!r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP); tt_assert(a); test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP); a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP); tt_assert(a); test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 1e. nodename is NULL (bind) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = EVUTIL_AI_PASSIVE; r = evdns_getaddrinfo(dns_base, NULL, "9090", &hints, gai_cb, &local_outcome); tt_assert(!r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); /* we should get a v4 address of 0.0.0.0... */ a = ai_find_by_family(local_outcome.ai, PF_INET); tt_assert(a); test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP); /* ... and a v6 address of ::0 */ a = ai_find_by_family(local_outcome.ai, PF_INET6); tt_assert(a); test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 1f. nodename is NULL (connect) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; r = evdns_getaddrinfo(dns_base, NULL, "2", &hints, gai_cb, &local_outcome); tt_assert(!r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); /* we should get a v4 address of 127.0.0.1 .... */ a = ai_find_by_family(local_outcome.ai, PF_INET); tt_assert(a); test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP); /* ... and a v6 address of ::1 */ a = ai_find_by_family(local_outcome.ai, PF_INET6); tt_assert(a); test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 1g. We find localhost immediately. (pf_unspec) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80", &hints, gai_cb, &local_outcome); tt_assert(!r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); /* we should get a v4 address of 127.0.0.1 .... */ a = ai_find_by_family(local_outcome.ai, PF_INET); tt_assert(a); test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP); /* ... and a v6 address of ::1 */ a = ai_find_by_family(local_outcome.ai, PF_INET6); tt_assert(a); test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 1g. We find localhost immediately. (pf_inet6) */ memset(&hints, 0, sizeof(hints)); memset(&local_outcome, 0, sizeof(local_outcome)); hints.ai_family = PF_INET6; hints.ai_socktype = SOCK_STREAM; r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999", &hints, gai_cb, &local_outcome); tt_assert(! r); tt_int_op(local_outcome.err,==,0); tt_assert(local_outcome.ai); a = local_outcome.ai; test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP); tt_ptr_op(a->ai_next, ==, NULL); evutil_freeaddrinfo(local_outcome.ai); local_outcome.ai = NULL; /* 2. Okay, now we can actually test the asynchronous resolver. */ /* Start a dummy local dns server... */ port = regress_get_dnsserver(data->base, &dns_port, NULL, be_getaddrinfo_server_cb, &n_dns_questions); tt_assert(port); tt_int_op(dns_port, >=, 0); /* ... and tell the evdns_base about it. */ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port); evdns_base_nameserver_ip_add(dns_base, buf); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = EVUTIL_AI_CANONNAME; /* 0: Request for both.example.com should return both addresses. */ r = evdns_getaddrinfo(dns_base, "both.example.com", "8000", &hints, gai_cb, &a_out[0]); tt_assert(r); /* 1: Request for v4only.example.com should return one address. */ r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001", &hints, gai_cb, &a_out[1]); tt_assert(r); /* 2: Request for v6only.example.com should return one address. */ hints.ai_flags = 0; r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002", &hints, gai_cb, &a_out[2]); tt_assert(r); /* 3: PF_INET request for v4assert.example.com should not generate a * v6 request. The server will fail the test if it does. */ hints.ai_family = PF_INET; r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003", &hints, gai_cb, &a_out[3]); tt_assert(r); /* 4: PF_INET6 request for v6assert.example.com should not generate a * v4 request. The server will fail the test if it does. */ hints.ai_family = PF_INET6; r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004", &hints, gai_cb, &a_out[4]); tt_assert(r); /* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */ hints.ai_family = PF_INET; r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005", &hints, gai_cb, &a_out[5]); tt_assert(r); /* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST. */ hints.ai_family = PF_UNSPEC; r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006", &hints, gai_cb, &a_out[6]); tt_assert(r); /* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4 * address only. */ hints.ai_family = PF_UNSPEC; r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007", &hints, gai_cb, &a_out[7]); tt_assert(r); /* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give * a NEXIST */ hints.ai_family = PF_UNSPEC; r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com", "8008", &hints, gai_cb, &a_out[8]); tt_assert(r); /* 9: AI_ADDRCONFIG should at least not crash. Can't test it more * without knowing what kind of internet we have. */ hints.ai_flags |= EVUTIL_AI_ADDRCONFIG; r = evdns_getaddrinfo(dns_base, "both.example.com", "8009", &hints, gai_cb, &a_out[9]); tt_assert(r); /* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address * only. */ hints.ai_family = PF_UNSPEC; hints.ai_flags = 0; r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010", &hints, gai_cb, &a_out[10]); tt_assert(r); /* 11: timeout.example.com: cancel it after 100 msec. */ r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011", &hints, gai_cb, &a_out[11]); tt_assert(r); { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100*1000; /* 100 msec */ event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb, r, &tv); } /* XXXXX There are more tests we could do, including: - A test to elicit NODATA. */ n_gai_results_pending = 12; exit_base_on_no_pending_results = data->base; event_base_dispatch(data->base); /* 0: both.example.com */ tt_int_op(a_out[0].err, ==, 0); tt_assert(a_out[0].ai); tt_assert(a_out[0].ai->ai_next); tt_assert(!a_out[0].ai->ai_next->ai_next); a = ai_find_by_family(a_out[0].ai, PF_INET); tt_assert(a); test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP); a = ai_find_by_family(a_out[0].ai, PF_INET6); tt_assert(a); test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP); tt_assert(a_out[0].ai->ai_canonname); tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com"); /* 1: v4only.example.com */ tt_int_op(a_out[1].err, ==, 0); tt_assert(a_out[1].ai); tt_assert(! a_out[1].ai->ai_next); test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP); tt_assert(a_out[1].ai->ai_canonname == NULL); /* 2: v6only.example.com */ tt_int_op(a_out[2].err, ==, 0); tt_assert(a_out[2].ai); tt_assert(! a_out[2].ai->ai_next); test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP); /* 3: v4assert.example.com */ tt_int_op(a_out[3].err, ==, 0); tt_assert(a_out[3].ai); tt_assert(! a_out[3].ai->ai_next); test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP); /* 4: v6assert.example.com */ tt_int_op(a_out[4].err, ==, 0); tt_assert(a_out[4].ai); tt_assert(! a_out[4].ai->ai_next); test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP); /* 5: nosuchplace.example.com (inet) */ tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME); tt_assert(! a_out[5].ai); /* 6: nosuchplace.example.com (unspec) */ tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME); tt_assert(! a_out[6].ai); /* 7: v6timeout.example.com */ tt_int_op(a_out[7].err, ==, 0); tt_assert(a_out[7].ai); tt_assert(! a_out[7].ai->ai_next); test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP); /* 8: v6timeout-nonexist.example.com */ tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME); tt_assert(! a_out[8].ai); /* 9: both (ADDRCONFIG) */ tt_int_op(a_out[9].err, ==, 0); tt_assert(a_out[9].ai); a = ai_find_by_family(a_out[9].ai, PF_INET); if (a) test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP); else tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6)); a = ai_find_by_family(a_out[9].ai, PF_INET6); if (a) test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP); else tt_assert(ai_find_by_family(a_out[9].ai, PF_INET)); /* 10: v4timeout.example.com */ tt_int_op(a_out[10].err, ==, 0); tt_assert(a_out[10].ai); tt_assert(! a_out[10].ai->ai_next); test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP); /* 11: cancelled request. */ tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL); tt_assert(a_out[11].ai == NULL); end: if (local_outcome.ai) evutil_freeaddrinfo(local_outcome.ai); for (i = 0; i < ARRAY_SIZE(a_out); ++i) { if (a_out[i].ai) evutil_freeaddrinfo(a_out[i].ai); } if (port) evdns_close_server_port(port); if (dns_base) evdns_base_free(dns_base, 0); } struct gaic_request_status { int magic; struct event_base *base; struct evdns_base *dns_base; struct evdns_getaddrinfo_request *request; struct event cancel_event; int canceled; }; #define GAIC_MAGIC 0x1234abcd static int gaic_pending = 0; static int gaic_freed = 0; static void gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg) { struct gaic_request_status *status = arg; tt_assert(status->magic == GAIC_MAGIC); status->canceled = 1; evdns_getaddrinfo_cancel(status->request); return; end: event_base_loopexit(status->base, NULL); } static void gaic_server_cb(struct evdns_server_request *req, void *arg) { ev_uint32_t answer = 0x7f000001; tt_assert(req->nquestions); evdns_server_request_add_a_reply(req, req->questions[0]->name, 1, &answer, 100); evdns_server_request_respond(req, 0); return; end: evdns_server_request_respond(req, DNS_ERR_REFUSED); } static void gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg) { struct gaic_request_status *status = arg; struct event_base *base = status->base; tt_assert(status->magic == GAIC_MAGIC); if (result == EVUTIL_EAI_CANCEL) { tt_assert(status->canceled); } event_del(&status->cancel_event); memset(status, 0xf0, sizeof(*status)); free(status); end: if (res) { TT_BLATHER(("evutil_freeaddrinfo(%p)", res)); evutil_freeaddrinfo(res); ++gaic_freed; } if (--gaic_pending <= 0) event_base_loopexit(base, NULL); } static void gaic_launch(struct event_base *base, struct evdns_base *dns_base) { struct gaic_request_status *status = calloc(1,sizeof(*status)); struct timeval tv = { 0, 10000 }; status->magic = GAIC_MAGIC; status->base = base; status->dns_base = dns_base; event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb, status); status->request = evdns_getaddrinfo(dns_base, "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb, status); event_add(&status->cancel_event, &tv); ++gaic_pending; } #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED /* FIXME: We should move this to regress_main.c if anything else needs it.*/ /* Trivial replacements for malloc/free/realloc to check for memory leaks. * Not threadsafe. */ static int allocated_chunks = 0; static void * cnt_malloc(size_t sz) { allocated_chunks += 1; return malloc(sz); } static void * cnt_realloc(void *old, size_t sz) { if (!old) allocated_chunks += 1; if (!sz) allocated_chunks -= 1; return realloc(old, sz); } static void cnt_free(void *ptr) { allocated_chunks -= 1; free(ptr); } struct testleak_env_t { struct event_base *base; struct evdns_base *dns_base; struct evdns_request *req; struct generic_dns_callback_result r; }; static void * testleak_setup(const struct testcase_t *testcase) { struct testleak_env_t *env; allocated_chunks = 0; /* Reset allocation counter, to start allocations from the very beginning. * (this will avoid false-positive negative numbers for allocated_chunks) */ libevent_global_shutdown(); event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free); event_enable_debug_mode(); /* not mm_calloc: we don't want to mess with the count. */ env = calloc(1, sizeof(struct testleak_env_t)); env->base = event_base_new(); env->dns_base = evdns_base_new(env->base, 0); env->req = evdns_base_resolve_ipv4( env->dns_base, "example.com", DNS_QUERY_NO_SEARCH, generic_dns_callback, &env->r); return env; } static int testleak_cleanup(const struct testcase_t *testcase, void *env_) { int ok = 0; struct testleak_env_t *env = env_; tt_assert(env); #ifdef EVENT__DISABLE_DEBUG_MODE tt_int_op(allocated_chunks, ==, 0); #else libevent_global_shutdown(); tt_int_op(allocated_chunks, ==, 0); #endif ok = 1; end: if (env) { if (env->dns_base) evdns_base_free(env->dns_base, 0); if (env->base) event_base_free(env->base); free(env); } return ok; } static struct testcase_setup_t testleak_funcs = { testleak_setup, testleak_cleanup }; static void test_dbg_leak_cancel(void *env_) { /* cancel, loop, free/dns, free/base */ struct testleak_env_t *env = env_; int send_err_shutdown = 1; evdns_cancel_request(env->dns_base, env->req); env->req = 0; /* `req` is freed in callback, that's why one loop is required. */ event_base_loop(env->base, EVLOOP_NONBLOCK); /* send_err_shutdown means nothing as soon as our request is * already canceled */ evdns_base_free(env->dns_base, send_err_shutdown); env->dns_base = 0; event_base_free(env->base); env->base = 0; } static void dbg_leak_resume(void *env_, int cancel, int send_err_shutdown) { /* cancel, loop, free/dns, free/base */ struct testleak_env_t *env = env_; if (cancel) { evdns_cancel_request(env->dns_base, env->req); tt_assert(!evdns_base_resume(env->dns_base)); } else { /* TODO: No nameservers, request can't be processed, must be errored */ tt_assert(!evdns_base_resume(env->dns_base)); } event_base_loop(env->base, EVLOOP_NONBLOCK); /** * Because we don't cancel request, and want our callback to recieve * DNS_ERR_SHUTDOWN, we use deferred callback, and there was: * - one extra malloc(), * @see reply_schedule_callback() * - and one missing free * @see request_finished() (req->handle->pending_cb = 1) * than we don't need to count in testleak_cleanup(), but we can clean them * if we will run loop once again, but *after* evdns base freed. */ evdns_base_free(env->dns_base, send_err_shutdown); env->dns_base = 0; event_base_loop(env->base, EVLOOP_NONBLOCK); end: event_base_free(env->base); env->base = 0; } #define IMPL_DBG_LEAK_RESUME(name, cancel, send_err_shutdown) \ static void \ test_dbg_leak_##name##_(void *env_) \ { \ dbg_leak_resume(env_, cancel, send_err_shutdown); \ } IMPL_DBG_LEAK_RESUME(resume, 0, 0) IMPL_DBG_LEAK_RESUME(cancel_and_resume, 1, 0) IMPL_DBG_LEAK_RESUME(resume_send_err, 0, 1) IMPL_DBG_LEAK_RESUME(cancel_and_resume_send_err, 1, 1) static void test_dbg_leak_shutdown(void *env_) { /* free/dns, loop, free/base */ struct testleak_env_t *env = env_; int send_err_shutdown = 1; /* `req` is freed both with `send_err_shutdown` and without it, * the only difference is `evdns_callback` call */ env->req = 0; evdns_base_free(env->dns_base, send_err_shutdown); env->dns_base = 0; /* `req` is freed in callback, that's why one loop is required */ event_base_loop(env->base, EVLOOP_NONBLOCK); event_base_free(env->base); env->base = 0; } #endif static void test_getaddrinfo_async_cancel_stress(void *ptr) { struct event_base *base; struct evdns_base *dns_base = NULL; struct evdns_server_port *server = NULL; evutil_socket_t fd = -1; struct sockaddr_in sin; struct sockaddr_storage ss; ev_socklen_t slen; unsigned i; base = event_base_new(); dns_base = evdns_base_new(base, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = 0; sin.sin_addr.s_addr = htonl(0x7f000001); if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { tt_abort_perror("socket"); } evutil_make_socket_nonblocking(fd); if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) { tt_abort_perror("bind"); } server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb, base); memset(&ss, 0, sizeof(ss)); slen = sizeof(ss); if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) { tt_abort_perror("getsockname"); } evdns_base_nameserver_sockaddr_add(dns_base, (struct sockaddr*)&ss, slen, 0); for (i = 0; i < 1000; ++i) { gaic_launch(base, dns_base); } event_base_dispatch(base); // at least some was canceled via external event tt_int_op(gaic_freed, !=, 1000); end: if (dns_base) evdns_base_free(dns_base, 1); if (server) evdns_close_server_port(server); if (base) event_base_free(base); if (fd >= 0) evutil_closesocket(fd); } static void dns_client_fail_requests_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; int limit_inflight = data->setup_data && !strcmp(data->setup_data, "limit-inflight"); struct evdns_base *dns = NULL; struct evdns_server_port *dns_port = NULL; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r[20]; unsigned i; dns_port = regress_get_dnsserver(base, &portnum, NULL, regress_dns_server_cb, reissue_table); tt_assert(dns_port); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); if (limit_inflight) tt_assert(!evdns_base_set_option(dns, "max-inflight:", "11")); for (i = 0; i < 20; ++i) evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]); n_replies_left = 20; exit_base = base; evdns_base_free(dns, 1 /** fail requests */); /** run defered callbacks, to trigger UAF */ event_base_dispatch(base); tt_int_op(n_replies_left, ==, 0); for (i = 0; i < 20; ++i) tt_int_op(r[i].result, ==, DNS_ERR_SHUTDOWN); end: evdns_close_server_port(dns_port); } static void getaddrinfo_cb(int err, struct evutil_addrinfo *res, void *ptr) { generic_dns_callback(err, 0, 0, 0, NULL, ptr); } static void dns_client_fail_requests_getaddrinfo_test(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evdns_base *dns = NULL; struct evdns_server_port *dns_port = NULL; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r[20]; int i; dns_port = regress_get_dnsserver(base, &portnum, NULL, regress_dns_server_cb, reissue_table); tt_assert(dns_port); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); for (i = 0; i < 20; ++i) tt_assert(evdns_getaddrinfo(dns, "foof.example.com", "80", NULL, getaddrinfo_cb, &r[i])); n_replies_left = 20; exit_base = base; evdns_base_free(dns, 1 /** fail requests */); /** run defered callbacks, to trigger UAF */ event_base_dispatch(base); tt_int_op(n_replies_left, ==, 0); for (i = 0; i < 20; ++i) tt_int_op(r[i].result, ==, EVUTIL_EAI_FAIL); end: evdns_close_server_port(dns_port); } #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED struct race_param { void *lock; void *reqs_cmpl_cond; int bw_threads; void *bw_threads_exited_cond; volatile int stopping; void *base; void *dns; int locked; }; static void * race_base_run(void *arg) { struct race_param *rp = (struct race_param *)arg; event_base_loop(rp->base, EVLOOP_NO_EXIT_ON_EMPTY); THREAD_RETURN(); } static void * race_busywait_run(void *arg) { struct race_param *rp = (struct race_param *)arg; struct sockaddr_storage ss; while (!rp->stopping) evdns_base_get_nameserver_addr(rp->dns, 0, (struct sockaddr *)&ss, sizeof(ss)); EVLOCK_LOCK(rp->lock, 0); if (--rp->bw_threads == 0) EVTHREAD_COND_SIGNAL(rp->bw_threads_exited_cond); EVLOCK_UNLOCK(rp->lock, 0); THREAD_RETURN(); } static void race_gai_cb(int result, struct evutil_addrinfo *res, void *arg) { struct race_param *rp = arg; (void)result; (void)res; --n_replies_left; if (n_replies_left == 0) { EVLOCK_LOCK(rp->lock, 0); EVTHREAD_COND_SIGNAL(rp->reqs_cmpl_cond); EVLOCK_UNLOCK(rp->lock, 0); } } static void getaddrinfo_race_gotresolve_test(void *arg) { struct race_param rp; struct evdns_server_port *dns_port = NULL; ev_uint16_t portnum = 0; char buf[64]; int i; // Some stress is needed to yield inside getaddrinfo between resolve_ipv4 and resolve_ipv6 int n_reqs = 16384; #ifdef _SC_NPROCESSORS_ONLN int n_threads = sysconf(_SC_NPROCESSORS_ONLN) + 1; #else int n_threads = 17; #endif THREAD_T thread[n_threads]; struct timeval tv; (void)arg; evthread_use_pthreads(); rp.base = event_base_new(); tt_assert(rp.base); if (evthread_make_base_notifiable(rp.base) < 0) tt_abort_msg("Couldn't make base notifiable!"); dns_port = regress_get_dnsserver(rp.base, &portnum, NULL, regress_dns_server_cb, reissue_table); tt_assert(dns_port); evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); rp.dns = evdns_base_new(rp.base, 0); tt_assert(!evdns_base_nameserver_ip_add(rp.dns, buf)); n_replies_left = n_reqs; EVTHREAD_ALLOC_LOCK(rp.lock, 0); EVTHREAD_ALLOC_COND(rp.reqs_cmpl_cond); EVTHREAD_ALLOC_COND(rp.bw_threads_exited_cond); tt_assert(rp.lock); tt_assert(rp.reqs_cmpl_cond); tt_assert(rp.bw_threads_exited_cond); rp.bw_threads = 0; rp.stopping = 0; // Run resolver thread THREAD_START(thread[0], race_base_run, &rp); // Run busy-wait threads used to force yield this thread for (i = 1; i < n_threads; i++) { rp.bw_threads++; THREAD_START(thread[i], race_busywait_run, &rp); } EVLOCK_LOCK(rp.lock, 0); rp.locked = 1; for (i = 0; i < n_reqs; ++i) { tt_assert(evdns_getaddrinfo(rp.dns, "foof.example.com", "80", NULL, race_gai_cb, &rp)); // This magic along with busy-wait threads make this thread yield frequently if (i % 100 == 0) { tv.tv_sec = 0; tv.tv_usec = 10000; evutil_usleep_(&tv); } } exit_base = rp.base; // Wait for some time tv.tv_sec = 5; tv.tv_usec = 0; EVTHREAD_COND_WAIT_TIMED(rp.reqs_cmpl_cond, rp.lock, &tv); // Stop busy-wait threads tv.tv_sec = 1; tv.tv_usec = 0; rp.stopping = 1; tt_assert(EVTHREAD_COND_WAIT_TIMED(rp.bw_threads_exited_cond, rp.lock, &tv) == 0); EVLOCK_UNLOCK(rp.lock, 0); rp.locked = 0; evdns_base_free(rp.dns, 1 /** fail requests */); tt_int_op(n_replies_left, ==, 0); end: if (rp.locked) EVLOCK_UNLOCK(rp.lock, 0); EVTHREAD_FREE_LOCK(rp.lock, 0); EVTHREAD_FREE_COND(rp.reqs_cmpl_cond); EVTHREAD_FREE_COND(rp.bw_threads_exited_cond); evdns_close_server_port(dns_port); event_base_loopbreak(rp.base); event_base_free(rp.base); } #endif static void test_set_so_rcvbuf_so_sndbuf(void *arg) { struct basic_test_data *data = arg; struct evdns_base *dns_base; dns_base = evdns_base_new(data->base, 0); tt_assert(dns_base); tt_assert(!evdns_base_set_option(dns_base, "so-rcvbuf", "10240")); tt_assert(!evdns_base_set_option(dns_base, "so-sndbuf", "10240")); /* actually check SO_RCVBUF/SO_SNDBUF not fails */ tt_assert(!evdns_base_nameserver_ip_add(dns_base, "127.0.0.1")); end: if (dns_base) evdns_base_free(dns_base, 0); } static void test_set_option(void *arg) { #define SUCCESS 0 #define FAIL -1 struct basic_test_data *data = arg; struct evdns_base *dns_base; size_t i; /* Option names are allowed to have ':' at the end. * So all test option names come in pairs. */ const char *int_options[] = { "ndots", "ndots:", "max-timeouts", "max-timeouts:", "max-inflight", "max-inflight:", "attempts", "attempts:", "randomize-case", "randomize-case:", "so-rcvbuf", "so-rcvbuf:", "so-sndbuf", "so-sndbuf:", }; const char *timeval_options[] = { "timeout", "timeout:", "getaddrinfo-allow-skew", "getaddrinfo-allow-skew:", "initial-probe-timeout", "initial-probe-timeout:", }; const char *addr_port_options[] = { "bind-to", "bind-to:", }; dns_base = evdns_base_new(data->base, 0); tt_assert(dns_base); for (i = 0; i < ARRAY_SIZE(int_options); ++i) { tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "0")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "1")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "10000")); tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "foo")); tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "3.14")); } for (i = 0; i < ARRAY_SIZE(timeval_options); ++i) { tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "1")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "0.001")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "3.14")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "10000")); tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "0")); tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "foo")); } for (i = 0; i < ARRAY_SIZE(addr_port_options); ++i) { tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "8.8.8.8:80")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "1.2.3.4")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "::1:82")); tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "3::4")); tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "3.14")); tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "foo")); } #undef SUCCESS #undef FAIL end: if (dns_base) evdns_base_free(dns_base, 0); } #define DNS_LEGACY(name, flags) \ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \ dns_##name } struct testcase_t dns_testcases[] = { DNS_LEGACY(server, TT_FORK|TT_NEED_BASE), DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT), { "resolve_reverse", dns_resolve_reverse, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL }, { "search_empty", dns_search_empty_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "search_lower", dns_search_lower_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "search_cancel", dns_search_cancel_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "retry_disable_when_inactive", dns_retry_disable_when_inactive_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "reissue_disable_when_inactive", dns_reissue_disable_when_inactive_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "bufferevent_connect_hostname", test_bufferevent_connect_hostname, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, #ifdef EVENT__HAVE_SETRLIMIT { "bufferevent_connect_hostname_emfile", test_bufferevent_connect_hostname, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"emfile" }, #endif { "disable_when_inactive", dns_disable_when_inactive_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "initialize_nameservers", dns_initialize_nameservers_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, #ifndef _WIN32 { "nameservers_no_default", dns_nameservers_no_default_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, #endif { "getaddrinfo_async", test_getaddrinfo_async, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress, TT_FORK, NULL, NULL }, #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED { "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL }, { "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL }, { "leak_resume", test_dbg_leak_resume_, TT_FORK, &testleak_funcs, NULL }, { "leak_cancel_and_resume", test_dbg_leak_cancel_and_resume_, TT_FORK, &testleak_funcs, NULL }, { "leak_resume_send_err", test_dbg_leak_resume_send_err_, TT_FORK, &testleak_funcs, NULL }, { "leak_cancel_and_resume_send_err", test_dbg_leak_cancel_and_resume_send_err_, TT_FORK, &testleak_funcs, NULL }, #endif { "client_fail_requests", dns_client_fail_requests_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, { "client_fail_waiting_requests", dns_client_fail_requests_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, (char*)"limit-inflight" }, { "client_fail_requests_getaddrinfo", dns_client_fail_requests_getaddrinfo_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL }, #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED { "getaddrinfo_race_gotresolve", getaddrinfo_race_gotresolve_test, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL }, #endif { "set_SO_RCVBUF_SO_SNDBUF", test_set_so_rcvbuf_so_sndbuf, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "set_options", test_set_option, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, END_OF_TESTCASES }; lldpd-1.0.13/libevent/test/regress_util.c0000644000076400001440000012506714111362571021047 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Nick Mathewson and Niels Provos * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** For event_debug() usage/coverage */ #define EVENT_VISIBILITY_WANT_DLLIMPORT #include "../util-internal.h" #ifdef _WIN32 #include #include #include #endif #include "event2/event-config.h" #include #ifndef _WIN32 #include #include #include #include #endif #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #ifdef EVENT__HAVE_SYS_WAIT_H #include #endif #include #include #include #include #include "event2/event.h" #include "event2/util.h" #include "../ipv6-internal.h" #include "../log-internal.h" #include "../strlcpy-internal.h" #include "../mm-internal.h" #include "../time-internal.h" #include "regress.h" enum entry_status { NORMAL, CANONICAL, BAD }; /* This is a big table of results we expect from generating and parsing */ static struct ipv4_entry { const char *addr; ev_uint32_t res; enum entry_status status; } ipv4_entries[] = { { "1.2.3.4", 0x01020304u, CANONICAL }, { "255.255.255.255", 0xffffffffu, CANONICAL }, { "256.0.0.0", 0, BAD }, { "ABC", 0, BAD }, { "1.2.3.4.5", 0, BAD }, { "176.192.208.244", 0xb0c0d0f4, CANONICAL }, { NULL, 0, BAD }, }; static struct ipv6_entry { const char *addr; ev_uint32_t res[4]; enum entry_status status; } ipv6_entries[] = { { "::", { 0, 0, 0, 0, }, CANONICAL }, { "0:0:0:0:0:0:0:0", { 0, 0, 0, 0, }, NORMAL }, { "::1", { 0, 0, 0, 1, }, CANONICAL }, { "::1.2.3.4", { 0, 0, 0, 0x01020304, }, CANONICAL }, { "ffff:1::", { 0xffff0001u, 0, 0, 0, }, CANONICAL }, { "ffff:0000::", { 0xffff0000u, 0, 0, 0, }, NORMAL }, { "ffff::1234", { 0xffff0000u, 0, 0, 0x1234, }, CANONICAL }, { "0102::1.2.3.4", {0x01020000u, 0, 0, 0x01020304u }, NORMAL }, { "::9:c0a8:1:1", { 0, 0, 0x0009c0a8u, 0x00010001u }, CANONICAL }, { "::ffff:1.2.3.4", { 0, 0, 0x000ffffu, 0x01020304u }, CANONICAL }, { "FFFF::", { 0xffff0000u, 0, 0, 0 }, NORMAL }, { "foobar.", { 0, 0, 0, 0 }, BAD }, { "foobar", { 0, 0, 0, 0 }, BAD }, { "fo:obar", { 0, 0, 0, 0 }, BAD }, { "ffff", { 0, 0, 0, 0 }, BAD }, { "fffff::", { 0, 0, 0, 0 }, BAD }, { "fffff::", { 0, 0, 0, 0 }, BAD }, { "::1.0.1.1000", { 0, 0, 0, 0 }, BAD }, { "1:2:33333:4::", { 0, 0, 0, 0 }, BAD }, { "1:2:3:4:5:6:7:8:9", { 0, 0, 0, 0 }, BAD }, { "1::2::3", { 0, 0, 0, 0 }, BAD }, { ":::1", { 0, 0, 0, 0 }, BAD }, { NULL, { 0, 0, 0, 0, }, BAD }, }; static void regress_ipv4_parse(void *ptr) { int i; for (i = 0; ipv4_entries[i].addr; ++i) { char written[128]; struct ipv4_entry *ent = &ipv4_entries[i]; struct in_addr in; int r; r = evutil_inet_pton(AF_INET, ent->addr, &in); if (r == 0) { if (ent->status != BAD) { TT_FAIL(("%s did not parse, but it's a good address!", ent->addr)); } continue; } if (ent->status == BAD) { TT_FAIL(("%s parsed, but we expected an error", ent->addr)); continue; } if (ntohl(in.s_addr) != ent->res) { TT_FAIL(("%s parsed to %lx, but we expected %lx", ent->addr, (unsigned long)ntohl(in.s_addr), (unsigned long)ent->res)); continue; } if (ent->status == CANONICAL) { const char *w = evutil_inet_ntop(AF_INET, &in, written, sizeof(written)); if (!w) { TT_FAIL(("Tried to write out %s; got NULL.", ent->addr)); continue; } if (strcmp(written, ent->addr)) { TT_FAIL(("Tried to write out %s; got %s", ent->addr, written)); continue; } } } } static void regress_ipv6_parse(void *ptr) { #ifdef AF_INET6 int i, j; for (i = 0; ipv6_entries[i].addr; ++i) { char written[128]; struct ipv6_entry *ent = &ipv6_entries[i]; struct in6_addr in6; int r; r = evutil_inet_pton(AF_INET6, ent->addr, &in6); if (r == 0) { if (ent->status != BAD) TT_FAIL(("%s did not parse, but it's a good address!", ent->addr)); continue; } if (ent->status == BAD) { TT_FAIL(("%s parsed, but we expected an error", ent->addr)); continue; } for (j = 0; j < 4; ++j) { /* Can't use s6_addr32 here; some don't have it. */ ev_uint32_t u = ((ev_uint32_t)in6.s6_addr[j*4 ] << 24) | ((ev_uint32_t)in6.s6_addr[j*4+1] << 16) | ((ev_uint32_t)in6.s6_addr[j*4+2] << 8) | ((ev_uint32_t)in6.s6_addr[j*4+3]); if (u != ent->res[j]) { TT_FAIL(("%s did not parse as expected.", ent->addr)); continue; } } if (ent->status == CANONICAL) { const char *w = evutil_inet_ntop(AF_INET6, &in6, written, sizeof(written)); if (!w) { TT_FAIL(("Tried to write out %s; got NULL.", ent->addr)); continue; } if (strcmp(written, ent->addr)) { TT_FAIL(("Tried to write out %s; got %s", ent->addr, written)); continue; } } } #else TT_BLATHER(("Skipping IPv6 address parsing.")); #endif } static struct ipv6_entry_scope { const char *addr; ev_uint32_t res[4]; unsigned scope; enum entry_status status; } ipv6_entries_scope[] = { { "2001:DB8::", { 0x20010db8, 0, 0 }, 0, NORMAL }, { "2001:DB8::%0", { 0x20010db8, 0, 0, 0 }, 0, NORMAL }, { "2001:DB8::%1", { 0x20010db8, 0, 0, 0 }, 1, NORMAL }, { "foobar.", { 0, 0, 0, 0 }, 0, BAD }, { "2001:DB8::%does-not-exist", { 0, 0, 0, 0 }, 0, BAD }, { NULL, { 0, 0, 0, 0, }, 0, BAD }, }; static void regress_ipv6_parse_scope(void *ptr) { #ifdef AF_INET6 int i, j; unsigned if_scope; for (i = 0; ipv6_entries_scope[i].addr; ++i) { struct ipv6_entry_scope *ent = &ipv6_entries_scope[i]; struct in6_addr in6; int r; r = evutil_inet_pton_scope(AF_INET6, ent->addr, &in6, &if_scope); if (r == 0) { if (ent->status != BAD) TT_FAIL(("%s did not parse, but it's a good address!", ent->addr)); continue; } if (ent->status == BAD) { TT_FAIL(("%s parsed, but we expected an error", ent->addr)); continue; } for (j = 0; j < 4; ++j) { /* Can't use s6_addr32 here; some don't have it. */ ev_uint32_t u = ((ev_uint32_t)in6.s6_addr[j*4 ] << 24) | ((ev_uint32_t)in6.s6_addr[j*4+1] << 16) | ((ev_uint32_t)in6.s6_addr[j*4+2] << 8) | ((ev_uint32_t)in6.s6_addr[j*4+3]); if (u != ent->res[j]) { TT_FAIL(("%s did not parse as expected.", ent->addr)); continue; } } if (if_scope != ent->scope) { TT_FAIL(("%s did not parse as expected.", ent->addr)); continue; } } #else TT_BLATHER(("Skipping IPv6 address parsing.")); #endif } static struct sa_port_ent { const char *parse; int safamily; const char *addr; int port; } sa_port_ents[] = { { "[ffff::1]:1000", AF_INET6, "ffff::1", 1000 }, { "[ffff::1]", AF_INET6, "ffff::1", 0 }, { "[ffff::1", 0, NULL, 0 }, { "[ffff::1]:65599", 0, NULL, 0 }, { "[ffff::1]:0", 0, NULL, 0 }, { "[ffff::1]:-1", 0, NULL, 0 }, { "::1", AF_INET6, "::1", 0 }, { "1:2::1", AF_INET6, "1:2::1", 0 }, { "192.168.0.1:50", AF_INET, "192.168.0.1", 50 }, { "1.2.3.4", AF_INET, "1.2.3.4", 0 }, { NULL, 0, NULL, 0 }, }; static void regress_sockaddr_port_parse(void *ptr) { struct sockaddr_storage ss; int i, r; for (i = 0; sa_port_ents[i].parse; ++i) { struct sa_port_ent *ent = &sa_port_ents[i]; int len = sizeof(ss); memset(&ss, 0, sizeof(ss)); r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len); if (r < 0) { if (ent->safamily) TT_FAIL(("Couldn't parse %s!", ent->parse)); continue; } else if (! ent->safamily) { TT_FAIL(("Shouldn't have been able to parse %s!", ent->parse)); continue; } if (ent->safamily == AF_INET) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); #ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.sin_len = sizeof(sin); #endif sin.sin_family = AF_INET; sin.sin_port = htons(ent->port); r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr); if (1 != r) { TT_FAIL(("Couldn't parse ipv4 target %s.", ent->addr)); } else if (memcmp(&sin, &ss, sizeof(sin))) { TT_FAIL(("Parse for %s was not as expected.", ent->parse)); } else if (len != sizeof(sin)) { TT_FAIL(("Length for %s not as expected.",ent->parse)); } } else { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); #ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6.sin6_len = sizeof(sin6); #endif sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(ent->port); r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr); if (1 != r) { TT_FAIL(("Couldn't parse ipv6 target %s.", ent->addr)); } else if (memcmp(&sin6, &ss, sizeof(sin6))) { TT_FAIL(("Parse for %s was not as expected.", ent->parse)); } else if (len != sizeof(sin6)) { TT_FAIL(("Length for %s not as expected.",ent->parse)); } } } } static void regress_sockaddr_port_format(void *ptr) { struct sockaddr_storage ss; int len; const char *cp; char cbuf[128]; int r; len = sizeof(ss); r = evutil_parse_sockaddr_port("192.168.1.1:80", (struct sockaddr*)&ss, &len); tt_int_op(r,==,0); cp = evutil_format_sockaddr_port_( (struct sockaddr*)&ss, cbuf, sizeof(cbuf)); tt_ptr_op(cp,==,cbuf); tt_str_op(cp,==,"192.168.1.1:80"); len = sizeof(ss); r = evutil_parse_sockaddr_port("[ff00::8010]:999", (struct sockaddr*)&ss, &len); tt_int_op(r,==,0); cp = evutil_format_sockaddr_port_( (struct sockaddr*)&ss, cbuf, sizeof(cbuf)); tt_ptr_op(cp,==,cbuf); tt_str_op(cp,==,"[ff00::8010]:999"); ss.ss_family=99; cp = evutil_format_sockaddr_port_( (struct sockaddr*)&ss, cbuf, sizeof(cbuf)); tt_ptr_op(cp,==,cbuf); tt_str_op(cp,==,""); end: ; } static struct sa_pred_ent { const char *parse; int is_loopback; } sa_pred_entries[] = { { "127.0.0.1", 1 }, { "127.0.3.2", 1 }, { "128.1.2.3", 0 }, { "18.0.0.1", 0 }, { "129.168.1.1", 0 }, { "::1", 1 }, { "::0", 0 }, { "f::1", 0 }, { "::501", 0 }, { NULL, 0 }, }; static void test_evutil_sockaddr_predicates(void *ptr) { struct sockaddr_storage ss; int r, i; for (i=0; sa_pred_entries[i].parse; ++i) { struct sa_pred_ent *ent = &sa_pred_entries[i]; int len = sizeof(ss); r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, &len); if (r<0) { TT_FAIL(("Couldn't parse %s!", ent->parse)); continue; } /* sockaddr_is_loopback */ if (ent->is_loopback != evutil_sockaddr_is_loopback_((struct sockaddr*)&ss)) { TT_FAIL(("evutil_sockaddr_loopback(%s) not as expected", ent->parse)); } } } static void test_evutil_strtoll(void *ptr) { const char *s; char *endptr; tt_want(evutil_strtoll("5000000000", NULL, 10) == ((ev_int64_t)5000000)*1000); tt_want(evutil_strtoll("-5000000000", NULL, 10) == ((ev_int64_t)5000000)*-1000); s = " 99999stuff"; tt_want(evutil_strtoll(s, &endptr, 10) == (ev_int64_t)99999); tt_want(endptr == s+6); tt_want(evutil_strtoll("foo", NULL, 10) == 0); } static void test_evutil_snprintf(void *ptr) { char buf[16]; int r; ev_uint64_t u64 = ((ev_uint64_t)1000000000)*200; ev_int64_t i64 = -1 * (ev_int64_t) u64; size_t size = 8000; ev_ssize_t ssize = -9000; r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100); tt_str_op(buf, ==, "50 100"); tt_int_op(r, ==, 6); r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890); tt_str_op(buf, ==, "longish 1234567"); tt_int_op(r, ==, 18); r = evutil_snprintf(buf, sizeof(buf), EV_U64_FMT, EV_U64_ARG(u64)); tt_str_op(buf, ==, "200000000000"); tt_int_op(r, ==, 12); r = evutil_snprintf(buf, sizeof(buf), EV_I64_FMT, EV_I64_ARG(i64)); tt_str_op(buf, ==, "-200000000000"); tt_int_op(r, ==, 13); r = evutil_snprintf(buf, sizeof(buf), EV_SIZE_FMT" "EV_SSIZE_FMT, EV_SIZE_ARG(size), EV_SSIZE_ARG(ssize)); tt_str_op(buf, ==, "8000 -9000"); tt_int_op(r, ==, 10); end: ; } static void test_evutil_casecmp(void *ptr) { tt_int_op(evutil_ascii_strcasecmp("ABC", "ABC"), ==, 0); tt_int_op(evutil_ascii_strcasecmp("ABC", "abc"), ==, 0); tt_int_op(evutil_ascii_strcasecmp("ABC", "abcd"), <, 0); tt_int_op(evutil_ascii_strcasecmp("ABC", "abb"), >, 0); tt_int_op(evutil_ascii_strcasecmp("ABCd", "abc"), >, 0); tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 100), ==, 0); tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEvEnT", 4), ==, 0); tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibEXXXX", 4), ==, 0); tt_int_op(evutil_ascii_strncasecmp("Libevent", "LibE", 4), ==, 0); tt_int_op(evutil_ascii_strncasecmp("Libe", "LibEvEnT", 4), ==, 0); tt_int_op(evutil_ascii_strncasecmp("Lib", "LibEvEnT", 4), <, 0); tt_int_op(evutil_ascii_strncasecmp("abc", "def", 99), <, 0); tt_int_op(evutil_ascii_strncasecmp("Z", "qrst", 1), >, 0); end: ; } static void test_evutil_rtrim(void *ptr) { #define TEST_TRIM(s, result) \ do { \ if (cp) mm_free(cp); \ cp = mm_strdup(s); \ tt_assert(cp); \ evutil_rtrim_lws_(cp); \ tt_str_op(cp, ==, result); \ } while(0) char *cp = NULL; (void) ptr; TEST_TRIM("", ""); TEST_TRIM("a", "a"); TEST_TRIM("abcdef ghi", "abcdef ghi"); TEST_TRIM(" ", ""); TEST_TRIM(" ", ""); TEST_TRIM("a ", "a"); TEST_TRIM("abcdef gH ", "abcdef gH"); TEST_TRIM("\t\t", ""); TEST_TRIM(" \t", ""); TEST_TRIM("\t", ""); TEST_TRIM("a \t", "a"); TEST_TRIM("a\t ", "a"); TEST_TRIM("a\t", "a"); TEST_TRIM("abcdef gH \t ", "abcdef gH"); end: if (cp) mm_free(cp); } static int logsev = 0; static char *logmsg = NULL; static void logfn(int severity, const char *msg) { logsev = severity; tt_want(msg); if (msg) { if (logmsg) free(logmsg); logmsg = strdup(msg); } } static int fatal_want_severity = 0; static const char *fatal_want_message = NULL; static void fatalfn(int exitcode) { if (logsev != fatal_want_severity || !logmsg || strcmp(logmsg, fatal_want_message)) exit(0); else exit(exitcode); } #ifndef _WIN32 #define CAN_CHECK_ERR static void check_error_logging(void (*fn)(void), int wantexitcode, int wantseverity, const char *wantmsg) { pid_t pid; int status = 0, exitcode; fatal_want_severity = wantseverity; fatal_want_message = wantmsg; if ((pid = regress_fork()) == 0) { /* child process */ fn(); exit(0); /* should be unreachable. */ } else { wait(&status); exitcode = WEXITSTATUS(status); tt_int_op(wantexitcode, ==, exitcode); } end: ; } static void errx_fn(void) { event_errx(2, "Fatal error; too many kumquats (%d)", 5); } static void err_fn(void) { errno = ENOENT; event_err(5,"Couldn't open %s", "/very/bad/file"); } static void sock_err_fn(void) { evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0); #ifdef _WIN32 EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK); #else errno = EAGAIN; #endif event_sock_err(20, fd, "Unhappy socket"); } #endif static void test_evutil_log(void *ptr) { evutil_socket_t fd = -1; char buf[128]; event_set_log_callback(logfn); event_set_fatal_callback(fatalfn); #define RESET() do { \ logsev = 0; \ if (logmsg) free(logmsg); \ logmsg = NULL; \ } while (0) #define LOGEQ(sev,msg) do { \ tt_int_op(logsev,==,sev); \ tt_assert(logmsg != NULL); \ tt_str_op(logmsg,==,msg); \ } while (0) #ifdef CAN_CHECK_ERR /* We need to disable these tests for now. Previously, the logging * module didn't enforce the requirement that a fatal callback * actually exit. Now, it exits no matter what, so if we wan to * reinstate these tests, we'll need to fork for each one. */ check_error_logging(errx_fn, 2, EVENT_LOG_ERR, "Fatal error; too many kumquats (5)"); RESET(); #endif event_warnx("Far too many %s (%d)", "wombats", 99); LOGEQ(EVENT_LOG_WARN, "Far too many wombats (99)"); RESET(); event_msgx("Connecting lime to coconut"); LOGEQ(EVENT_LOG_MSG, "Connecting lime to coconut"); RESET(); event_debug(("A millisecond passed! We should log that!")); #ifdef USE_DEBUG LOGEQ(EVENT_LOG_DEBUG, "A millisecond passed! We should log that!"); #else tt_int_op(logsev,==,0); tt_ptr_op(logmsg,==,NULL); #endif RESET(); /* Try with an errno. */ errno = ENOENT; event_warn("Couldn't open %s", "/bad/file"); evutil_snprintf(buf, sizeof(buf), "Couldn't open /bad/file: %s",strerror(ENOENT)); LOGEQ(EVENT_LOG_WARN,buf); RESET(); #ifdef CAN_CHECK_ERR evutil_snprintf(buf, sizeof(buf), "Couldn't open /very/bad/file: %s",strerror(ENOENT)); check_error_logging(err_fn, 5, EVENT_LOG_ERR, buf); RESET(); #endif /* Try with a socket errno. */ fd = socket(AF_INET, SOCK_STREAM, 0); #ifdef _WIN32 evutil_snprintf(buf, sizeof(buf), "Unhappy socket: %s", evutil_socket_error_to_string(WSAEWOULDBLOCK)); EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK); #else evutil_snprintf(buf, sizeof(buf), "Unhappy socket: %s", strerror(EAGAIN)); errno = EAGAIN; #endif event_sock_warn(fd, "Unhappy socket"); LOGEQ(EVENT_LOG_WARN, buf); RESET(); #ifdef CAN_CHECK_ERR check_error_logging(sock_err_fn, 20, EVENT_LOG_ERR, buf); RESET(); #endif #undef RESET #undef LOGEQ end: if (logmsg) free(logmsg); if (fd >= 0) evutil_closesocket(fd); } static void test_evutil_strlcpy(void *arg) { char buf[8]; /* Successful case. */ tt_int_op(5, ==, strlcpy(buf, "Hello", sizeof(buf))); tt_str_op(buf, ==, "Hello"); /* Overflow by a lot. */ tt_int_op(13, ==, strlcpy(buf, "pentasyllabic", sizeof(buf))); tt_str_op(buf, ==, "pentasy"); /* Overflow by exactly one. */ tt_int_op(8, ==, strlcpy(buf, "overlong", sizeof(buf))); tt_str_op(buf, ==, "overlon"); end: ; } struct example_struct { const char *a; const char *b; long c; }; static void test_evutil_upcast(void *arg) { struct example_struct es1; const char **cp; es1.a = "World"; es1.b = "Hello"; es1.c = -99; tt_int_op(evutil_offsetof(struct example_struct, b), ==, sizeof(char*)); cp = &es1.b; tt_ptr_op(EVUTIL_UPCAST(cp, struct example_struct, b), ==, &es1); end: ; } static void test_evutil_integers(void *arg) { ev_int64_t i64; ev_uint64_t u64; ev_int32_t i32; ev_uint32_t u32; ev_int16_t i16; ev_uint16_t u16; ev_int8_t i8; ev_uint8_t u8; void *ptr; ev_intptr_t iptr; ev_uintptr_t uptr; ev_ssize_t ssize; tt_int_op(sizeof(u64), ==, 8); tt_int_op(sizeof(i64), ==, 8); tt_int_op(sizeof(u32), ==, 4); tt_int_op(sizeof(i32), ==, 4); tt_int_op(sizeof(u16), ==, 2); tt_int_op(sizeof(i16), ==, 2); tt_int_op(sizeof(u8), ==, 1); tt_int_op(sizeof(i8), ==, 1); tt_int_op(sizeof(ev_ssize_t), ==, sizeof(size_t)); tt_int_op(sizeof(ev_intptr_t), >=, sizeof(void *)); tt_int_op(sizeof(ev_uintptr_t), ==, sizeof(intptr_t)); u64 = 1000000000; u64 *= 1000000000; tt_assert(u64 / 1000000000 == 1000000000); i64 = -1000000000; i64 *= 1000000000; tt_assert(i64 / 1000000000 == -1000000000); u64 = EV_UINT64_MAX; i64 = EV_INT64_MAX; tt_assert(u64 > 0); tt_assert(i64 > 0); u64++; /* i64++; */ tt_assert(u64 == 0); /* tt_assert(i64 == EV_INT64_MIN); */ /* tt_assert(i64 < 0); */ u32 = EV_UINT32_MAX; i32 = EV_INT32_MAX; tt_assert(u32 > 0); tt_assert(i32 > 0); u32++; /* i32++; */ tt_assert(u32 == 0); /* tt_assert(i32 == EV_INT32_MIN); */ /* tt_assert(i32 < 0); */ u16 = EV_UINT16_MAX; i16 = EV_INT16_MAX; tt_assert(u16 > 0); tt_assert(i16 > 0); u16++; /* i16++; */ tt_assert(u16 == 0); /* tt_assert(i16 == EV_INT16_MIN); */ /* tt_assert(i16 < 0); */ u8 = EV_UINT8_MAX; i8 = EV_INT8_MAX; tt_assert(u8 > 0); tt_assert(i8 > 0); u8++; /* i8++;*/ tt_assert(u8 == 0); /* tt_assert(i8 == EV_INT8_MIN); */ /* tt_assert(i8 < 0); */ /* ssize = EV_SSIZE_MAX; tt_assert(ssize > 0); ssize++; tt_assert(ssize < 0); tt_assert(ssize == EV_SSIZE_MIN); */ ptr = &ssize; iptr = (ev_intptr_t)ptr; uptr = (ev_uintptr_t)ptr; ptr = (void *)iptr; tt_assert(ptr == &ssize); ptr = (void *)uptr; tt_assert(ptr == &ssize); iptr = -1; tt_assert(iptr < 0); end: ; } struct evutil_addrinfo * ai_find_by_family(struct evutil_addrinfo *ai, int family) { while (ai) { if (ai->ai_family == family) return ai; ai = ai->ai_next; } return NULL; } struct evutil_addrinfo * ai_find_by_protocol(struct evutil_addrinfo *ai, int protocol) { while (ai) { if (ai->ai_protocol == protocol) return ai; ai = ai->ai_next; } return NULL; } int test_ai_eq_(const struct evutil_addrinfo *ai, const char *sockaddr_port, int socktype, int protocol, int line) { struct sockaddr_storage ss; int slen = sizeof(ss); int gotport; char buf[128]; memset(&ss, 0, sizeof(ss)); if (socktype > 0) tt_int_op(ai->ai_socktype, ==, socktype); if (protocol > 0) tt_int_op(ai->ai_protocol, ==, protocol); if (evutil_parse_sockaddr_port( sockaddr_port, (struct sockaddr*)&ss, &slen)<0) { TT_FAIL(("Couldn't parse expected address %s on line %d", sockaddr_port, line)); return -1; } if (ai->ai_family != ss.ss_family) { TT_FAIL(("Address family %d did not match %d on line %d", ai->ai_family, ss.ss_family, line)); return -1; } if (ai->ai_addr->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in*)ai->ai_addr; evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); gotport = ntohs(sin->sin_port); if (ai->ai_addrlen != sizeof(struct sockaddr_in)) { TT_FAIL(("Addr size mismatch on line %d", line)); return -1; } } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr; evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf)); gotport = ntohs(sin6->sin6_port); if (ai->ai_addrlen != sizeof(struct sockaddr_in6)) { TT_FAIL(("Addr size mismatch on line %d", line)); return -1; } } if (evutil_sockaddr_cmp(ai->ai_addr, (struct sockaddr*)&ss, 1)) { TT_FAIL(("Wanted %s, got %s:%d on line %d", sockaddr_port, buf, gotport, line)); return -1; } else { TT_BLATHER(("Wanted %s, got %s:%d on line %d", sockaddr_port, buf, gotport, line)); } return 0; end: TT_FAIL(("Test failed on line %d", line)); return -1; } static void test_evutil_rand(void *arg) { char buf1[32]; char buf2[32]; int counts[256]; int i, j, k, n=0; struct evutil_weakrand_state seed = { 12346789U }; memset(buf2, 0, sizeof(buf2)); memset(counts, 0, sizeof(counts)); for (k=0;k<32;++k) { /* Try a few different start and end points; try to catch * the various misaligned cases of arc4random_buf */ int startpoint = evutil_weakrand_(&seed) % 4; int endpoint = 32 - (evutil_weakrand_(&seed) % 4); memset(buf2, 0, sizeof(buf2)); /* Do 6 runs over buf1, or-ing the result into buf2 each * time, to make sure we're setting each byte that we mean * to set. */ for (i=0;i<8;++i) { memset(buf1, 0, sizeof(buf1)); evutil_secure_rng_get_bytes(buf1 + startpoint, endpoint-startpoint); n += endpoint - startpoint; for (j=0; j<32; ++j) { if (j >= startpoint && j < endpoint) { buf2[j] |= buf1[j]; ++counts[(unsigned char)buf1[j]]; } else { tt_assert(buf1[j] == 0); tt_int_op(buf1[j], ==, 0); } } } /* This will give a false positive with P=(256**8)==(2**64) * for each character. */ for (j=startpoint;jai_next, ==, NULL); /* no ambiguity */ test_ai_eq(ai, "1.2.3.4:8080", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_protocol = IPPROTO_UDP; r = evutil_getaddrinfo("1001:b0b::f00f", "4321", &hints, &ai); tt_int_op(r, ==, 0); tt_assert(ai); tt_ptr_op(ai->ai_next, ==, NULL); /* no ambiguity */ test_ai_eq(ai, "[1001:b0b::f00f]:4321", SOCK_DGRAM, IPPROTO_UDP); evutil_freeaddrinfo(ai); ai = NULL; /* Try out the behavior of nodename=NULL */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind */ r = evutil_getaddrinfo(NULL, "9999", &hints, &ai); tt_int_op(r,==,0); tt_assert(ai); tt_ptr_op(ai->ai_next, ==, NULL); test_ai_eq(ai, "0.0.0.0:9999", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; hints.ai_flags = 0; /* as if for connect */ r = evutil_getaddrinfo(NULL, "9998", &hints, &ai); tt_assert(ai); tt_int_op(r,==,0); test_ai_eq(ai, "127.0.0.1:9998", SOCK_STREAM, IPPROTO_TCP); tt_ptr_op(ai->ai_next, ==, NULL); evutil_freeaddrinfo(ai); ai = NULL; hints.ai_flags = 0; /* as if for connect */ hints.ai_family = PF_INET6; r = evutil_getaddrinfo(NULL, "9997", &hints, &ai); tt_assert(ai); tt_int_op(r,==,0); tt_ptr_op(ai->ai_next, ==, NULL); test_ai_eq(ai, "[::1]:9997", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; hints.ai_flags = EVUTIL_AI_PASSIVE; /* as if for bind. */ hints.ai_family = PF_INET6; r = evutil_getaddrinfo(NULL, "9996", &hints, &ai); tt_assert(ai); tt_int_op(r,==,0); tt_ptr_op(ai->ai_next, ==, NULL); test_ai_eq(ai, "[::]:9996", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; /* Now try an unspec one. We should get a v6 and a v4. */ hints.ai_family = PF_UNSPEC; r = evutil_getaddrinfo(NULL, "9996", &hints, &ai); tt_assert(ai); tt_int_op(r,==,0); a = ai_find_by_family(ai, PF_INET6); tt_assert(a); test_ai_eq(a, "[::]:9996", SOCK_STREAM, IPPROTO_TCP); a = ai_find_by_family(ai, PF_INET); tt_assert(a); test_ai_eq(a, "0.0.0.0:9996", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; /* Try out AI_NUMERICHOST: successful case. Also try * multiprotocol. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = EVUTIL_AI_NUMERICHOST; r = evutil_getaddrinfo("1.2.3.4", NULL, &hints, &ai); tt_int_op(r, ==, 0); a = ai_find_by_protocol(ai, IPPROTO_TCP); tt_assert(a); test_ai_eq(a, "1.2.3.4", SOCK_STREAM, IPPROTO_TCP); a = ai_find_by_protocol(ai, IPPROTO_UDP); tt_assert(a); test_ai_eq(a, "1.2.3.4", SOCK_DGRAM, IPPROTO_UDP); evutil_freeaddrinfo(ai); ai = NULL; /* Try the failing case of AI_NUMERICHOST */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = EVUTIL_AI_NUMERICHOST; r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai); tt_int_op(r, ==, EVUTIL_EAI_NONAME); tt_ptr_op(ai, ==, NULL); /* Try symbolic service names wit AI_NUMERICSERV */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = EVUTIL_AI_NUMERICSERV; r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai); tt_int_op(r,==,EVUTIL_EAI_NONAME); /* Try symbolic service names */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; r = evutil_getaddrinfo("1.2.3.4", "http", &hints, &ai); if (r!=0) { TT_DECLARE("SKIP", ("Symbolic service names seem broken.")); } else { tt_assert(ai); test_ai_eq(ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; } end: if (ai) evutil_freeaddrinfo(ai); } static void test_evutil_getaddrinfo_live(void *arg) { struct evutil_addrinfo *ai = NULL; struct evutil_addrinfo hints; struct sockaddr_in6 *sin6; struct sockaddr_in *sin; char buf[128]; const char *cp; int r; /* Now do some actual lookups. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; r = evutil_getaddrinfo("www.google.com", "80", &hints, &ai); if (r != 0) { TT_DECLARE("SKIP", ("Couldn't resolve www.google.com")); } else { tt_assert(ai); tt_int_op(ai->ai_family, ==, PF_INET); tt_int_op(ai->ai_protocol, ==, IPPROTO_TCP); tt_int_op(ai->ai_socktype, ==, SOCK_STREAM); tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in)); sin = (struct sockaddr_in*)ai->ai_addr; tt_int_op(sin->sin_family, ==, AF_INET); tt_int_op(sin->sin_port, ==, htons(80)); tt_int_op(sin->sin_addr.s_addr, !=, 0xffffffff); cp = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); TT_BLATHER(("www.google.com resolved to %s", cp?cp:"")); evutil_freeaddrinfo(ai); ai = NULL; } hints.ai_family = PF_INET6; r = evutil_getaddrinfo("ipv6.google.com", "80", &hints, &ai); if (r != 0) { TT_BLATHER(("Couldn't do an ipv6 lookup for ipv6.google.com")); } else { tt_assert(ai); tt_int_op(ai->ai_family, ==, PF_INET6); tt_int_op(ai->ai_addrlen, ==, sizeof(struct sockaddr_in6)); sin6 = (struct sockaddr_in6*)ai->ai_addr; tt_int_op(sin6->sin6_port, ==, htons(80)); cp = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf)); TT_BLATHER(("ipv6.google.com resolved to %s", cp?cp:"")); } end: if (ai) evutil_freeaddrinfo(ai); } static void test_evutil_getaddrinfo_AI_ADDRCONFIG(void *arg) { struct evutil_addrinfo *ai = NULL; struct evutil_addrinfo hints; int r; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; /* IPv4 */ r = evutil_getaddrinfo("127.0.0.1", "80", &hints, &ai); tt_int_op(r, ==, 0); tt_assert(ai); tt_ptr_op(ai->ai_next, ==, NULL); test_ai_eq(ai, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; /* IPv6 */ r = evutil_getaddrinfo("::1", "80", &hints, &ai); tt_int_op(r, ==, 0); tt_assert(ai); tt_ptr_op(ai->ai_next, ==, NULL); test_ai_eq(ai, "[::1]:80", SOCK_STREAM, IPPROTO_TCP); evutil_freeaddrinfo(ai); ai = NULL; end: if (ai) evutil_freeaddrinfo(ai); } #ifdef _WIN32 static void test_evutil_loadsyslib(void *arg) { HMODULE h=NULL; h = evutil_load_windows_system_library_(TEXT("kernel32.dll")); tt_assert(h); end: if (h) CloseHandle(h); } #endif /** Test mm_malloc(). */ static void test_event_malloc(void *arg) { void *p = NULL; (void)arg; /* mm_malloc(0) should simply return NULL. */ #ifndef EVENT__DISABLE_MM_REPLACEMENT errno = 0; p = mm_malloc(0); tt_assert(p == NULL); tt_int_op(errno, ==, 0); #endif /* Trivial case. */ errno = 0; p = mm_malloc(8); tt_assert(p != NULL); tt_int_op(errno, ==, 0); mm_free(p); end: errno = 0; return; } static void test_event_calloc(void *arg) { void *p = NULL; (void)arg; #ifndef EVENT__DISABLE_MM_REPLACEMENT /* mm_calloc() should simply return NULL * if either argument is zero. */ errno = 0; p = mm_calloc(0, 0); tt_assert(p == NULL); tt_int_op(errno, ==, 0); errno = 0; p = mm_calloc(0, 1); tt_assert(p == NULL); tt_int_op(errno, ==, 0); errno = 0; p = mm_calloc(1, 0); tt_assert(p == NULL); tt_int_op(errno, ==, 0); #endif /* Trivial case. */ errno = 0; p = mm_calloc(8, 8); tt_assert(p != NULL); tt_int_op(errno, ==, 0); mm_free(p); p = NULL; /* mm_calloc() should set errno = ENOMEM and return NULL * in case of potential overflow. */ errno = 0; p = mm_calloc(EV_SIZE_MAX/2, EV_SIZE_MAX/2 + 8); tt_assert(p == NULL); tt_int_op(errno, ==, ENOMEM); end: errno = 0; if (p) mm_free(p); return; } static void test_event_strdup(void *arg) { void *p = NULL; (void)arg; #ifndef EVENT__DISABLE_MM_REPLACEMENT /* mm_strdup(NULL) should set errno = EINVAL and return NULL. */ errno = 0; p = mm_strdup(NULL); tt_assert(p == NULL); tt_int_op(errno, ==, EINVAL); #endif /* Trivial cases. */ errno = 0; p = mm_strdup(""); tt_assert(p != NULL); tt_int_op(errno, ==, 0); tt_str_op(p, ==, ""); mm_free(p); errno = 0; p = mm_strdup("foo"); tt_assert(p != NULL); tt_int_op(errno, ==, 0); tt_str_op(p, ==, "foo"); mm_free(p); /* XXX * mm_strdup(str) where str is a string of length EV_SIZE_MAX * should set errno = ENOMEM and return NULL. */ end: errno = 0; return; } static void test_evutil_usleep(void *arg) { struct timeval tv1, tv2, tv3, diff1, diff2; const struct timeval quarter_sec = {0, 250*1000}; const struct timeval tenth_sec = {0, 100*1000}; long usec1, usec2; evutil_gettimeofday(&tv1, NULL); evutil_usleep_(&quarter_sec); evutil_gettimeofday(&tv2, NULL); evutil_usleep_(&tenth_sec); evutil_gettimeofday(&tv3, NULL); evutil_timersub(&tv2, &tv1, &diff1); evutil_timersub(&tv3, &tv2, &diff2); usec1 = diff1.tv_sec * 1000000 + diff1.tv_usec; usec2 = diff2.tv_sec * 1000000 + diff2.tv_usec; tt_int_op(usec1, >, 200000); tt_int_op(usec1, <, 300000); tt_int_op(usec2, >, 80000); tt_int_op(usec2, <, 120000); end: ; } static void test_evutil_monotonic_res(void *data_) { /* Basic santity-test for monotonic timers. What we'd really like * to do is make sure that they can't go backwards even when the * system clock goes backwards. But we haven't got a good way to * move the system clock backwards. */ struct basic_test_data *data = data_; struct evutil_monotonic_timer timer; const int precise = strstr(data->setup_data, "precise") != NULL; const int fallback = strstr(data->setup_data, "fallback") != NULL; struct timeval tv[10], delay; int total_diff = 0; int flags = 0, wantres, acceptdiff, i; if (precise) flags |= EV_MONOT_PRECISE; if (fallback) flags |= EV_MONOT_FALLBACK; if (precise || fallback) { #ifdef _WIN32 wantres = 10*1000; acceptdiff = 1000; #else wantres = 1000; acceptdiff = 300; #endif } else { wantres = 40*1000; acceptdiff = 20*1000; } TT_BLATHER(("Precise = %d", precise)); TT_BLATHER(("Fallback = %d", fallback)); /* First, make sure we match up with usleep. */ delay.tv_sec = 0; delay.tv_usec = wantres; tt_int_op(evutil_configure_monotonic_time_(&timer, flags), ==, 0); for (i = 0; i < 10; ++i) { evutil_gettime_monotonic_(&timer, &tv[i]); evutil_usleep_(&delay); } for (i = 0; i < 9; ++i) { struct timeval diff; tt_assert(evutil_timercmp(&tv[i], &tv[i+1], <)); evutil_timersub(&tv[i+1], &tv[i], &diff); tt_int_op(diff.tv_sec, ==, 0); total_diff += diff.tv_usec; TT_BLATHER(("Difference = %d", (int)diff.tv_usec)); } tt_int_op(abs(total_diff/9 - wantres), <, acceptdiff); end: ; } static void test_evutil_monotonic_prc(void *data_) { struct basic_test_data *data = data_; struct evutil_monotonic_timer timer; const int precise = strstr(data->setup_data, "precise") != NULL; const int fallback = strstr(data->setup_data, "fallback") != NULL; struct timeval tv[10]; int total_diff = 0; int i, maxstep = 25*1000,flags=0; if (precise) maxstep = 500; if (precise) flags |= EV_MONOT_PRECISE; if (fallback) flags |= EV_MONOT_FALLBACK; tt_int_op(evutil_configure_monotonic_time_(&timer, flags), ==, 0); /* find out what precision we actually see. */ evutil_gettime_monotonic_(&timer, &tv[0]); for (i = 1; i < 10; ++i) { do { evutil_gettime_monotonic_(&timer, &tv[i]); } while (evutil_timercmp(&tv[i-1], &tv[i], ==)); } total_diff = 0; for (i = 0; i < 9; ++i) { struct timeval diff; tt_assert(evutil_timercmp(&tv[i], &tv[i+1], <)); evutil_timersub(&tv[i+1], &tv[i], &diff); tt_int_op(diff.tv_sec, ==, 0); total_diff += diff.tv_usec; TT_BLATHER(("Step difference = %d", (int)diff.tv_usec)); } TT_BLATHER(("Average step difference = %d", total_diff / 9)); tt_int_op(total_diff/9, <, maxstep); end: ; } static void create_tm_from_unix_epoch(struct tm *cur_p, const time_t t) { #ifdef _WIN32 struct tm *tmp = gmtime(&t); if (!tmp) { fprintf(stderr, "gmtime: %s (%i)", strerror(errno), (int)t); exit(1); } *cur_p = *tmp; #else gmtime_r(&t, cur_p); #endif } static struct date_rfc1123_case { time_t t; char date[30]; } date_rfc1123_cases[] = { { 0, "Thu, 01 Jan 1970 00:00:00 GMT"} /* UNIX time of zero */, { 946684799, "Fri, 31 Dec 1999 23:59:59 GMT"} /* the last moment of the 20th century */, { 946684800, "Sat, 01 Jan 2000 00:00:00 GMT"} /* the first moment of the 21st century */, { 981072000, "Fri, 02 Feb 2001 00:00:00 GMT"}, { 1015113600, "Sun, 03 Mar 2002 00:00:00 GMT"}, { 1049414400, "Fri, 04 Apr 2003 00:00:00 GMT"}, { 1083715200, "Wed, 05 May 2004 00:00:00 GMT"}, { 1118016000, "Mon, 06 Jun 2005 00:00:00 GMT"}, { 1152230400, "Fri, 07 Jul 2006 00:00:00 GMT"}, { 1186531200, "Wed, 08 Aug 2007 00:00:00 GMT"}, { 1220918400, "Tue, 09 Sep 2008 00:00:00 GMT"}, { 1255132800, "Sat, 10 Oct 2009 00:00:00 GMT"}, { 1289433600, "Thu, 11 Nov 2010 00:00:00 GMT"}, { 1323648000, "Mon, 12 Dec 2011 00:00:00 GMT"}, #ifndef _WIN32 #if EVENT__SIZEOF_TIME_T > 4 /** In win32 case we have max "23:59:59 January 18, 2038, UTC" for time32 */ { 4294967296, "Sun, 07 Feb 2106 06:28:16 GMT"} /* 2^32 */, /** In win32 case we have max "23:59:59, December 31, 3000, UTC" for time64 */ {253402300799, "Fri, 31 Dec 9999 23:59:59 GMT"} /* long long future no one can imagine */, #endif /* time_t != 32bit */ { 1456704000, "Mon, 29 Feb 2016 00:00:00 GMT"} /* leap year */, #endif { 1435708800, "Wed, 01 Jul 2015 00:00:00 GMT"} /* leap second */, { 1481866376, "Fri, 16 Dec 2016 05:32:56 GMT"} /* the time this test case is generated */, {0, ""} /* end of test cases. */ }; static void test_evutil_date_rfc1123(void *arg) { struct tm query; char result[30]; size_t i = 0; /* Checks if too small buffers are safely accepted. */ { create_tm_from_unix_epoch(&query, 0); evutil_date_rfc1123(result, 8, &query); tt_str_op(result, ==, "Thu, 01"); } /* Checks for testcases. */ for (i = 0; ; i++) { struct date_rfc1123_case c = date_rfc1123_cases[i]; if (strlen(c.date) == 0) break; create_tm_from_unix_epoch(&query, c.t); evutil_date_rfc1123(result, sizeof(result), &query); tt_str_op(result, ==, c.date); } end: ; } static void test_evutil_v4addr_is_local(void *arg) { struct sockaddr_in sin; sin.sin_family = AF_INET; /* we use evutil_inet_pton() here to fill in network-byte order */ #define LOCAL(str, yes) do { \ tt_int_op(evutil_inet_pton(AF_INET, str, &sin.sin_addr), ==, 1); \ tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, yes); \ } while (0) /** any */ sin.sin_addr.s_addr = INADDR_ANY; tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1); /** loopback */ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1); LOCAL("127.0.0.1", 1); LOCAL("127.255.255.255", 1); LOCAL("121.0.0.1", 0); /** link-local */ LOCAL("169.254.0.1", 1); LOCAL("169.254.255.255", 1); LOCAL("170.0.0.0", 0); /** Multicast */ LOCAL("224.0.0.0", 1); LOCAL("239.255.255.255", 1); LOCAL("240.0.0.0", 0); end: ; } static void test_evutil_v6addr_is_local(void *arg) { struct sockaddr_in6 sin6; struct in6_addr anyaddr = IN6ADDR_ANY_INIT; struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT; sin6.sin6_family = AF_INET6; #define LOCAL6(str, yes) do { \ tt_int_op(evutil_inet_pton(AF_INET6, str, &sin6.sin6_addr), ==, 1);\ tt_int_op(evutil_v6addr_is_local_(&sin6.sin6_addr), ==, yes); \ } while (0) /** any */ tt_int_op(evutil_v6addr_is_local_(&anyaddr), ==, 1); LOCAL6("::0", 1); /** loopback */ tt_int_op(evutil_v6addr_is_local_(&loopback), ==, 1); LOCAL6("::1", 1); /** IPV4 mapped */ LOCAL6("::ffff:0:0", 1); /** IPv4 translated */ LOCAL6("::ffff:0:0:0", 1); /** IPv4/IPv6 translation */ LOCAL6("64:ff9b::", 0); /** Link-local */ LOCAL6("fe80::", 1); /** Multicast */ LOCAL6("ff00::", 1); /** Unspecified */ LOCAL6("::", 1); /** Global Internet */ LOCAL6("2001::", 0); LOCAL6("2001:4860:4802:32::1b", 0); end: ; } struct testcase_t util_testcases[] = { { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL }, { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL }, { "ipv6_parse_scope", regress_ipv6_parse_scope, 0, NULL, NULL }, { "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL }, { "sockaddr_port_format", regress_sockaddr_port_format, 0, NULL, NULL }, { "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL }, { "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL }, { "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL }, { "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL }, { "evutil_rtrim", test_evutil_rtrim, 0, NULL, NULL }, { "strlcpy", test_evutil_strlcpy, 0, NULL, NULL }, { "log", test_evutil_log, TT_FORK, NULL, NULL }, { "upcast", test_evutil_upcast, 0, NULL, NULL }, { "integers", test_evutil_integers, 0, NULL, NULL }, { "rand", test_evutil_rand, TT_FORK, NULL, NULL }, { "EVUTIL_IS_", test_EVUTIL_IS_, 0, NULL, NULL }, { "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL }, { "getaddrinfo_live", test_evutil_getaddrinfo_live, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL }, { "getaddrinfo_AI_ADDRCONFIG", test_evutil_getaddrinfo_AI_ADDRCONFIG, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL }, #ifdef _WIN32 { "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL }, #endif { "mm_malloc", test_event_malloc, 0, NULL, NULL }, { "mm_calloc", test_event_calloc, 0, NULL, NULL }, { "mm_strdup", test_event_strdup, 0, NULL, NULL }, { "usleep", test_evutil_usleep, TT_RETRIABLE, NULL, NULL }, { "monotonic_res", test_evutil_monotonic_res, 0, &basic_setup, (void*)"" }, { "monotonic_res_precise", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"precise" }, { "monotonic_res_fallback", test_evutil_monotonic_res, TT_OFF_BY_DEFAULT, &basic_setup, (void*)"fallback" }, { "monotonic_prc", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"" }, { "monotonic_prc_precise", test_evutil_monotonic_prc, TT_RETRIABLE, &basic_setup, (void*)"precise" }, { "monotonic_prc_fallback", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"fallback" }, { "date_rfc1123", test_evutil_date_rfc1123, 0, NULL, NULL }, { "evutil_v4addr_is_local", test_evutil_v4addr_is_local, 0, NULL, NULL }, { "evutil_v6addr_is_local", test_evutil_v6addr_is_local, 0, NULL, NULL }, END_OF_TESTCASES, }; lldpd-1.0.13/libevent/test/regress.gen.c0000644000076400001440000000000214143725025020541 0ustar00bernatusers00000000000000 lldpd-1.0.13/libevent/test/bench_http.c0000644000076400001440000001170614111362571020450 0ustar00bernatusers00000000000000/* * Copyright 2008-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #ifdef _WIN32 #include #else #include #include #include #include #endif #include #include #include #include #include #include #include "event2/event.h" #include "event2/buffer.h" #include "event2/util.h" #include "event2/http.h" #include "event2/thread.h" static void http_basic_cb(struct evhttp_request *req, void *arg); static char *content; static size_t content_len = 0; static void http_basic_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); evbuffer_add(evb, content, content_len); /* allow sending of an empty reply */ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); } #if LIBEVENT_VERSION_NUMBER >= 0x02000200 static void http_ref_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); evbuffer_add_reference(evb, content, content_len, NULL, NULL); /* allow sending of an empty reply */ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); } #endif int main(int argc, char **argv) { struct event_config *cfg = event_config_new(); struct event_base *base; struct evhttp *http; int i; int c; int use_iocp = 0; ev_uint16_t port = 8080; char *endptr = NULL; #ifdef _WIN32 WSADATA WSAData; WSAStartup(0x101, &WSAData); #else if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return (1); #endif setbuf(stdout, NULL); setbuf(stderr, NULL); for (i = 1; i < argc; ++i) { if (*argv[i] != '-') continue; c = argv[i][1]; if ((c == 'p' || c == 'l') && i + 1 >= argc) { fprintf(stderr, "-%c requires argument.\n", c); exit(1); } switch (c) { case 'p': if (i+1 >= argc || !argv[i+1]) { fprintf(stderr, "Missing port\n"); exit(1); } port = (int)strtol(argv[i+1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "Bad port\n"); exit(1); } break; case 'l': if (i+1 >= argc || !argv[i+1]) { fprintf(stderr, "Missing content length\n"); exit(1); } content_len = (size_t)strtol(argv[i+1], &endptr, 10); if (*endptr != '\0' || content_len == 0) { fprintf(stderr, "Bad content length\n"); exit(1); } break; #ifdef _WIN32 case 'i': use_iocp = 1; #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED evthread_use_windows_threads(); #endif event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP); break; #endif default: fprintf(stderr, "Illegal argument \"%c\"\n", c); exit(1); } } base = event_base_new_with_config(cfg); if (!base) { fprintf(stderr, "creating event_base failed. Exiting.\n"); return 1; } http = evhttp_new(base); content = malloc(content_len); if (content == NULL) { fprintf(stderr, "Cannot allocate content\n"); exit(1); } else { int i = 0; for (i = 0; i < (int)content_len; ++i) content[i] = (i & 255); } evhttp_set_cb(http, "/ind", http_basic_cb, NULL); fprintf(stderr, "/ind - basic content (memory copy)\n"); evhttp_set_cb(http, "/ref", http_ref_cb, NULL); fprintf(stderr, "/ref - basic content (reference)\n"); fprintf(stderr, "Serving %d bytes on port %d using %s\n", (int)content_len, port, use_iocp? "IOCP" : event_base_get_method(base)); evhttp_bind_socket(http, "0.0.0.0", port); #ifdef _WIN32 if (use_iocp) { struct timeval tv={99999999,0}; event_base_loopexit(base, &tv); } #endif event_base_dispatch(base); #ifdef _WIN32 WSACleanup(); #endif /* NOTREACHED */ return (0); } lldpd-1.0.13/libevent/test/check-dumpevents.py0000755000076400001440000000301314111362571022000 0ustar00bernatusers00000000000000#!/usr/bin/env python # # Post-process the output of test-dumpevents and check it for correctness. # import math import re import sys text = sys.stdin.readlines() try: expect_inserted_pos = text.index("Inserted:\n") expect_active_pos = text.index("Active:\n") got_inserted_pos = text.index("Inserted events:\n") got_active_pos = text.index("Active events:\n") except ValueError: sys.stderr.write("Missing expected dividing line in dumpevents output") sys.exit(1) if not (expect_inserted_pos < expect_active_pos < got_inserted_pos < got_active_pos): sys.stderr.write("Sections out of order in dumpevents output") sys.exit(1) now,T= text[1].split() T = float(T) want_inserted = set(text[expect_inserted_pos+1:expect_active_pos]) want_active = set(text[expect_active_pos+1:got_inserted_pos-1]) got_inserted = set(text[got_inserted_pos+1:got_active_pos]) got_active = set(text[got_active_pos+1:]) pat = re.compile(r'Timeout=([0-9\.]+)') def replace_time(m): t = float(m.group(1)) if .9 < abs(t-T) < 1.1: return "Timeout=T+1" elif 2.4 < abs(t-T) < 2.6: return "Timeout=T+2.5" else: return m.group(0) cleaned_inserted = set( pat.sub(replace_time, s) for s in got_inserted if "Internal" not in s) if cleaned_inserted != want_inserted: sys.stderr.write("Inserted event lists were not as expected!") sys.exit(1) if set(got_active) != set(want_active): sys.stderr.write("Active event lists were not as expected!") sys.exit(1) lldpd-1.0.13/libevent/test/regress_thread.c0000644000076400001440000003527114111362571021336 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util-internal.h" /* The old tests here need assertions to work. */ #undef NDEBUG #include "event2/event-config.h" #include #include #include #include #ifdef EVENT__HAVE_UNISTD_H #include #endif #ifdef EVENT__HAVE_SYS_WAIT_H #include #endif #ifdef EVENT__HAVE_PTHREADS #include #elif defined(_WIN32) #include #endif #include #ifdef EVENT__HAVE_UNISTD_H #include #endif #include #include "sys/queue.h" #include "event2/event.h" #include "event2/event_struct.h" #include "event2/thread.h" #include "event2/util.h" #include "evthread-internal.h" #include "event-internal.h" #include "defer-internal.h" #include "regress.h" #include "tinytest_macros.h" #include "time-internal.h" #include "regress_thread.h" struct cond_wait { void *lock; void *cond; }; static void wake_all_timeout(evutil_socket_t fd, short what, void *arg) { struct cond_wait *cw = arg; EVLOCK_LOCK(cw->lock, 0); EVTHREAD_COND_BROADCAST(cw->cond); EVLOCK_UNLOCK(cw->lock, 0); } static void wake_one_timeout(evutil_socket_t fd, short what, void *arg) { struct cond_wait *cw = arg; EVLOCK_LOCK(cw->lock, 0); EVTHREAD_COND_SIGNAL(cw->cond); EVLOCK_UNLOCK(cw->lock, 0); } #define NUM_THREADS 100 #define NUM_ITERATIONS 100 void *count_lock; static int count; static THREAD_FN basic_thread(void *arg) { struct cond_wait cw; struct event_base *base = arg; struct event ev; int i = 0; EVTHREAD_ALLOC_LOCK(cw.lock, 0); EVTHREAD_ALLOC_COND(cw.cond); assert(cw.lock); assert(cw.cond); evtimer_assign(&ev, base, wake_all_timeout, &cw); for (i = 0; i < NUM_ITERATIONS; i++) { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 3000; EVLOCK_LOCK(cw.lock, 0); /* we need to make sure that event does not happen before * we get to wait on the conditional variable */ assert(evtimer_add(&ev, &tv) == 0); assert(EVTHREAD_COND_WAIT(cw.cond, cw.lock) == 0); EVLOCK_UNLOCK(cw.lock, 0); EVLOCK_LOCK(count_lock, 0); ++count; EVLOCK_UNLOCK(count_lock, 0); } /* exit the loop only if all threads fired all timeouts */ EVLOCK_LOCK(count_lock, 0); if (count >= NUM_THREADS * NUM_ITERATIONS) event_base_loopexit(base, NULL); EVLOCK_UNLOCK(count_lock, 0); EVTHREAD_FREE_LOCK(cw.lock, 0); EVTHREAD_FREE_COND(cw.cond); THREAD_RETURN(); } static int notification_fd_used = 0; #ifndef _WIN32 static int got_sigchld = 0; static void sigchld_cb(evutil_socket_t fd, short event, void *arg) { struct timeval tv; struct event_base *base = arg; got_sigchld++; tv.tv_usec = 100000; tv.tv_sec = 0; event_base_loopexit(base, &tv); } static void notify_fd_cb(evutil_socket_t fd, short event, void *arg) { ++notification_fd_used; } #endif static void thread_basic(void *arg) { THREAD_T threads[NUM_THREADS]; struct event ev; struct timeval tv; int i; struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *notification_event = NULL; struct event *sigchld_event = NULL; EVTHREAD_ALLOC_LOCK(count_lock, 0); tt_assert(count_lock); tt_assert(base); if (evthread_make_base_notifiable(base)<0) { tt_abort_msg("Couldn't make base notifiable!"); } #ifndef _WIN32 if (data->setup_data && !strcmp(data->setup_data, "forking")) { pid_t pid; int status; sigchld_event = evsignal_new(base, SIGCHLD, sigchld_cb, base); /* This piggybacks on the th_notify_fd weirdly, and looks * inside libevent internals. Not a good idea in non-testing * code! */ notification_event = event_new(base, base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb, NULL); event_add(sigchld_event, NULL); event_add(notification_event, NULL); if ((pid = fork()) == 0) { event_del(notification_event); if (event_reinit(base) < 0) { TT_FAIL(("reinit")); exit(1); } event_assign(notification_event, base, base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb, NULL); event_add(notification_event, NULL); goto child; } event_base_dispatch(base); if (waitpid(pid, &status, 0) == -1) tt_abort_perror("waitpid"); TT_BLATHER(("Waitpid okay\n")); tt_assert(got_sigchld); tt_int_op(notification_fd_used, ==, 0); goto end; } child: #endif for (i = 0; i < NUM_THREADS; ++i) THREAD_START(threads[i], basic_thread, base); evtimer_assign(&ev, base, NULL, NULL); evutil_timerclear(&tv); tv.tv_sec = 1000; event_add(&ev, &tv); event_base_dispatch(base); for (i = 0; i < NUM_THREADS; ++i) THREAD_JOIN(threads[i]); event_del(&ev); tt_int_op(count, ==, NUM_THREADS * NUM_ITERATIONS); EVTHREAD_FREE_LOCK(count_lock, 0); TT_BLATHER(("notifiations==%d", notification_fd_used)); end: if (notification_event) event_free(notification_event); if (sigchld_event) event_free(sigchld_event); } #undef NUM_THREADS #define NUM_THREADS 10 struct alerted_record { struct cond_wait *cond; struct timeval delay; struct timeval alerted_at; int timed_out; }; static THREAD_FN wait_for_condition(void *arg) { struct alerted_record *rec = arg; int r; EVLOCK_LOCK(rec->cond->lock, 0); if (rec->delay.tv_sec || rec->delay.tv_usec) { r = EVTHREAD_COND_WAIT_TIMED(rec->cond->cond, rec->cond->lock, &rec->delay); } else { r = EVTHREAD_COND_WAIT(rec->cond->cond, rec->cond->lock); } EVLOCK_UNLOCK(rec->cond->lock, 0); evutil_gettimeofday(&rec->alerted_at, NULL); if (r == 1) rec->timed_out = 1; THREAD_RETURN(); } static void thread_conditions_simple(void *arg) { struct timeval tv_signal, tv_timeout, tv_broadcast; struct alerted_record alerted[NUM_THREADS]; THREAD_T threads[NUM_THREADS]; struct cond_wait cond; int i; struct timeval launched_at; struct event wake_one; struct event wake_all; struct basic_test_data *data = arg; struct event_base *base = data->base; int n_timed_out=0, n_signal=0, n_broadcast=0; tv_signal.tv_sec = tv_timeout.tv_sec = tv_broadcast.tv_sec = 0; tv_signal.tv_usec = 30*1000; tv_timeout.tv_usec = 150*1000; tv_broadcast.tv_usec = 500*1000; EVTHREAD_ALLOC_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE); EVTHREAD_ALLOC_COND(cond.cond); tt_assert(cond.lock); tt_assert(cond.cond); for (i = 0; i < NUM_THREADS; ++i) { memset(&alerted[i], 0, sizeof(struct alerted_record)); alerted[i].cond = &cond; } /* Threads 5 and 6 will be allowed to time out */ memcpy(&alerted[5].delay, &tv_timeout, sizeof(tv_timeout)); memcpy(&alerted[6].delay, &tv_timeout, sizeof(tv_timeout)); evtimer_assign(&wake_one, base, wake_one_timeout, &cond); evtimer_assign(&wake_all, base, wake_all_timeout, &cond); evutil_gettimeofday(&launched_at, NULL); /* Launch the threads... */ for (i = 0; i < NUM_THREADS; ++i) { THREAD_START(threads[i], wait_for_condition, &alerted[i]); } /* Start the timers... */ tt_int_op(event_add(&wake_one, &tv_signal), ==, 0); tt_int_op(event_add(&wake_all, &tv_broadcast), ==, 0); /* And run for a bit... */ event_base_dispatch(base); /* And wait till the threads are done. */ for (i = 0; i < NUM_THREADS; ++i) THREAD_JOIN(threads[i]); /* Now, let's see what happened. At least one of 5 or 6 should * have timed out. */ n_timed_out = alerted[5].timed_out + alerted[6].timed_out; tt_int_op(n_timed_out, >=, 1); tt_int_op(n_timed_out, <=, 2); for (i = 0; i < NUM_THREADS; ++i) { const struct timeval *target_delay; struct timeval target_time, actual_delay; if (alerted[i].timed_out) { TT_BLATHER(("%d looks like a timeout\n", i)); target_delay = &tv_timeout; tt_assert(i == 5 || i == 6); } else if (evutil_timerisset(&alerted[i].alerted_at)) { long diff1,diff2; evutil_timersub(&alerted[i].alerted_at, &launched_at, &actual_delay); diff1 = timeval_msec_diff(&actual_delay, &tv_signal); diff2 = timeval_msec_diff(&actual_delay, &tv_broadcast); if (labs(diff1) < labs(diff2)) { TT_BLATHER(("%d looks like a signal\n", i)); target_delay = &tv_signal; ++n_signal; } else { TT_BLATHER(("%d looks like a broadcast\n", i)); target_delay = &tv_broadcast; ++n_broadcast; } } else { TT_FAIL(("Thread %d never got woken", i)); continue; } evutil_timeradd(target_delay, &launched_at, &target_time); test_timeval_diff_leq(&target_time, &alerted[i].alerted_at, 0, 200); } tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS); tt_int_op(n_signal, ==, 1); end: EVTHREAD_FREE_LOCK(cond.lock, EVTHREAD_LOCKTYPE_RECURSIVE); EVTHREAD_FREE_COND(cond.cond); } #define CB_COUNT 128 #define QUEUE_THREAD_COUNT 8 static void SLEEP_MS(int ms) { struct timeval tv; tv.tv_sec = ms/1000; tv.tv_usec = (ms%1000)*1000; evutil_usleep_(&tv); } struct deferred_test_data { struct event_callback cbs[CB_COUNT]; struct event_base *queue; }; static struct timeval timer_start = {0,0}; static struct timeval timer_end = {0,0}; static unsigned callback_count = 0; static THREAD_T load_threads[QUEUE_THREAD_COUNT]; static struct deferred_test_data deferred_data[QUEUE_THREAD_COUNT]; static void deferred_callback(struct event_callback *cb, void *arg) { SLEEP_MS(1); callback_count += 1; } static THREAD_FN load_deferred_queue(void *arg) { struct deferred_test_data *data = arg; size_t i; for (i = 0; i < CB_COUNT; ++i) { event_deferred_cb_init_(&data->cbs[i], 0, deferred_callback, NULL); event_deferred_cb_schedule_(data->queue, &data->cbs[i]); SLEEP_MS(1); } THREAD_RETURN(); } static void timer_callback(evutil_socket_t fd, short what, void *arg) { evutil_gettimeofday(&timer_end, NULL); } static void start_threads_callback(evutil_socket_t fd, short what, void *arg) { int i; for (i = 0; i < QUEUE_THREAD_COUNT; ++i) { THREAD_START(load_threads[i], load_deferred_queue, &deferred_data[i]); } } static void thread_deferred_cb_skew(void *arg) { struct timeval tv_timer = {1, 0}; struct event_base *base = NULL; struct event_config *cfg = NULL; struct timeval elapsed; int elapsed_usec; int i; cfg = event_config_new(); tt_assert(cfg); event_config_set_max_dispatch_interval(cfg, NULL, 16, 0); base = event_base_new_with_config(cfg); tt_assert(base); for (i = 0; i < QUEUE_THREAD_COUNT; ++i) deferred_data[i].queue = base; evutil_gettimeofday(&timer_start, NULL); event_base_once(base, -1, EV_TIMEOUT, timer_callback, NULL, &tv_timer); event_base_once(base, -1, EV_TIMEOUT, start_threads_callback, NULL, NULL); event_base_dispatch(base); evutil_timersub(&timer_end, &timer_start, &elapsed); TT_BLATHER(("callback count, %u", callback_count)); elapsed_usec = (unsigned)(elapsed.tv_sec*1000000 + elapsed.tv_usec); TT_BLATHER(("elapsed time, %u usec", elapsed_usec)); /* XXX be more intelligent here. just make sure skew is * within .4 seconds for now. */ tt_assert(elapsed_usec >= 600000 && elapsed_usec <= 1400000); end: for (i = 0; i < QUEUE_THREAD_COUNT; ++i) THREAD_JOIN(load_threads[i]); if (base) event_base_free(base); if (cfg) event_config_free(cfg); } static struct event time_events[5]; static struct timeval times[5]; static struct event_base *exit_base = NULL; static void note_time_cb(evutil_socket_t fd, short what, void *arg) { evutil_gettimeofday(arg, NULL); if (arg == ×[4]) { event_base_loopbreak(exit_base); } } static THREAD_FN register_events_subthread(void *arg) { struct timeval tv = {0,0}; SLEEP_MS(100); event_active(&time_events[0], EV_TIMEOUT, 1); SLEEP_MS(100); event_active(&time_events[1], EV_TIMEOUT, 1); SLEEP_MS(100); tv.tv_usec = 100*1000; event_add(&time_events[2], &tv); tv.tv_usec = 150*1000; event_add(&time_events[3], &tv); SLEEP_MS(200); event_active(&time_events[4], EV_TIMEOUT, 1); THREAD_RETURN(); } static void thread_no_events(void *arg) { THREAD_T thread; struct basic_test_data *data = arg; struct timeval starttime, endtime; int i; exit_base = data->base; memset(times,0,sizeof(times)); for (i=0;i<5;++i) { event_assign(&time_events[i], data->base, -1, 0, note_time_cb, ×[i]); } evutil_gettimeofday(&starttime, NULL); THREAD_START(thread, register_events_subthread, data->base); event_base_loop(data->base, EVLOOP_NO_EXIT_ON_EMPTY); evutil_gettimeofday(&endtime, NULL); tt_assert(event_base_got_break(data->base)); THREAD_JOIN(thread); for (i=0; i<5; ++i) { struct timeval diff; double sec; evutil_timersub(×[i], &starttime, &diff); sec = diff.tv_sec + diff.tv_usec/1.0e6; TT_BLATHER(("event %d at %.4f seconds", i, sec)); } test_timeval_diff_eq(&starttime, ×[0], 100); test_timeval_diff_eq(&starttime, ×[1], 200); test_timeval_diff_eq(&starttime, ×[2], 400); test_timeval_diff_eq(&starttime, ×[3], 450); test_timeval_diff_eq(&starttime, ×[4], 500); test_timeval_diff_eq(&starttime, &endtime, 500); end: ; } #define TEST(name, f) \ { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE|(f), \ &basic_setup, NULL } struct testcase_t thread_testcases[] = { { "basic", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, &basic_setup, NULL }, #ifndef _WIN32 { "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, &basic_setup, (char*)"forking" }, #endif TEST(conditions_simple, TT_RETRIABLE), { "deferred_cb_skew", thread_deferred_cb_skew, TT_FORK|TT_NEED_THREADS|TT_OFF_BY_DEFAULT, &basic_setup, NULL }, #ifndef _WIN32 /****** XXX TODO FIXME windows seems to be having some timing trouble, * looking into it now. / ellzey ******/ TEST(no_events, TT_RETRIABLE), #endif END_OF_TESTCASES }; lldpd-1.0.13/libevent/test/regress_testutils.h0000644000076400001440000000504414111362571022127 0ustar00bernatusers00000000000000/* * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef REGRESS_TESTUTILS_H_INCLUDED_ #define REGRESS_TESTUTILS_H_INCLUDED_ #include "event2/dns.h" struct regress_dns_server_table { const char *q; const char *anstype; const char *ans; int seen; int lower; }; struct evdns_server_port * regress_get_dnsserver(struct event_base *base, ev_uint16_t *portnum, evutil_socket_t *psock, evdns_request_callback_fn_type cb, void *arg); /* Helper: return the port that a socket is bound on, in host order. */ int regress_get_socket_port(evutil_socket_t fd); /* used to look up pre-canned responses in a search table */ void regress_dns_server_cb( struct evdns_server_request *req, void *data); /* globally allocates a dns server that serves from a search table */ int regress_dnsserver(struct event_base *base, ev_uint16_t *port, struct regress_dns_server_table *seach_table); /* clean up the global dns server resources */ void regress_clean_dnsserver(void); struct evconnlistener; struct sockaddr; int regress_get_listener_addr(struct evconnlistener *lev, struct sockaddr *sa, ev_socklen_t *socklen); #endif /* REGRESS_TESTUTILS_H_INCLUDED_ */ lldpd-1.0.13/libevent/test/regress.c0000644000076400001440000025554514111362571020017 0ustar00bernatusers00000000000000/* * Copyright (c) 2003-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util-internal.h" #ifdef _WIN32 #include #include #endif #include "event2/event-config.h" #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #ifndef _WIN32 #include #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include "event2/event.h" #include "event2/event_struct.h" #include "event2/event_compat.h" #include "event2/tag.h" #include "event2/buffer.h" #include "event2/buffer_compat.h" #include "event2/util.h" #include "event-internal.h" #include "evthread-internal.h" #include "log-internal.h" #include "time-internal.h" #include "regress.h" #include "regress_thread.h" #ifndef _WIN32 #include "regress.gen.h" #endif evutil_socket_t pair[2]; int test_ok; int called; struct event_base *global_base; static char wbuf[4096]; static char rbuf[4096]; static int woff; static int roff; static int usepersist; static struct timeval tset; static struct timeval tcalled; #define TEST1 "this is a test" #ifdef _WIN32 #define write(fd,buf,len) send((fd),(buf),(int)(len),0) #define read(fd,buf,len) recv((fd),(buf),(int)(len),0) #endif struct basic_cb_args { struct event_base *eb; struct event *ev; unsigned int callcount; }; static void simple_read_cb(evutil_socket_t fd, short event, void *arg) { char buf[256]; int len; len = read(fd, buf, sizeof(buf)); if (len) { if (!called) { if (event_add(arg, NULL) == -1) exit(1); } } else if (called == 1) test_ok = 1; called++; } static void basic_read_cb(evutil_socket_t fd, short event, void *data) { char buf[256]; int len; struct basic_cb_args *arg = data; len = read(fd, buf, sizeof(buf)); if (len < 0) { tt_fail_perror("read (callback)"); } else { switch (arg->callcount++) { case 0: /* first call: expect to read data; cycle */ if (len > 0) return; tt_fail_msg("EOF before data read"); break; case 1: /* second call: expect EOF; stop */ if (len > 0) tt_fail_msg("not all data read on first cycle"); break; default: /* third call: should not happen */ tt_fail_msg("too many cycles"); } } event_del(arg->ev); event_base_loopexit(arg->eb, NULL); } static void dummy_read_cb(evutil_socket_t fd, short event, void *arg) { } static void simple_write_cb(evutil_socket_t fd, short event, void *arg) { int len; len = write(fd, TEST1, strlen(TEST1) + 1); if (len == -1) test_ok = 0; else test_ok = 1; } static void multiple_write_cb(evutil_socket_t fd, short event, void *arg) { struct event *ev = arg; int len; len = 128; if (woff + len >= (int)sizeof(wbuf)) len = sizeof(wbuf) - woff; len = write(fd, wbuf + woff, len); if (len == -1) { fprintf(stderr, "%s: write\n", __func__); if (usepersist) event_del(ev); return; } woff += len; if (woff >= (int)sizeof(wbuf)) { shutdown(fd, EVUTIL_SHUT_WR); if (usepersist) event_del(ev); return; } if (!usepersist) { if (event_add(ev, NULL) == -1) exit(1); } } static void multiple_read_cb(evutil_socket_t fd, short event, void *arg) { struct event *ev = arg; int len; len = read(fd, rbuf + roff, sizeof(rbuf) - roff); if (len == -1) fprintf(stderr, "%s: read\n", __func__); if (len <= 0) { if (usepersist) event_del(ev); return; } roff += len; if (!usepersist) { if (event_add(ev, NULL) == -1) exit(1); } } static void timeout_cb(evutil_socket_t fd, short event, void *arg) { evutil_gettimeofday(&tcalled, NULL); } struct both { struct event ev; int nread; }; static void combined_read_cb(evutil_socket_t fd, short event, void *arg) { struct both *both = arg; char buf[128]; int len; len = read(fd, buf, sizeof(buf)); if (len == -1) fprintf(stderr, "%s: read\n", __func__); if (len <= 0) return; both->nread += len; if (event_add(&both->ev, NULL) == -1) exit(1); } static void combined_write_cb(evutil_socket_t fd, short event, void *arg) { struct both *both = arg; char buf[128]; int len; len = sizeof(buf); if (len > both->nread) len = both->nread; memset(buf, 'q', len); len = write(fd, buf, len); if (len == -1) fprintf(stderr, "%s: write\n", __func__); if (len <= 0) { shutdown(fd, EVUTIL_SHUT_WR); return; } both->nread -= len; if (event_add(&both->ev, NULL) == -1) exit(1); } /* These macros used to replicate the work of the legacy test wrapper code */ #define setup_test(x) do { \ if (!in_legacy_test_wrapper) { \ TT_FAIL(("Legacy test %s not wrapped properly", x)); \ return; \ } \ } while (0) #define cleanup_test() setup_test("cleanup") static void test_simpleread(void) { struct event ev; /* Very simple read test */ setup_test("Simple read: "); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } shutdown(pair[0], EVUTIL_SHUT_WR); event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); event_dispatch(); cleanup_test(); } static void test_simplewrite(void) { struct event ev; /* Very simple write test */ setup_test("Simple write: "); event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); event_dispatch(); cleanup_test(); } static void simpleread_multiple_cb(evutil_socket_t fd, short event, void *arg) { if (++called == 2) test_ok = 1; } static void test_simpleread_multiple(void) { struct event one, two; /* Very simple read test */ setup_test("Simple read to multiple evens: "); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } shutdown(pair[0], EVUTIL_SHUT_WR); event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL); if (event_add(&one, NULL) == -1) exit(1); event_set(&two, pair[1], EV_READ, simpleread_multiple_cb, NULL); if (event_add(&two, NULL) == -1) exit(1); event_dispatch(); cleanup_test(); } static int have_closed = 0; static int premature_event = 0; static void simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr) { evutil_socket_t **fds = ptr; TT_BLATHER(("Closing")); evutil_closesocket(*fds[0]); evutil_closesocket(*fds[1]); *fds[0] = -1; *fds[1] = -1; have_closed = 1; } static void record_event_cb(evutil_socket_t s, short what, void *ptr) { short *whatp = ptr; if (!have_closed) premature_event = 1; *whatp = what; TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s)); } static void test_simpleclose_rw(void *ptr) { /* Test that a close of FD is detected as a read and as a write. */ struct event_base *base = event_base_new(); evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1}; evutil_socket_t *to_close[2]; struct event *rev=NULL, *wev=NULL, *closeev=NULL; struct timeval tv; short got_read_on_close = 0, got_write_on_close = 0; char buf[1024]; memset(buf, 99, sizeof(buf)); #ifdef _WIN32 #define LOCAL_SOCKETPAIR_AF AF_INET #else #define LOCAL_SOCKETPAIR_AF AF_UNIX #endif if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0) TT_DIE(("socketpair: %s", strerror(errno))); if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0) TT_DIE(("socketpair: %s", strerror(errno))); if (evutil_make_socket_nonblocking(pair1[1]) < 0) TT_DIE(("make_socket_nonblocking")); if (evutil_make_socket_nonblocking(pair2[1]) < 0) TT_DIE(("make_socket_nonblocking")); /** Stuff pair2[1] full of data, until write fails */ while (1) { int r = write(pair2[1], buf, sizeof(buf)); if (r<0) { int err = evutil_socket_geterror(pair2[1]); if (! EVUTIL_ERR_RW_RETRIABLE(err)) TT_DIE(("write failed strangely: %s", evutil_socket_error_to_string(err))); break; } } to_close[0] = &pair1[0]; to_close[1] = &pair2[0]; closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb, to_close); rev = event_new(base, pair1[1], EV_READ, record_event_cb, &got_read_on_close); TT_BLATHER(("Waiting for read on %d", (int)pair1[1])); wev = event_new(base, pair2[1], EV_WRITE, record_event_cb, &got_write_on_close); TT_BLATHER(("Waiting for write on %d", (int)pair2[1])); tv.tv_sec = 0; tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make * sure we get a read event. */ event_add(closeev, &tv); event_add(rev, NULL); event_add(wev, NULL); /* Don't let the test go on too long. */ tv.tv_sec = 0; tv.tv_usec = 200*1000; event_base_loopexit(base, &tv); event_base_loop(base, 0); tt_int_op(got_read_on_close, ==, EV_READ); tt_int_op(got_write_on_close, ==, EV_WRITE); tt_int_op(premature_event, ==, 0); end: if (pair1[0] >= 0) evutil_closesocket(pair1[0]); if (pair1[1] >= 0) evutil_closesocket(pair1[1]); if (pair2[0] >= 0) evutil_closesocket(pair2[0]); if (pair2[1] >= 0) evutil_closesocket(pair2[1]); if (rev) event_free(rev); if (wev) event_free(wev); if (closeev) event_free(closeev); if (base) event_base_free(base); } static void test_simpleclose(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; evutil_socket_t *pair = data->pair; const char *flags = (const char *)data->setup_data; int et = !!strstr(flags, "ET"); int persist = !!strstr(flags, "persist"); short events = EV_CLOSED | (et ? EV_ET : 0) | (persist ? EV_PERSIST : 0); struct event *ev = NULL; short got_event; if (!(event_base_get_features(data->base) & EV_FEATURE_EARLY_CLOSE)) tt_skip(); /* XXX: should this code moved to regress_et.c ? */ if (et && !(event_base_get_features(data->base) & EV_FEATURE_ET)) tt_skip(); ev = event_new(base, pair[0], events, record_event_cb, &got_event); tt_assert(ev); tt_assert(!event_add(ev, NULL)); got_event = 0; if (strstr(flags, "close")) { tt_assert(!evutil_closesocket(pair[1])); /* avoid closing in setup routines */ pair[1] = -1; } else if (strstr(flags, "shutdown")) { tt_assert(!shutdown(pair[1], EVUTIL_SHUT_WR)); } else { tt_abort_msg("unknown flags"); } /* w/o edge-triggerd but w/ persist it will not stop */ if (!et && persist) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 10000; tt_assert(!event_base_loopexit(base, &tv)); } tt_int_op(event_base_loop(base, EVLOOP_NONBLOCK), ==, !persist); tt_int_op(got_event, ==, (events & ~EV_PERSIST)); end: if (ev) event_free(ev); } static void test_multiple(void) { struct event ev, ev2; int i; /* Multiple read and write test */ setup_test("Multiple read/write: "); memset(rbuf, 0, sizeof(rbuf)); for (i = 0; i < (int)sizeof(wbuf); i++) wbuf[i] = i; roff = woff = 0; usepersist = 0; event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2); if (event_add(&ev2, NULL) == -1) exit(1); event_dispatch(); if (roff == woff) test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; cleanup_test(); } static void test_persistent(void) { struct event ev, ev2; int i; /* Multiple read and write test with persist */ setup_test("Persist read/write: "); memset(rbuf, 0, sizeof(rbuf)); for (i = 0; i < (int)sizeof(wbuf); i++) wbuf[i] = i; roff = woff = 0; usepersist = 1; event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2); if (event_add(&ev2, NULL) == -1) exit(1); event_dispatch(); if (roff == woff) test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; cleanup_test(); } static void test_combined(void) { struct both r1, r2, w1, w2; setup_test("Combined read/write: "); memset(&r1, 0, sizeof(r1)); memset(&r2, 0, sizeof(r2)); memset(&w1, 0, sizeof(w1)); memset(&w2, 0, sizeof(w2)); w1.nread = 4096; w2.nread = 8192; event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1); event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1); event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2); event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2); tt_assert(event_add(&r1.ev, NULL) != -1); tt_assert(!event_add(&w1.ev, NULL)); tt_assert(!event_add(&r2.ev, NULL)); tt_assert(!event_add(&w2.ev, NULL)); event_dispatch(); if (r1.nread == 8192 && r2.nread == 4096) test_ok = 1; end: cleanup_test(); } static void test_simpletimeout(void) { struct timeval tv; struct event ev; setup_test("Simple timeout: "); tv.tv_usec = 200*1000; tv.tv_sec = 0; evutil_timerclear(&tcalled); evtimer_set(&ev, timeout_cb, NULL); evtimer_add(&ev, &tv); evutil_gettimeofday(&tset, NULL); event_dispatch(); test_timeval_diff_eq(&tset, &tcalled, 200); test_ok = 1; end: cleanup_test(); } static void periodic_timeout_cb(evutil_socket_t fd, short event, void *arg) { int *count = arg; (*count)++; if (*count == 6) { /* call loopexit only once - on slow machines(?), it is * apparently possible for this to get called twice. */ test_ok = 1; event_base_loopexit(global_base, NULL); } } static void test_persistent_timeout(void) { struct timeval tv; struct event ev; int count = 0; evutil_timerclear(&tv); tv.tv_usec = 10000; event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST, periodic_timeout_cb, &count); event_add(&ev, &tv); event_dispatch(); event_del(&ev); } static void test_persistent_timeout_jump(void *ptr) { struct basic_test_data *data = ptr; struct event ev; int count = 0; struct timeval msec100 = { 0, 100 * 1000 }; struct timeval msec50 = { 0, 50 * 1000 }; struct timeval msec300 = { 0, 300 * 1000 }; event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count); event_add(&ev, &msec100); /* Wait for a bit */ evutil_usleep_(&msec300); event_base_loopexit(data->base, &msec50); event_base_dispatch(data->base); tt_int_op(count, ==, 1); end: event_del(&ev); } struct persist_active_timeout_called { int n; short events[16]; struct timeval tvs[16]; }; static void activate_cb(evutil_socket_t fd, short event, void *arg) { struct event *ev = arg; event_active(ev, EV_READ, 1); } static void persist_active_timeout_cb(evutil_socket_t fd, short event, void *arg) { struct persist_active_timeout_called *c = arg; if (c->n < 15) { c->events[c->n] = event; evutil_gettimeofday(&c->tvs[c->n], NULL); ++c->n; } } static void test_persistent_active_timeout(void *ptr) { struct timeval tv, tv2, tv_exit, start; struct event ev; struct persist_active_timeout_called res; struct basic_test_data *data = ptr; struct event_base *base = data->base; memset(&res, 0, sizeof(res)); tv.tv_sec = 0; tv.tv_usec = 200 * 1000; event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST, persist_active_timeout_cb, &res); event_add(&ev, &tv); tv2.tv_sec = 0; tv2.tv_usec = 100 * 1000; event_base_once(base, -1, EV_TIMEOUT, activate_cb, &ev, &tv2); tv_exit.tv_sec = 0; tv_exit.tv_usec = 600 * 1000; event_base_loopexit(base, &tv_exit); event_base_assert_ok_(base); evutil_gettimeofday(&start, NULL); event_base_dispatch(base); event_base_assert_ok_(base); tt_int_op(res.n, ==, 3); tt_int_op(res.events[0], ==, EV_READ); tt_int_op(res.events[1], ==, EV_TIMEOUT); tt_int_op(res.events[2], ==, EV_TIMEOUT); test_timeval_diff_eq(&start, &res.tvs[0], 100); test_timeval_diff_eq(&start, &res.tvs[1], 300); test_timeval_diff_eq(&start, &res.tvs[2], 500); end: event_del(&ev); } struct common_timeout_info { struct event ev; struct timeval called_at; int which; int count; }; static void common_timeout_cb(evutil_socket_t fd, short event, void *arg) { struct common_timeout_info *ti = arg; ++ti->count; evutil_gettimeofday(&ti->called_at, NULL); if (ti->count >= 4) event_del(&ti->ev); } static void test_common_timeout(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; int i; struct common_timeout_info info[100]; struct timeval start; struct timeval tmp_100_ms = { 0, 100*1000 }; struct timeval tmp_200_ms = { 0, 200*1000 }; struct timeval tmp_5_sec = { 5, 0 }; struct timeval tmp_5M_usec = { 0, 5*1000*1000 }; const struct timeval *ms_100, *ms_200, *sec_5; ms_100 = event_base_init_common_timeout(base, &tmp_100_ms); ms_200 = event_base_init_common_timeout(base, &tmp_200_ms); sec_5 = event_base_init_common_timeout(base, &tmp_5_sec); tt_assert(ms_100); tt_assert(ms_200); tt_assert(sec_5); tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms), ==, ms_200); tt_ptr_op(event_base_init_common_timeout(base, ms_200), ==, ms_200); tt_ptr_op(event_base_init_common_timeout(base, &tmp_5M_usec), ==, sec_5); tt_int_op(ms_100->tv_sec, ==, 0); tt_int_op(ms_200->tv_sec, ==, 0); tt_int_op(sec_5->tv_sec, ==, 5); tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000); tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000); tt_int_op(sec_5->tv_usec, ==, 0|0x50200000); memset(info, 0, sizeof(info)); for (i=0; i<100; ++i) { info[i].which = i; event_assign(&info[i].ev, base, -1, EV_TIMEOUT|EV_PERSIST, common_timeout_cb, &info[i]); if (i % 2) { if ((i%20)==1) { /* Glass-box test: Make sure we survive the * transition to non-common timeouts. It's * a little tricky. */ event_add(&info[i].ev, ms_200); event_add(&info[i].ev, &tmp_100_ms); } else if ((i%20)==3) { /* Check heap-to-common too. */ event_add(&info[i].ev, &tmp_200_ms); event_add(&info[i].ev, ms_100); } else if ((i%20)==5) { /* Also check common-to-common. */ event_add(&info[i].ev, ms_200); event_add(&info[i].ev, ms_100); } else { event_add(&info[i].ev, ms_100); } } else { event_add(&info[i].ev, ms_200); } } event_base_assert_ok_(base); evutil_gettimeofday(&start, NULL); event_base_dispatch(base); event_base_assert_ok_(base); for (i=0; i<10; ++i) { tt_int_op(info[i].count, ==, 4); if (i % 2) { test_timeval_diff_eq(&start, &info[i].called_at, 400); } else { test_timeval_diff_eq(&start, &info[i].called_at, 800); } } /* Make sure we can free the base with some events in. */ for (i=0; i<100; ++i) { if (i % 2) { event_add(&info[i].ev, ms_100); } else { event_add(&info[i].ev, ms_200); } } end: event_base_free(data->base); /* need to do this here before info is * out-of-scope */ data->base = NULL; } #ifndef _WIN32 #define current_base event_global_current_base_ extern struct event_base *current_base; static void fork_signal_cb(evutil_socket_t fd, short events, void *arg) { event_del(arg); } int child_pair[2] = { -1, -1 }; static void simple_child_read_cb(evutil_socket_t fd, short event, void *arg) { char buf[256]; int len; len = read(fd, buf, sizeof(buf)); if (write(child_pair[0], "", 1) < 0) tt_fail_perror("write"); if (len) { if (!called) { if (event_add(arg, NULL) == -1) exit(1); } } else if (called == 1) test_ok = 1; called++; } #define TEST_FORK_EXIT_SUCCESS 76 static void fork_wait_check(int pid) { int status; TT_BLATHER(("Before waitpid")); #ifdef WNOWAIT if ((waitpid(pid, &status, WNOWAIT) == -1 && errno == EINVAL) && #else if ( #endif waitpid(pid, &status, 0) == -1) { perror("waitpid"); exit(1); } TT_BLATHER(("After waitpid")); if (WEXITSTATUS(status) != TEST_FORK_EXIT_SUCCESS) { fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); exit(1); } } static void test_fork(void) { char c; struct event ev, sig_ev, usr_ev, existing_ev; pid_t pid; setup_test("After fork: "); { if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, child_pair) == -1) { fprintf(stderr, "%s: socketpair\n", __func__); exit(1); } if (evutil_make_socket_nonblocking(child_pair[0]) == -1) { fprintf(stderr, "fcntl(O_NONBLOCK)"); exit(1); } } tt_assert(current_base); evthread_make_base_notifiable(current_base); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } event_set(&ev, pair[1], EV_READ, simple_child_read_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); evsignal_set(&sig_ev, SIGCHLD, fork_signal_cb, &sig_ev); evsignal_add(&sig_ev, NULL); evsignal_set(&existing_ev, SIGUSR2, fork_signal_cb, &existing_ev); evsignal_add(&existing_ev, NULL); event_base_assert_ok_(current_base); TT_BLATHER(("Before fork")); if ((pid = regress_fork()) == 0) { /* in the child */ TT_BLATHER(("In child, before reinit")); event_base_assert_ok_(current_base); if (event_reinit(current_base) == -1) { fprintf(stdout, "FAILED (reinit)\n"); exit(1); } TT_BLATHER(("After reinit")); event_base_assert_ok_(current_base); TT_BLATHER(("After assert-ok")); evsignal_del(&sig_ev); evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); evsignal_add(&usr_ev, NULL); kill(getpid(), SIGUSR1); kill(getpid(), SIGUSR2); called = 0; event_dispatch(); event_base_free(current_base); /* we do not send an EOF; simple_read_cb requires an EOF * to set test_ok. we just verify that the callback was * called. */ exit(test_ok != 0 || called != 2 ? -2 : TEST_FORK_EXIT_SUCCESS); } /** wait until client read first message */ if (read(child_pair[1], &c, 1) < 0) { tt_fail_perror("read"); } if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } fork_wait_check(pid); /* test that the current event loop still works */ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { fprintf(stderr, "%s: write\n", __func__); } shutdown(pair[0], EVUTIL_SHUT_WR); evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); evsignal_add(&usr_ev, NULL); kill(getpid(), SIGUSR1); kill(getpid(), SIGUSR2); event_dispatch(); evsignal_del(&sig_ev); tt_int_op(test_ok, ==, 1); end: cleanup_test(); if (child_pair[0] != -1) evutil_closesocket(child_pair[0]); if (child_pair[1] != -1) evutil_closesocket(child_pair[1]); } #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED static void* del_wait_thread(void *arg) { struct timeval tv_start, tv_end; evutil_gettimeofday(&tv_start, NULL); event_dispatch(); evutil_gettimeofday(&tv_end, NULL); test_timeval_diff_eq(&tv_start, &tv_end, 300); end: return NULL; } static void del_wait_cb(evutil_socket_t fd, short event, void *arg) { struct timeval delay = { 0, 300*1000 }; TT_BLATHER(("Sleeping: %i", test_ok)); evutil_usleep_(&delay); ++test_ok; } static void test_del_wait(void) { struct event ev; THREAD_T thread; setup_test("event_del will wait: "); event_set(&ev, pair[1], EV_READ|EV_PERSIST, del_wait_cb, &ev); event_add(&ev, NULL); THREAD_START(thread, del_wait_thread, NULL); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } { struct timeval delay = { 0, 30*1000 }; evutil_usleep_(&delay); } { struct timeval tv_start, tv_end; evutil_gettimeofday(&tv_start, NULL); event_del(&ev); evutil_gettimeofday(&tv_end, NULL); test_timeval_diff_eq(&tv_start, &tv_end, 270); } THREAD_JOIN(thread); tt_int_op(test_ok, ==, 1); end: ; } static void null_cb(evutil_socket_t fd, short what, void *arg) {} static void* test_del_notify_thread(void *arg) { event_dispatch(); return NULL; } static void test_del_notify(void) { struct event ev; THREAD_T thread; test_ok = 1; event_set(&ev, -1, EV_READ, null_cb, &ev); event_add(&ev, NULL); THREAD_START(thread, test_del_notify_thread, NULL); { struct timeval delay = { 0, 1000 }; evutil_usleep_(&delay); } event_del(&ev); THREAD_JOIN(thread); } #endif static void signal_cb_sa(int sig) { test_ok = 2; } static void signal_cb(evutil_socket_t fd, short event, void *arg) { struct event *ev = arg; evsignal_del(ev); test_ok = 1; } static void test_simplesignal_impl(int find_reorder) { struct event ev; struct itimerval itv; evsignal_set(&ev, SIGALRM, signal_cb, &ev); evsignal_add(&ev, NULL); /* find bugs in which operations are re-ordered */ if (find_reorder) { evsignal_del(&ev); evsignal_add(&ev, NULL); } memset(&itv, 0, sizeof(itv)); itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 100000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) goto skip_simplesignal; event_dispatch(); skip_simplesignal: if (evsignal_del(&ev) == -1) test_ok = 0; cleanup_test(); } static void test_simplestsignal(void) { setup_test("Simplest one signal: "); test_simplesignal_impl(0); } static void test_simplesignal(void) { setup_test("Simple signal: "); test_simplesignal_impl(1); } static void test_multiplesignal(void) { struct event ev_one, ev_two; struct itimerval itv; setup_test("Multiple signal: "); evsignal_set(&ev_one, SIGALRM, signal_cb, &ev_one); evsignal_add(&ev_one, NULL); evsignal_set(&ev_two, SIGALRM, signal_cb, &ev_two); evsignal_add(&ev_two, NULL); memset(&itv, 0, sizeof(itv)); itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 100000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) goto skip_simplesignal; event_dispatch(); skip_simplesignal: if (evsignal_del(&ev_one) == -1) test_ok = 0; if (evsignal_del(&ev_two) == -1) test_ok = 0; cleanup_test(); } static void test_immediatesignal(void) { struct event ev; test_ok = 0; evsignal_set(&ev, SIGUSR1, signal_cb, &ev); evsignal_add(&ev, NULL); kill(getpid(), SIGUSR1); event_loop(EVLOOP_NONBLOCK); evsignal_del(&ev); cleanup_test(); } static void test_signal_dealloc(void) { /* make sure that evsignal_event is event_del'ed and pipe closed */ struct event ev; struct event_base *base = event_init(); evsignal_set(&ev, SIGUSR1, signal_cb, &ev); evsignal_add(&ev, NULL); evsignal_del(&ev); event_base_free(base); /* If we got here without asserting, we're fine. */ test_ok = 1; cleanup_test(); } static void test_signal_pipeloss(void) { /* make sure that the base1 pipe is closed correctly. */ struct event_base *base1, *base2; int pipe1; test_ok = 0; base1 = event_init(); pipe1 = base1->sig.ev_signal_pair[0]; base2 = event_init(); event_base_free(base2); event_base_free(base1); if (close(pipe1) != -1 || errno!=EBADF) { /* fd must be closed, so second close gives -1, EBADF */ printf("signal pipe not closed. "); test_ok = 0; } else { test_ok = 1; } cleanup_test(); } /* * make two bases to catch signals, use both of them. this only works * for event mechanisms that use our signal pipe trick. kqueue handles * signals internally, and all interested kqueues get all the signals. */ static void test_signal_switchbase(void) { struct event ev1, ev2; struct event_base *base1, *base2; int is_kqueue; test_ok = 0; base1 = event_init(); base2 = event_init(); is_kqueue = !strcmp(event_get_method(),"kqueue"); evsignal_set(&ev1, SIGUSR1, signal_cb, &ev1); evsignal_set(&ev2, SIGUSR1, signal_cb, &ev2); if (event_base_set(base1, &ev1) || event_base_set(base2, &ev2) || event_add(&ev1, NULL) || event_add(&ev2, NULL)) { fprintf(stderr, "%s: cannot set base, add\n", __func__); exit(1); } tt_ptr_op(event_get_base(&ev1), ==, base1); tt_ptr_op(event_get_base(&ev2), ==, base2); test_ok = 0; /* can handle signal before loop is called */ kill(getpid(), SIGUSR1); event_base_loop(base2, EVLOOP_NONBLOCK); if (is_kqueue) { if (!test_ok) goto end; test_ok = 0; } event_base_loop(base1, EVLOOP_NONBLOCK); if (test_ok && !is_kqueue) { test_ok = 0; /* set base1 to handle signals */ event_base_loop(base1, EVLOOP_NONBLOCK); kill(getpid(), SIGUSR1); event_base_loop(base1, EVLOOP_NONBLOCK); event_base_loop(base2, EVLOOP_NONBLOCK); } end: event_base_free(base1); event_base_free(base2); cleanup_test(); } /* * assert that a signal event removed from the event queue really is * removed - with no possibility of it's parent handler being fired. */ static void test_signal_assert(void) { struct event ev; struct event_base *base = event_init(); test_ok = 0; /* use SIGCONT so we don't kill ourselves when we signal to nowhere */ evsignal_set(&ev, SIGCONT, signal_cb, &ev); evsignal_add(&ev, NULL); /* * if evsignal_del() fails to reset the handler, it's current handler * will still point to evsig_handler(). */ evsignal_del(&ev); kill(getpid(), SIGCONT); #if 0 /* only way to verify we were in evsig_handler() */ /* XXXX Now there's no longer a good way. */ if (base->sig.evsig_caught) test_ok = 0; else test_ok = 1; #else test_ok = 1; #endif event_base_free(base); cleanup_test(); return; } /* * assert that we restore our previous signal handler properly. */ static void test_signal_restore(void) { struct event ev; struct event_base *base = event_init(); #ifdef EVENT__HAVE_SIGACTION struct sigaction sa; #endif test_ok = 0; #ifdef EVENT__HAVE_SIGACTION sa.sa_handler = signal_cb_sa; sa.sa_flags = 0x0; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) == -1) goto out; #else if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR) goto out; #endif evsignal_set(&ev, SIGUSR1, signal_cb, &ev); evsignal_add(&ev, NULL); evsignal_del(&ev); kill(getpid(), SIGUSR1); /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */ if (test_ok != 2) test_ok = 0; out: event_base_free(base); cleanup_test(); return; } static void signal_cb_swp(int sig, short event, void *arg) { called++; if (called < 5) kill(getpid(), sig); else event_loopexit(NULL); } static void timeout_cb_swp(evutil_socket_t fd, short event, void *arg) { if (called == -1) { struct timeval tv = {5, 0}; called = 0; evtimer_add((struct event *)arg, &tv); kill(getpid(), SIGUSR1); return; } test_ok = 0; event_loopexit(NULL); } static void test_signal_while_processing(void) { struct event_base *base = event_init(); struct event ev, ev_timer; struct timeval tv = {0, 0}; setup_test("Receiving a signal while processing other signal: "); called = -1; test_ok = 1; signal_set(&ev, SIGUSR1, signal_cb_swp, NULL); signal_add(&ev, NULL); evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer); evtimer_add(&ev_timer, &tv); event_dispatch(); event_base_free(base); cleanup_test(); return; } #endif static void test_free_active_base(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base1; struct event ev1; base1 = event_init(); tt_assert(base1); event_assign(&ev1, base1, data->pair[1], EV_READ, dummy_read_cb, NULL); event_add(&ev1, NULL); event_base_free(base1); /* should not crash */ base1 = event_init(); tt_assert(base1); event_assign(&ev1, base1, data->pair[0], 0, dummy_read_cb, NULL); event_active(&ev1, EV_READ, 1); event_base_free(base1); end: ; } static void test_manipulate_active_events(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event ev1; event_assign(&ev1, base, -1, EV_TIMEOUT, dummy_read_cb, NULL); /* Make sure an active event is pending. */ event_active(&ev1, EV_READ, 1); tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), ==, EV_READ); /* Make sure that activating an event twice works. */ event_active(&ev1, EV_WRITE, 1); tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), ==, EV_READ|EV_WRITE); end: event_del(&ev1); } static void event_selfarg_cb(evutil_socket_t fd, short event, void *arg) { struct event *ev = arg; struct event_base *base = event_get_base(ev); event_base_assert_ok_(base); event_base_loopexit(base, NULL); tt_want(ev == event_base_get_running_event(base)); } static void test_event_new_selfarg(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event *ev = event_new(base, -1, EV_READ, event_selfarg_cb, event_self_cbarg()); event_active(ev, EV_READ, 1); event_base_dispatch(base); event_free(ev); } static void test_event_assign_selfarg(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event ev; event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, event_self_cbarg()); event_active(&ev, EV_READ, 1); event_base_dispatch(base); } static void test_event_base_get_num_events(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event ev; int event_count_active; int event_count_virtual; int event_count_added; int event_count_active_virtual; int event_count_active_added; int event_count_virtual_added; int event_count_active_added_virtual; struct timeval qsec = {0, 100000}; event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, event_self_cbarg()); event_add(&ev, &qsec); event_count_active = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE); event_count_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL); event_count_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ADDED); event_count_active_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); event_count_active_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); event_count_virtual_added = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); event_count_active_added_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE| EVENT_BASE_COUNT_ADDED| EVENT_BASE_COUNT_VIRTUAL); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 0); /* libevent itself adds a timeout event, so the event_count is 2 here */ tt_int_op(event_count_added, ==, 2); tt_int_op(event_count_active_virtual, ==, 0); tt_int_op(event_count_active_added, ==, 2); tt_int_op(event_count_virtual_added, ==, 2); tt_int_op(event_count_active_added_virtual, ==, 2); event_active(&ev, EV_READ, 1); event_count_active = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE); event_count_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL); event_count_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ADDED); event_count_active_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); event_count_active_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); event_count_virtual_added = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); event_count_active_added_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE| EVENT_BASE_COUNT_ADDED| EVENT_BASE_COUNT_VIRTUAL); tt_int_op(event_count_active, ==, 1); tt_int_op(event_count_virtual, ==, 0); tt_int_op(event_count_added, ==, 3); tt_int_op(event_count_active_virtual, ==, 1); tt_int_op(event_count_active_added, ==, 4); tt_int_op(event_count_virtual_added, ==, 3); tt_int_op(event_count_active_added_virtual, ==, 4); event_base_loop(base, 0); event_count_active = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE); event_count_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL); event_count_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ADDED); event_count_active_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); event_count_active_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); event_count_virtual_added = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); event_count_active_added_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE| EVENT_BASE_COUNT_ADDED| EVENT_BASE_COUNT_VIRTUAL); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 0); tt_int_op(event_count_added, ==, 0); tt_int_op(event_count_active_virtual, ==, 0); tt_int_op(event_count_active_added, ==, 0); tt_int_op(event_count_virtual_added, ==, 0); tt_int_op(event_count_active_added_virtual, ==, 0); event_base_add_virtual_(base); event_count_active = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE); event_count_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL); event_count_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ADDED); event_count_active_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_VIRTUAL); event_count_active_added = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE|EVENT_BASE_COUNT_ADDED); event_count_virtual_added = event_base_get_num_events(base, EVENT_BASE_COUNT_VIRTUAL|EVENT_BASE_COUNT_ADDED); event_count_active_added_virtual = event_base_get_num_events(base, EVENT_BASE_COUNT_ACTIVE| EVENT_BASE_COUNT_ADDED| EVENT_BASE_COUNT_VIRTUAL); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 1); tt_int_op(event_count_added, ==, 0); tt_int_op(event_count_active_virtual, ==, 1); tt_int_op(event_count_active_added, ==, 0); tt_int_op(event_count_virtual_added, ==, 1); tt_int_op(event_count_active_added_virtual, ==, 1); end: ; } static void test_event_base_get_max_events(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event ev; struct event ev2; int event_count_active; int event_count_virtual; int event_count_added; int event_count_active_virtual; int event_count_active_added; int event_count_virtual_added; int event_count_active_added_virtual; struct timeval qsec = {0, 100000}; event_assign(&ev, base, -1, EV_READ, event_selfarg_cb, event_self_cbarg()); event_assign(&ev2, base, -1, EV_READ, event_selfarg_cb, event_self_cbarg()); event_add(&ev, &qsec); event_add(&ev2, &qsec); event_del(&ev2); event_count_active = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE, 0); event_count_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL, 0); event_count_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ADDED, 0); event_count_active_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); event_count_active_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); event_count_virtual_added = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); event_count_active_added_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED | EVENT_BASE_COUNT_VIRTUAL, 0); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 0); /* libevent itself adds a timeout event, so the event_count is 4 here */ tt_int_op(event_count_added, ==, 4); tt_int_op(event_count_active_virtual, ==, 0); tt_int_op(event_count_active_added, ==, 4); tt_int_op(event_count_virtual_added, ==, 4); tt_int_op(event_count_active_added_virtual, ==, 4); event_active(&ev, EV_READ, 1); event_count_active = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE, 0); event_count_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL, 0); event_count_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ADDED, 0); event_count_active_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); event_count_active_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); event_count_virtual_added = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); event_count_active_added_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED | EVENT_BASE_COUNT_VIRTUAL, 0); tt_int_op(event_count_active, ==, 1); tt_int_op(event_count_virtual, ==, 0); tt_int_op(event_count_added, ==, 4); tt_int_op(event_count_active_virtual, ==, 1); tt_int_op(event_count_active_added, ==, 5); tt_int_op(event_count_virtual_added, ==, 4); tt_int_op(event_count_active_added_virtual, ==, 5); event_base_loop(base, 0); event_count_active = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE, 1); event_count_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL, 1); event_count_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ADDED, 1); event_count_active_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); event_count_active_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); event_count_virtual_added = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); event_count_active_added_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED | EVENT_BASE_COUNT_VIRTUAL, 1); tt_int_op(event_count_active, ==, 1); tt_int_op(event_count_virtual, ==, 0); tt_int_op(event_count_added, ==, 4); tt_int_op(event_count_active_virtual, ==, 0); tt_int_op(event_count_active_added, ==, 0); tt_int_op(event_count_virtual_added, ==, 0); tt_int_op(event_count_active_added_virtual, ==, 0); event_count_active = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE, 0); event_count_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL, 0); event_count_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ADDED, 0); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 0); tt_int_op(event_count_added, ==, 0); event_base_add_virtual_(base); event_count_active = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE, 0); event_count_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL, 0); event_count_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ADDED, 0); event_count_active_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_VIRTUAL, 0); event_count_active_added = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED, 0); event_count_virtual_added = event_base_get_max_events(base, EVENT_BASE_COUNT_VIRTUAL | EVENT_BASE_COUNT_ADDED, 0); event_count_active_added_virtual = event_base_get_max_events(base, EVENT_BASE_COUNT_ACTIVE | EVENT_BASE_COUNT_ADDED | EVENT_BASE_COUNT_VIRTUAL, 0); tt_int_op(event_count_active, ==, 0); tt_int_op(event_count_virtual, ==, 1); tt_int_op(event_count_added, ==, 0); tt_int_op(event_count_active_virtual, ==, 1); tt_int_op(event_count_active_added, ==, 0); tt_int_op(event_count_virtual_added, ==, 1); tt_int_op(event_count_active_added_virtual, ==, 1); end: ; } static void test_bad_assign(void *ptr) { struct event ev; int r; /* READ|SIGNAL is not allowed */ r = event_assign(&ev, NULL, -1, EV_SIGNAL|EV_READ, dummy_read_cb, NULL); tt_int_op(r,==,-1); end: ; } static int reentrant_cb_run = 0; static void bad_reentrant_run_loop_cb(evutil_socket_t fd, short what, void *ptr) { struct event_base *base = ptr; int r; reentrant_cb_run = 1; /* This reentrant call to event_base_loop should be detected and * should fail */ r = event_base_loop(base, 0); tt_int_op(r, ==, -1); end: ; } static void test_bad_reentrant(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event ev; int r; event_assign(&ev, base, -1, 0, bad_reentrant_run_loop_cb, base); event_active(&ev, EV_WRITE, 1); r = event_base_loop(base, 0); tt_int_op(r, ==, 1); tt_int_op(reentrant_cb_run, ==, 1); end: ; } static int n_write_a_byte_cb=0; static int n_read_and_drain_cb=0; static int n_activate_other_event_cb=0; static void write_a_byte_cb(evutil_socket_t fd, short what, void *arg) { char buf[] = "x"; if (write(fd, buf, 1) == 1) ++n_write_a_byte_cb; } static void read_and_drain_cb(evutil_socket_t fd, short what, void *arg) { char buf[128]; int n; ++n_read_and_drain_cb; while ((n = read(fd, buf, sizeof(buf))) > 0) ; } static void activate_other_event_cb(evutil_socket_t fd, short what, void *other_) { struct event *ev_activate = other_; ++n_activate_other_event_cb; event_active_later_(ev_activate, EV_READ); } static void test_active_later(void *ptr) { struct basic_test_data *data = ptr; struct event *ev1 = NULL, *ev2 = NULL; struct event ev3, ev4; struct timeval qsec = {0, 100000}; ev1 = event_new(data->base, data->pair[0], EV_READ|EV_PERSIST, read_and_drain_cb, NULL); ev2 = event_new(data->base, data->pair[1], EV_WRITE|EV_PERSIST, write_a_byte_cb, NULL); event_assign(&ev3, data->base, -1, 0, activate_other_event_cb, &ev4); event_assign(&ev4, data->base, -1, 0, activate_other_event_cb, &ev3); event_add(ev1, NULL); event_add(ev2, NULL); event_active_later_(&ev3, EV_READ); event_base_loopexit(data->base, &qsec); event_base_loop(data->base, 0); TT_BLATHER(("%d write calls, %d read calls, %d activate-other calls.", n_write_a_byte_cb, n_read_and_drain_cb, n_activate_other_event_cb)); event_del(&ev3); event_del(&ev4); tt_int_op(n_write_a_byte_cb, ==, n_activate_other_event_cb); tt_int_op(n_write_a_byte_cb, >, 100); tt_int_op(n_read_and_drain_cb, >, 100); tt_int_op(n_activate_other_event_cb, >, 100); event_active_later_(&ev4, EV_READ); event_active(&ev4, EV_READ, 1); /* This should make the event active immediately. */ tt_assert((ev4.ev_flags & EVLIST_ACTIVE) != 0); tt_assert((ev4.ev_flags & EVLIST_ACTIVE_LATER) == 0); /* Now leave this one around, so that event_free sees it and removes * it. */ event_active_later_(&ev3, EV_READ); event_base_assert_ok_(data->base); end: if (ev1) event_free(ev1); if (ev2) event_free(ev2); event_base_free(data->base); data->base = NULL; } static void incr_arg_cb(evutil_socket_t fd, short what, void *arg) { int *intptr = arg; (void) fd; (void) what; ++*intptr; } static void remove_timers_cb(evutil_socket_t fd, short what, void *arg) { struct event **ep = arg; (void) fd; (void) what; event_remove_timer(ep[0]); event_remove_timer(ep[1]); } static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg) { evutil_socket_t *sockp = arg; (void) fd; (void) what; if (write(*sockp, "A", 1) < 0) tt_fail_perror("write"); } struct read_not_timeout_param { struct event **ev; int events; int count; }; static void read_not_timeout_cb(evutil_socket_t fd, short what, void *arg) { struct read_not_timeout_param *rntp = arg; char c; ev_ssize_t n; (void) fd; (void) what; n = read(fd, &c, 1); tt_int_op(n, ==, 1); rntp->events |= what; ++rntp->count; if(2 == rntp->count) event_del(rntp->ev[0]); end: ; } static void test_event_remove_timeout(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = data->base; struct event *ev[5]; int ev1_fired=0; struct timeval ms25 = { 0, 25*1000 }, ms40 = { 0, 40*1000 }, ms75 = { 0, 75*1000 }, ms125 = { 0, 125*1000 }; struct read_not_timeout_param rntp = { ev, 0, 0 }; event_base_assert_ok_(base); ev[0] = event_new(base, data->pair[0], EV_READ|EV_PERSIST, read_not_timeout_cb, &rntp); ev[1] = evtimer_new(base, incr_arg_cb, &ev1_fired); ev[2] = evtimer_new(base, remove_timers_cb, ev); ev[3] = evtimer_new(base, send_a_byte_cb, &data->pair[1]); ev[4] = evtimer_new(base, send_a_byte_cb, &data->pair[1]); tt_assert(base); event_add(ev[2], &ms25); /* remove timers */ event_add(ev[4], &ms40); /* write to test if timer re-activates */ event_add(ev[0], &ms75); /* read */ event_add(ev[1], &ms75); /* timer */ event_add(ev[3], &ms125); /* timeout. */ event_base_assert_ok_(base); event_base_dispatch(base); tt_int_op(ev1_fired, ==, 0); tt_int_op(rntp.events, ==, EV_READ); event_base_assert_ok_(base); end: event_free(ev[0]); event_free(ev[1]); event_free(ev[2]); event_free(ev[3]); event_free(ev[4]); } static void test_event_base_new(void *ptr) { struct basic_test_data *data = ptr; struct event_base *base = 0; struct event ev1; struct basic_cb_args args; int towrite = (int)strlen(TEST1)+1; int len = write(data->pair[0], TEST1, towrite); if (len < 0) tt_abort_perror("initial write"); else if (len != towrite) tt_abort_printf(("initial write fell short (%d of %d bytes)", len, towrite)); if (shutdown(data->pair[0], EVUTIL_SHUT_WR)) tt_abort_perror("initial write shutdown"); base = event_base_new(); if (!base) tt_abort_msg("failed to create event base"); args.eb = base; args.ev = &ev1; args.callcount = 0; event_assign(&ev1, base, data->pair[1], EV_READ|EV_PERSIST, basic_read_cb, &args); if (event_add(&ev1, NULL)) tt_abort_perror("initial event_add"); if (event_base_loop(base, 0)) tt_abort_msg("unsuccessful exit from event loop"); end: if (base) event_base_free(base); } static void test_loopexit(void) { struct timeval tv, tv_start, tv_end; struct event ev; setup_test("Loop exit: "); tv.tv_usec = 0; tv.tv_sec = 60*60*24; evtimer_set(&ev, timeout_cb, NULL); evtimer_add(&ev, &tv); tv.tv_usec = 300*1000; tv.tv_sec = 0; event_loopexit(&tv); evutil_gettimeofday(&tv_start, NULL); event_dispatch(); evutil_gettimeofday(&tv_end, NULL); evtimer_del(&ev); tt_assert(event_base_got_exit(global_base)); tt_assert(!event_base_got_break(global_base)); test_timeval_diff_eq(&tv_start, &tv_end, 300); test_ok = 1; end: cleanup_test(); } static void test_loopexit_multiple(void) { struct timeval tv, tv_start, tv_end; struct event_base *base; setup_test("Loop Multiple exit: "); base = event_base_new(); tv.tv_usec = 200*1000; tv.tv_sec = 0; event_base_loopexit(base, &tv); tv.tv_usec = 0; tv.tv_sec = 3; event_base_loopexit(base, &tv); evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(base); evutil_gettimeofday(&tv_end, NULL); tt_assert(event_base_got_exit(base)); tt_assert(!event_base_got_break(base)); event_base_free(base); test_timeval_diff_eq(&tv_start, &tv_end, 200); test_ok = 1; end: cleanup_test(); } static void break_cb(evutil_socket_t fd, short events, void *arg) { test_ok = 1; event_loopbreak(); } static void fail_cb(evutil_socket_t fd, short events, void *arg) { test_ok = 0; } static void test_loopbreak(void) { struct event ev1, ev2; struct timeval tv; setup_test("Loop break: "); tv.tv_sec = 0; tv.tv_usec = 0; evtimer_set(&ev1, break_cb, NULL); evtimer_add(&ev1, &tv); evtimer_set(&ev2, fail_cb, NULL); evtimer_add(&ev2, &tv); event_dispatch(); tt_assert(!event_base_got_exit(global_base)); tt_assert(event_base_got_break(global_base)); evtimer_del(&ev1); evtimer_del(&ev2); end: cleanup_test(); } static struct event *readd_test_event_last_added = NULL; static void re_add_read_cb(evutil_socket_t fd, short event, void *arg) { char buf[256]; struct event *ev_other = arg; ev_ssize_t n_read; readd_test_event_last_added = ev_other; n_read = read(fd, buf, sizeof(buf)); if (n_read < 0) { tt_fail_perror("read"); event_base_loopbreak(event_get_base(ev_other)); } else { event_add(ev_other, NULL); ++test_ok; } } static void test_nonpersist_readd(void *_data) { struct event ev1, ev2; struct basic_test_data *data = _data; memset(&ev1, 0, sizeof(ev1)); memset(&ev2, 0, sizeof(ev2)); tt_assert(!event_assign(&ev1, data->base, data->pair[0], EV_READ, re_add_read_cb, &ev2)); tt_assert(!event_assign(&ev2, data->base, data->pair[1], EV_READ, re_add_read_cb, &ev1)); tt_int_op(write(data->pair[0], "Hello", 5), ==, 5); tt_int_op(write(data->pair[1], "Hello", 5), ==, 5); tt_int_op(event_add(&ev1, NULL), ==, 0); tt_int_op(event_add(&ev2, NULL), ==, 0); tt_int_op(event_base_loop(data->base, EVLOOP_ONCE), ==, 0); tt_int_op(test_ok, ==, 2); /* At this point, we executed both callbacks. Whichever one got * called first added the second, but the second then immediately got * deleted before its callback was called. At this point, though, it * re-added the first. */ tt_assert(readd_test_event_last_added); if (readd_test_event_last_added == &ev1) { tt_assert(event_pending(&ev1, EV_READ, NULL) && !event_pending(&ev2, EV_READ, NULL)); } else { tt_assert(event_pending(&ev2, EV_READ, NULL) && !event_pending(&ev1, EV_READ, NULL)); } end: if (event_initialized(&ev1)) event_del(&ev1); if (event_initialized(&ev2)) event_del(&ev2); } struct test_pri_event { struct event ev; int count; }; static void test_priorities_cb(evutil_socket_t fd, short what, void *arg) { struct test_pri_event *pri = arg; struct timeval tv; if (pri->count == 3) { event_loopexit(NULL); return; } pri->count++; evutil_timerclear(&tv); event_add(&pri->ev, &tv); } static void test_priorities_impl(int npriorities) { struct test_pri_event one, two; struct timeval tv; TT_BLATHER(("Testing Priorities %d: ", npriorities)); event_base_priority_init(global_base, npriorities); memset(&one, 0, sizeof(one)); memset(&two, 0, sizeof(two)); timeout_set(&one.ev, test_priorities_cb, &one); if (event_priority_set(&one.ev, 0) == -1) { fprintf(stderr, "%s: failed to set priority", __func__); exit(1); } timeout_set(&two.ev, test_priorities_cb, &two); if (event_priority_set(&two.ev, npriorities - 1) == -1) { fprintf(stderr, "%s: failed to set priority", __func__); exit(1); } evutil_timerclear(&tv); if (event_add(&one.ev, &tv) == -1) exit(1); if (event_add(&two.ev, &tv) == -1) exit(1); event_dispatch(); event_del(&one.ev); event_del(&two.ev); if (npriorities == 1) { if (one.count == 3 && two.count == 3) test_ok = 1; } else if (npriorities == 2) { /* Two is called once because event_loopexit is priority 1 */ if (one.count == 3 && two.count == 1) test_ok = 1; } else { if (one.count == 3 && two.count == 0) test_ok = 1; } } static void test_priorities(void) { test_priorities_impl(1); if (test_ok) test_priorities_impl(2); if (test_ok) test_priorities_impl(3); } /* priority-active-inversion: activate a higher-priority event, and make sure * it keeps us from running a lower-priority event first. */ static int n_pai_calls = 0; static struct event pai_events[3]; static void prio_active_inversion_cb(evutil_socket_t fd, short what, void *arg) { int *call_order = arg; *call_order = n_pai_calls++; if (n_pai_calls == 1) { /* This should activate later, even though it shares a priority with us. */ event_active(&pai_events[1], EV_READ, 1); /* This should activate next, since its priority is higher, even though we activated it second. */ event_active(&pai_events[2], EV_TIMEOUT, 1); } } static void test_priority_active_inversion(void *data_) { struct basic_test_data *data = data_; struct event_base *base = data->base; int call_order[3]; int i; tt_int_op(event_base_priority_init(base, 8), ==, 0); n_pai_calls = 0; memset(call_order, 0, sizeof(call_order)); for (i=0;i<3;++i) { event_assign(&pai_events[i], data->base, -1, 0, prio_active_inversion_cb, &call_order[i]); } event_priority_set(&pai_events[0], 4); event_priority_set(&pai_events[1], 4); event_priority_set(&pai_events[2], 0); event_active(&pai_events[0], EV_WRITE, 1); event_base_dispatch(base); tt_int_op(n_pai_calls, ==, 3); tt_int_op(call_order[0], ==, 0); tt_int_op(call_order[1], ==, 2); tt_int_op(call_order[2], ==, 1); end: ; } static void test_multiple_cb(evutil_socket_t fd, short event, void *arg) { if (event & EV_READ) test_ok |= 1; else if (event & EV_WRITE) test_ok |= 2; } static void test_multiple_events_for_same_fd(void) { struct event e1, e2; setup_test("Multiple events for same fd: "); event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL); event_add(&e1, NULL); event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL); event_add(&e2, NULL); event_loop(EVLOOP_ONCE); event_del(&e2); if (write(pair[1], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } event_loop(EVLOOP_ONCE); event_del(&e1); if (test_ok != 3) test_ok = 0; cleanup_test(); } int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf); int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf); int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t number); int evtag_decode_tag(ev_uint32_t *pnumber, struct evbuffer *evbuf); static void read_once_cb(evutil_socket_t fd, short event, void *arg) { char buf[256]; int len; len = read(fd, buf, sizeof(buf)); if (called) { test_ok = 0; } else if (len) { /* Assumes global pair[0] can be used for writing */ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); test_ok = 0; } else { test_ok = 1; } } called++; } static void test_want_only_once(void) { struct event ev; struct timeval tv; /* Very simple read test */ setup_test("Want read only once: "); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } /* Setup the loop termination */ evutil_timerclear(&tv); tv.tv_usec = 300*1000; event_loopexit(&tv); event_set(&ev, pair[1], EV_READ, read_once_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); event_dispatch(); cleanup_test(); } #define TEST_MAX_INT 6 static void evtag_int_test(void *ptr) { struct evbuffer *tmp = evbuffer_new(); ev_uint32_t integers[TEST_MAX_INT] = { 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 }; ev_uint32_t integer; ev_uint64_t big_int; int i; evtag_init(); for (i = 0; i < TEST_MAX_INT; i++) { int oldlen, newlen; oldlen = (int)EVBUFFER_LENGTH(tmp); evtag_encode_int(tmp, integers[i]); newlen = (int)EVBUFFER_LENGTH(tmp); TT_BLATHER(("encoded 0x%08x with %d bytes", (unsigned)integers[i], newlen - oldlen)); big_int = integers[i]; big_int *= 1000000000; /* 1 billion */ evtag_encode_int64(tmp, big_int); } for (i = 0; i < TEST_MAX_INT; i++) { tt_int_op(evtag_decode_int(&integer, tmp), !=, -1); tt_uint_op(integer, ==, integers[i]); tt_int_op(evtag_decode_int64(&big_int, tmp), !=, -1); tt_assert((big_int / 1000000000) == integers[i]); } tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); end: evbuffer_free(tmp); } static void evtag_fuzz(void *ptr) { unsigned char buffer[4096]; struct evbuffer *tmp = evbuffer_new(); struct timeval tv; int i, j; int not_failed = 0; evtag_init(); for (j = 0; j < 100; j++) { for (i = 0; i < (int)sizeof(buffer); i++) buffer[i] = test_weakrand(); evbuffer_drain(tmp, -1); evbuffer_add(tmp, buffer, sizeof(buffer)); if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) not_failed++; } /* The majority of decodes should fail */ tt_int_op(not_failed, <, 10); /* Now insert some corruption into the tag length field */ evbuffer_drain(tmp, -1); evutil_timerclear(&tv); tv.tv_sec = 1; evtag_marshal_timeval(tmp, 0, &tv); evbuffer_add(tmp, buffer, sizeof(buffer)); ((char *)EVBUFFER_DATA(tmp))[1] = '\xff'; if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) { tt_abort_msg("evtag_unmarshal_timeval should have failed"); } end: evbuffer_free(tmp); } static void evtag_tag_encoding(void *ptr) { struct evbuffer *tmp = evbuffer_new(); ev_uint32_t integers[TEST_MAX_INT] = { 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 }; ev_uint32_t integer; int i; evtag_init(); for (i = 0; i < TEST_MAX_INT; i++) { int oldlen, newlen; oldlen = (int)EVBUFFER_LENGTH(tmp); evtag_encode_tag(tmp, integers[i]); newlen = (int)EVBUFFER_LENGTH(tmp); TT_BLATHER(("encoded 0x%08x with %d bytes", (unsigned)integers[i], newlen - oldlen)); } for (i = 0; i < TEST_MAX_INT; i++) { tt_int_op(evtag_decode_tag(&integer, tmp), !=, -1); tt_uint_op(integer, ==, integers[i]); } tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); end: evbuffer_free(tmp); } static void evtag_test_peek(void *ptr) { struct evbuffer *tmp = evbuffer_new(); ev_uint32_t u32; evtag_marshal_int(tmp, 30, 0); evtag_marshal_string(tmp, 40, "Hello world"); tt_int_op(evtag_peek(tmp, &u32), ==, 1); tt_int_op(u32, ==, 30); tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); tt_int_op(u32, ==, 1+1+1); tt_int_op(evtag_consume(tmp), ==, 0); tt_int_op(evtag_peek(tmp, &u32), ==, 1); tt_int_op(u32, ==, 40); tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); tt_int_op(u32, ==, 1+1+11); tt_int_op(evtag_payload_length(tmp, &u32), ==, 0); tt_int_op(u32, ==, 11); end: evbuffer_free(tmp); } static void test_methods(void *ptr) { const char **methods = event_get_supported_methods(); struct event_config *cfg = NULL; struct event_base *base = NULL; const char *backend; int n_methods = 0; tt_assert(methods); backend = methods[0]; while (*methods != NULL) { TT_BLATHER(("Support method: %s", *methods)); ++methods; ++n_methods; } cfg = event_config_new(); assert(cfg != NULL); tt_int_op(event_config_avoid_method(cfg, backend), ==, 0); event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); base = event_base_new_with_config(cfg); if (n_methods > 1) { tt_assert(base); tt_str_op(backend, !=, event_base_get_method(base)); } else { tt_assert(base == NULL); } end: if (base) event_base_free(base); if (cfg) event_config_free(cfg); } static void test_version(void *arg) { const char *vstr; ev_uint32_t vint; int major, minor, patch, n; vstr = event_get_version(); vint = event_get_version_number(); tt_assert(vstr); tt_assert(vint); tt_str_op(vstr, ==, LIBEVENT_VERSION); tt_int_op(vint, ==, LIBEVENT_VERSION_NUMBER); n = sscanf(vstr, "%d.%d.%d", &major, &minor, &patch); tt_assert(3 == n); tt_int_op((vint&0xffffff00), ==, ((major<<24)|(minor<<16)|(patch<<8))); end: ; } static void test_base_features(void *arg) { struct event_base *base = NULL; struct event_config *cfg = NULL; cfg = event_config_new(); tt_assert(0 == event_config_require_features(cfg, EV_FEATURE_ET)); base = event_base_new_with_config(cfg); if (base) { tt_int_op(EV_FEATURE_ET, ==, event_base_get_features(base) & EV_FEATURE_ET); } else { base = event_base_new(); tt_int_op(0, ==, event_base_get_features(base) & EV_FEATURE_ET); } end: if (base) event_base_free(base); if (cfg) event_config_free(cfg); } #ifdef EVENT__HAVE_SETENV #define SETENV_OK #elif !defined(EVENT__HAVE_SETENV) && defined(EVENT__HAVE_PUTENV) static void setenv(const char *k, const char *v, int o_) { char b[256]; evutil_snprintf(b, sizeof(b), "%s=%s",k,v); putenv(b); } #define SETENV_OK #endif #ifdef EVENT__HAVE_UNSETENV #define UNSETENV_OK #elif !defined(EVENT__HAVE_UNSETENV) && defined(EVENT__HAVE_PUTENV) static void unsetenv(const char *k) { char b[256]; evutil_snprintf(b, sizeof(b), "%s=",k); putenv(b); } #define UNSETENV_OK #endif #if defined(SETENV_OK) && defined(UNSETENV_OK) static void methodname_to_envvar(const char *mname, char *buf, size_t buflen) { char *cp; evutil_snprintf(buf, buflen, "EVENT_NO%s", mname); for (cp = buf; *cp; ++cp) { *cp = EVUTIL_TOUPPER_(*cp); } } #endif static void test_base_environ(void *arg) { struct event_base *base = NULL; struct event_config *cfg = NULL; #if defined(SETENV_OK) && defined(UNSETENV_OK) const char **basenames; int i, n_methods=0; char varbuf[128]; const char *defaultname, *ignoreenvname; /* See if unsetenv works before we rely on it. */ setenv("EVENT_NOWAFFLES", "1", 1); unsetenv("EVENT_NOWAFFLES"); if (getenv("EVENT_NOWAFFLES") != NULL) { #ifndef EVENT__HAVE_UNSETENV TT_DECLARE("NOTE", ("Can't fake unsetenv; skipping test")); #else TT_DECLARE("NOTE", ("unsetenv doesn't work; skipping test")); #endif tt_skip(); } basenames = event_get_supported_methods(); for (i = 0; basenames[i]; ++i) { methodname_to_envvar(basenames[i], varbuf, sizeof(varbuf)); unsetenv(varbuf); ++n_methods; } base = event_base_new(); tt_assert(base); defaultname = event_base_get_method(base); TT_BLATHER(("default is <%s>", defaultname)); event_base_free(base); base = NULL; /* Can we disable the method with EVENT_NOfoo ? */ if (!strcmp(defaultname, "epoll (with changelist)")) { setenv("EVENT_NOEPOLL", "1", 1); ignoreenvname = "epoll"; } else { methodname_to_envvar(defaultname, varbuf, sizeof(varbuf)); setenv(varbuf, "1", 1); ignoreenvname = defaultname; } /* Use an empty cfg rather than NULL so a failure doesn't exit() */ cfg = event_config_new(); base = event_base_new_with_config(cfg); event_config_free(cfg); cfg = NULL; if (n_methods == 1) { tt_assert(!base); } else { tt_assert(base); tt_str_op(defaultname, !=, event_base_get_method(base)); event_base_free(base); base = NULL; } /* Can we disable looking at the environment with IGNORE_ENV ? */ cfg = event_config_new(); event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); base = event_base_new_with_config(cfg); tt_assert(base); tt_str_op(ignoreenvname, ==, event_base_get_method(base)); #else tt_skip(); #endif end: if (base) event_base_free(base); if (cfg) event_config_free(cfg); } static void read_called_once_cb(evutil_socket_t fd, short event, void *arg) { tt_int_op(event, ==, EV_READ); called += 1; end: ; } static void timeout_called_once_cb(evutil_socket_t fd, short event, void *arg) { tt_int_op(event, ==, EV_TIMEOUT); called += 100; end: ; } static void immediate_called_twice_cb(evutil_socket_t fd, short event, void *arg) { tt_int_op(event, ==, EV_TIMEOUT); called += 1000; end: ; } static void test_event_once(void *ptr) { struct basic_test_data *data = ptr; struct timeval tv; int r; tv.tv_sec = 0; tv.tv_usec = 50*1000; called = 0; r = event_base_once(data->base, data->pair[0], EV_READ, read_called_once_cb, NULL, NULL); tt_int_op(r, ==, 0); r = event_base_once(data->base, -1, EV_TIMEOUT, timeout_called_once_cb, NULL, &tv); tt_int_op(r, ==, 0); r = event_base_once(data->base, -1, 0, NULL, NULL, NULL); tt_int_op(r, <, 0); r = event_base_once(data->base, -1, EV_TIMEOUT, immediate_called_twice_cb, NULL, NULL); tt_int_op(r, ==, 0); tv.tv_sec = 0; tv.tv_usec = 0; r = event_base_once(data->base, -1, EV_TIMEOUT, immediate_called_twice_cb, NULL, &tv); tt_int_op(r, ==, 0); if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } shutdown(data->pair[1], EVUTIL_SHUT_WR); event_base_dispatch(data->base); tt_int_op(called, ==, 2101); end: ; } static void test_event_once_never(void *ptr) { struct basic_test_data *data = ptr; struct timeval tv; /* Have one trigger in 10 seconds (don't worry, because) */ tv.tv_sec = 10; tv.tv_usec = 0; called = 0; event_base_once(data->base, -1, EV_TIMEOUT, timeout_called_once_cb, NULL, &tv); /* But shut down the base in 75 msec. */ tv.tv_sec = 0; tv.tv_usec = 75*1000; event_base_loopexit(data->base, &tv); event_base_dispatch(data->base); tt_int_op(called, ==, 0); end: ; } static void test_event_pending(void *ptr) { struct basic_test_data *data = ptr; struct event *r=NULL, *w=NULL, *t=NULL; struct timeval tv, now, tv2; tv.tv_sec = 0; tv.tv_usec = 500 * 1000; r = event_new(data->base, data->pair[0], EV_READ, simple_read_cb, NULL); w = event_new(data->base, data->pair[1], EV_WRITE, simple_write_cb, NULL); t = evtimer_new(data->base, timeout_cb, NULL); tt_assert(r); tt_assert(w); tt_assert(t); evutil_gettimeofday(&now, NULL); event_add(r, NULL); event_add(t, &tv); tt_assert( event_pending(r, EV_READ, NULL)); tt_assert(!event_pending(w, EV_WRITE, NULL)); tt_assert(!event_pending(r, EV_WRITE, NULL)); tt_assert( event_pending(r, EV_READ|EV_WRITE, NULL)); tt_assert(!event_pending(r, EV_TIMEOUT, NULL)); tt_assert( event_pending(t, EV_TIMEOUT, NULL)); tt_assert( event_pending(t, EV_TIMEOUT, &tv2)); tt_assert(evutil_timercmp(&tv2, &now, >)); test_timeval_diff_eq(&now, &tv2, 500); end: if (r) { event_del(r); event_free(r); } if (w) { event_del(w); event_free(w); } if (t) { event_del(t); event_free(t); } } static void dfd_cb(evutil_socket_t fd, short e, void *data) { *(int*)data = (int)e; } static void test_event_closed_fd_poll(void *arg) { struct timeval tv; struct event *e; struct basic_test_data *data = (struct basic_test_data *)arg; int i = 0; if (strcmp(event_base_get_method(data->base), "poll")) { tinytest_set_test_skipped_(); return; } e = event_new(data->base, data->pair[0], EV_READ, dfd_cb, &i); tt_assert(e); tv.tv_sec = 0; tv.tv_usec = 500 * 1000; event_add(e, &tv); tt_assert(event_pending(e, EV_READ, NULL)); close(data->pair[0]); data->pair[0] = -1; /** avoids double-close */ event_base_loop(data->base, EVLOOP_ONCE); tt_int_op(i, ==, EV_READ); end: if (e) { event_del(e); event_free(e); } } #ifndef _WIN32 /* You can't do this test on windows, since dup2 doesn't work on sockets */ /* Regression test for our workaround for a fun epoll/linux related bug * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2) * will get you an EEXIST */ static void test_dup_fd(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *ev1=NULL, *ev2=NULL; int fd, dfd=-1; int ev1_got, ev2_got; tt_int_op(write(data->pair[0], "Hello world", strlen("Hello world")), >, 0); fd = data->pair[1]; dfd = dup(fd); tt_int_op(dfd, >=, 0); ev1 = event_new(base, fd, EV_READ|EV_PERSIST, dfd_cb, &ev1_got); ev2 = event_new(base, dfd, EV_READ|EV_PERSIST, dfd_cb, &ev2_got); ev1_got = ev2_got = 0; event_add(ev1, NULL); event_add(ev2, NULL); event_base_loop(base, EVLOOP_ONCE); tt_int_op(ev1_got, ==, EV_READ); tt_int_op(ev2_got, ==, EV_READ); /* Now close and delete dfd then dispatch. We need to do the * dispatch here so that when we add it later, we think there * was an intermediate delete. */ close(dfd); event_del(ev2); ev1_got = ev2_got = 0; event_base_loop(base, EVLOOP_ONCE); tt_want_int_op(ev1_got, ==, EV_READ); tt_int_op(ev2_got, ==, 0); /* Re-duplicate the fd. We need to get the same duplicated * value that we closed to provoke the epoll quirk. Also, we * need to change the events to write, or else the old lingering * read event will make the test pass whether the change was * successful or not. */ tt_int_op(dup2(fd, dfd), ==, dfd); event_free(ev2); ev2 = event_new(base, dfd, EV_WRITE|EV_PERSIST, dfd_cb, &ev2_got); event_add(ev2, NULL); ev1_got = ev2_got = 0; event_base_loop(base, EVLOOP_ONCE); tt_want_int_op(ev1_got, ==, EV_READ); tt_int_op(ev2_got, ==, EV_WRITE); end: if (ev1) event_free(ev1); if (ev2) event_free(ev2); if (dfd >= 0) close(dfd); } #endif #ifdef EVENT__DISABLE_MM_REPLACEMENT static void test_mm_functions(void *arg) { tinytest_set_test_skipped_(); } #else static int check_dummy_mem_ok(void *mem_) { char *mem = mem_; mem -= 16; return !memcmp(mem, "{[]}", 16); } static void * dummy_malloc(size_t len) { char *mem = malloc(len+16); memcpy(mem, "{[]}", 16); return mem+16; } static void * dummy_realloc(void *mem_, size_t len) { char *mem = mem_; if (!mem) return dummy_malloc(len); tt_want(check_dummy_mem_ok(mem_)); mem -= 16; mem = realloc(mem, len+16); return mem+16; } static void dummy_free(void *mem_) { char *mem = mem_; tt_want(check_dummy_mem_ok(mem_)); mem -= 16; free(mem); } static void test_mm_functions(void *arg) { struct event_base *b = NULL; struct event_config *cfg = NULL; event_set_mem_functions(dummy_malloc, dummy_realloc, dummy_free); cfg = event_config_new(); event_config_avoid_method(cfg, "Nonesuch"); b = event_base_new_with_config(cfg); tt_assert(b); tt_assert(check_dummy_mem_ok(b)); end: if (cfg) event_config_free(cfg); if (b) event_base_free(b); } #endif static void many_event_cb(evutil_socket_t fd, short event, void *arg) { int *calledp = arg; *calledp += 1; } static void test_many_events(void *arg) { /* Try 70 events that should all be ready at once. This will * exercise the "resize" code on most of the backends, and will make * sure that we can get past the 64-handle limit of some windows * functions. */ #define MANY 70 struct basic_test_data *data = arg; struct event_base *base = data->base; int one_at_a_time = data->setup_data != NULL; evutil_socket_t sock[MANY]; struct event *ev[MANY]; int called[MANY]; int i; int loopflags = EVLOOP_NONBLOCK, evflags=0; if (one_at_a_time) { loopflags |= EVLOOP_ONCE; evflags = EV_PERSIST; } memset(sock, 0xff, sizeof(sock)); memset(ev, 0, sizeof(ev)); memset(called, 0, sizeof(called)); for (i = 0; i < MANY; ++i) { /* We need an event that will hit the backend, and that will * be ready immediately. "Send a datagram" is an easy * instance of that. */ sock[i] = socket(AF_INET, SOCK_DGRAM, 0); tt_assert(sock[i] >= 0); tt_assert(!evutil_make_socket_nonblocking(sock[i])); called[i] = 0; ev[i] = event_new(base, sock[i], EV_WRITE|evflags, many_event_cb, &called[i]); event_add(ev[i], NULL); if (one_at_a_time) event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); } event_base_loop(base, loopflags); for (i = 0; i < MANY; ++i) { if (one_at_a_time) tt_int_op(called[i], ==, MANY - i + 1); else tt_int_op(called[i], ==, 1); } end: for (i = 0; i < MANY; ++i) { if (ev[i]) event_free(ev[i]); if (sock[i] >= 0) evutil_closesocket(sock[i]); } #undef MANY } static void test_struct_event_size(void *arg) { tt_int_op(event_get_struct_event_size(), <=, sizeof(struct event)); end: ; } static void test_get_assignment(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *ev1 = NULL; const char *str = "foo"; struct event_base *b; evutil_socket_t s; short what; event_callback_fn cb; void *cb_arg; ev1 = event_new(base, data->pair[1], EV_READ, dummy_read_cb, (void*)str); event_get_assignment(ev1, &b, &s, &what, &cb, &cb_arg); tt_ptr_op(b, ==, base); tt_fd_op(s, ==, data->pair[1]); tt_int_op(what, ==, EV_READ); tt_ptr_op(cb, ==, dummy_read_cb); tt_ptr_op(cb_arg, ==, str); /* Now make sure this doesn't crash. */ event_get_assignment(ev1, NULL, NULL, NULL, NULL, NULL); end: if (ev1) event_free(ev1); } struct foreach_helper { int count; const struct event *ev; }; static int foreach_count_cb(const struct event_base *base, const struct event *ev, void *arg) { struct foreach_helper *h = event_get_callback_arg(ev); struct timeval *tv = arg; if (event_get_callback(ev) != timeout_cb) return 0; tt_ptr_op(event_get_base(ev), ==, base); tt_int_op(tv->tv_sec, ==, 10); h->ev = ev; h->count++; return 0; end: return -1; } static int foreach_find_cb(const struct event_base *base, const struct event *ev, void *arg) { const struct event **ev_out = arg; struct foreach_helper *h = event_get_callback_arg(ev); if (event_get_callback(ev) != timeout_cb) return 0; if (h->count == 99) { *ev_out = ev; return 101; } return 0; } static void test_event_foreach(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *ev[5]; struct foreach_helper visited[5]; int i; struct timeval ten_sec = {10,0}; const struct event *ev_found = NULL; for (i = 0; i < 5; ++i) { visited[i].count = 0; visited[i].ev = NULL; ev[i] = event_new(base, -1, 0, timeout_cb, &visited[i]); } tt_int_op(-1, ==, event_base_foreach_event(NULL, foreach_count_cb, NULL)); tt_int_op(-1, ==, event_base_foreach_event(base, NULL, NULL)); event_add(ev[0], &ten_sec); event_add(ev[1], &ten_sec); event_active(ev[1], EV_TIMEOUT, 1); event_active(ev[2], EV_TIMEOUT, 1); event_add(ev[3], &ten_sec); /* Don't touch ev[4]. */ tt_int_op(0, ==, event_base_foreach_event(base, foreach_count_cb, &ten_sec)); tt_int_op(1, ==, visited[0].count); tt_int_op(1, ==, visited[1].count); tt_int_op(1, ==, visited[2].count); tt_int_op(1, ==, visited[3].count); tt_ptr_op(ev[0], ==, visited[0].ev); tt_ptr_op(ev[1], ==, visited[1].ev); tt_ptr_op(ev[2], ==, visited[2].ev); tt_ptr_op(ev[3], ==, visited[3].ev); visited[2].count = 99; tt_int_op(101, ==, event_base_foreach_event(base, foreach_find_cb, &ev_found)); tt_ptr_op(ev_found, ==, ev[2]); end: for (i=0; i<5; ++i) { event_free(ev[i]); } } static struct event_base *cached_time_base = NULL; static int cached_time_reset = 0; static int cached_time_sleep = 0; static void cache_time_cb(evutil_socket_t fd, short what, void *arg) { struct timeval *tv = arg; tt_int_op(0, ==, event_base_gettimeofday_cached(cached_time_base, tv)); if (cached_time_sleep) { struct timeval delay = { 0, 30*1000 }; evutil_usleep_(&delay); } if (cached_time_reset) { event_base_update_cache_time(cached_time_base); } end: ; } static void test_gettimeofday_cached(void *arg) { struct basic_test_data *data = arg; struct event_config *cfg = NULL; struct event_base *base = NULL; struct timeval tv1, tv2, tv3, now; struct event *ev1=NULL, *ev2=NULL, *ev3=NULL; int cached_time_disable = strstr(data->setup_data, "disable") != NULL; cfg = event_config_new(); if (cached_time_disable) { event_config_set_flag(cfg, EVENT_BASE_FLAG_NO_CACHE_TIME); } cached_time_base = base = event_base_new_with_config(cfg); tt_assert(base); /* Try gettimeofday_cached outside of an event loop. */ evutil_gettimeofday(&now, NULL); tt_int_op(0, ==, event_base_gettimeofday_cached(NULL, &tv1)); tt_int_op(0, ==, event_base_gettimeofday_cached(base, &tv2)); tt_int_op(timeval_msec_diff(&tv1, &tv2), <, 10); tt_int_op(timeval_msec_diff(&tv1, &now), <, 10); cached_time_reset = strstr(data->setup_data, "reset") != NULL; cached_time_sleep = strstr(data->setup_data, "sleep") != NULL; ev1 = event_new(base, -1, 0, cache_time_cb, &tv1); ev2 = event_new(base, -1, 0, cache_time_cb, &tv2); ev3 = event_new(base, -1, 0, cache_time_cb, &tv3); event_active(ev1, EV_TIMEOUT, 1); event_active(ev2, EV_TIMEOUT, 1); event_active(ev3, EV_TIMEOUT, 1); event_base_dispatch(base); if (cached_time_reset && cached_time_sleep) { tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10); tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10); } else if (cached_time_disable && cached_time_sleep) { tt_int_op(labs(timeval_msec_diff(&tv1,&tv2)), >, 10); tt_int_op(labs(timeval_msec_diff(&tv2,&tv3)), >, 10); } else if (! cached_time_disable) { tt_assert(evutil_timercmp(&tv1, &tv2, ==)); tt_assert(evutil_timercmp(&tv2, &tv3, ==)); } end: if (ev1) event_free(ev1); if (ev2) event_free(ev2); if (ev3) event_free(ev3); if (base) event_base_free(base); if (cfg) event_config_free(cfg); } static void tabf_cb(evutil_socket_t fd, short what, void *arg) { int *ptr = arg; *ptr = what; *ptr += 0x10000; } static void test_evmap_invalid_slots(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *ev1 = NULL, *ev2 = NULL; int e1, e2; #ifndef _WIN32 struct event *ev3 = NULL, *ev4 = NULL; int e3, e4; #endif ev1 = evsignal_new(base, -1, dummy_read_cb, (void *)base); ev2 = evsignal_new(base, NSIG, dummy_read_cb, (void *)base); tt_assert(ev1); tt_assert(ev2); e1 = event_add(ev1, NULL); e2 = event_add(ev2, NULL); tt_int_op(e1, !=, 0); tt_int_op(e2, !=, 0); #ifndef _WIN32 ev3 = event_new(base, INT_MAX, EV_READ, dummy_read_cb, (void *)base); ev4 = event_new(base, INT_MAX / 2, EV_READ, dummy_read_cb, (void *)base); tt_assert(ev3); tt_assert(ev4); e3 = event_add(ev3, NULL); e4 = event_add(ev4, NULL); tt_int_op(e3, !=, 0); tt_int_op(e4, !=, 0); #endif end: event_free(ev1); event_free(ev2); #ifndef _WIN32 event_free(ev3); event_free(ev4); #endif } static void test_active_by_fd(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *ev1 = NULL, *ev2 = NULL, *ev3 = NULL, *ev4 = NULL; int e1,e2,e3,e4; #ifndef _WIN32 struct event *evsig = NULL; int es; #endif struct timeval tenmin = { 600, 0 }; /* Ensure no crash on nonexistent FD. */ event_base_active_by_fd(base, 1000, EV_READ); /* Ensure no crash on bogus FD. */ event_base_active_by_fd(base, -1, EV_READ); /* Ensure no crash on nonexistent/bogus signal. */ event_base_active_by_signal(base, 1000); event_base_active_by_signal(base, -1); event_base_assert_ok_(base); e1 = e2 = e3 = e4 = 0; ev1 = event_new(base, data->pair[0], EV_READ, tabf_cb, &e1); ev2 = event_new(base, data->pair[0], EV_WRITE, tabf_cb, &e2); ev3 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e3); ev4 = event_new(base, data->pair[1], EV_READ, tabf_cb, &e4); tt_assert(ev1); tt_assert(ev2); tt_assert(ev3); tt_assert(ev4); #ifndef _WIN32 evsig = event_new(base, SIGHUP, EV_SIGNAL, tabf_cb, &es); tt_assert(evsig); event_add(evsig, &tenmin); #endif event_add(ev1, &tenmin); event_add(ev2, NULL); event_add(ev3, NULL); event_add(ev4, &tenmin); event_base_assert_ok_(base); /* Trigger 2, 3, 4 */ event_base_active_by_fd(base, data->pair[0], EV_WRITE); event_base_active_by_fd(base, data->pair[1], EV_READ); event_base_active_by_fd(base, data->pair[1], EV_TIMEOUT); #ifndef _WIN32 event_base_active_by_signal(base, SIGHUP); #endif event_base_assert_ok_(base); event_base_loop(base, EVLOOP_ONCE); tt_int_op(e1, ==, 0); tt_int_op(e2, ==, EV_WRITE | 0x10000); tt_int_op(e3, ==, EV_READ | 0x10000); /* Mask out EV_WRITE here, since it could be genuinely writeable. */ tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | EV_TIMEOUT | 0x10000); #ifndef _WIN32 tt_int_op(es, ==, EV_SIGNAL | 0x10000); #endif end: if (ev1) event_free(ev1); if (ev2) event_free(ev2); if (ev3) event_free(ev3); if (ev4) event_free(ev4); #ifndef _WIN32 if (evsig) event_free(evsig); #endif } struct testcase_t main_testcases[] = { /* Some converted-over tests */ { "methods", test_methods, TT_FORK, NULL, NULL }, { "version", test_version, 0, NULL, NULL }, BASIC(base_features, TT_FORK|TT_NO_LOGS), { "base_environ", test_base_environ, TT_FORK, NULL, NULL }, BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR), BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR), BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE), BASIC(event_new_selfarg, TT_FORK|TT_NEED_BASE), BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE), BASIC(evmap_invalid_slots, TT_FORK|TT_NEED_BASE), BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_RETRIABLE), BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), /* These are still using the old API */ LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE), { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "persistent_active_timeout", test_persistent_active_timeout, TT_FORK|TT_NEED_BASE|TT_RETRIABLE, &basic_setup, NULL }, LEGACY(priorities, TT_FORK|TT_NEED_BASE), BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE), { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, /* These legacy tests may not all need all of these flags. */ LEGACY(simpleread, TT_ISOLATED), LEGACY(simpleread_multiple, TT_ISOLATED), LEGACY(simplewrite, TT_ISOLATED), { "simpleclose_rw", test_simpleclose_rw, TT_FORK, &basic_setup, NULL }, /* simpleclose */ { "simpleclose_close", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"close" }, { "simpleclose_shutdown", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"shutdown" }, /* simpleclose_*_persist */ { "simpleclose_close_persist", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"close_persist" }, { "simpleclose_shutdown_persist", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"shutdown_persist" }, /* simpleclose_*_et */ { "simpleclose_close_et", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"close_ET" }, { "simpleclose_shutdown_et", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"shutdown_ET" }, /* simpleclose_*_persist_et */ { "simpleclose_close_persist_et", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"close_persist_ET" }, { "simpleclose_shutdown_persist_et", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"shutdown_persist_ET" }, LEGACY(multiple, TT_ISOLATED), LEGACY(persistent, TT_ISOLATED), LEGACY(combined, TT_ISOLATED), LEGACY(simpletimeout, TT_ISOLATED), LEGACY(loopbreak, TT_ISOLATED), LEGACY(loopexit, TT_ISOLATED), LEGACY(loopexit_multiple, TT_ISOLATED), { "nonpersist_readd", test_nonpersist_readd, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, NULL }, LEGACY(multiple_events_for_same_fd, TT_ISOLATED), LEGACY(want_only_once, TT_ISOLATED), { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL }, { "event_once_never", test_event_once_never, TT_ISOLATED, &basic_setup, NULL }, { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup, NULL }, { "event_closed_fd_poll", test_event_closed_fd_poll, TT_ISOLATED, &basic_setup, NULL }, #ifndef _WIN32 { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL }, #endif { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL }, { "many_events", test_many_events, TT_ISOLATED, &basic_setup, NULL }, { "many_events_slow_add", test_many_events, TT_ISOLATED, &basic_setup, (void*)1 }, { "struct_event_size", test_struct_event_size, 0, NULL, NULL }, BASIC(get_assignment, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), BASIC(event_foreach, TT_FORK|TT_NEED_BASE), { "gettimeofday_cached", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"" }, { "gettimeofday_cached_sleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep" }, { "gettimeofday_cached_reset", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep reset" }, { "gettimeofday_cached_disabled", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"sleep disable" }, { "gettimeofday_cached_disabled_nosleep", test_gettimeofday_cached, TT_FORK, &basic_setup, (void*)"disable" }, BASIC(active_by_fd, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), #ifndef _WIN32 LEGACY(fork, TT_ISOLATED), #endif #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS|TT_RETRIABLE), LEGACY(del_notify, TT_ISOLATED|TT_NEED_THREADS), #endif END_OF_TESTCASES }; struct testcase_t evtag_testcases[] = { { "int", evtag_int_test, TT_FORK, NULL, NULL }, { "fuzz", evtag_fuzz, TT_FORK, NULL, NULL }, { "encoding", evtag_tag_encoding, TT_FORK, NULL, NULL }, { "peek", evtag_test_peek, 0, NULL, NULL }, END_OF_TESTCASES }; struct testcase_t signal_testcases[] = { #ifndef _WIN32 LEGACY(simplestsignal, TT_ISOLATED), LEGACY(simplesignal, TT_ISOLATED), LEGACY(multiplesignal, TT_ISOLATED), LEGACY(immediatesignal, TT_ISOLATED), LEGACY(signal_dealloc, TT_ISOLATED), LEGACY(signal_pipeloss, TT_ISOLATED), LEGACY(signal_switchbase, TT_ISOLATED|TT_NO_LOGS), LEGACY(signal_restore, TT_ISOLATED), LEGACY(signal_assert, TT_ISOLATED), LEGACY(signal_while_processing, TT_ISOLATED), #endif END_OF_TESTCASES }; lldpd-1.0.13/libevent/test/regress_ssl.c0000644000076400001440000007467214111362571020700 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Get rid of OSX 10.7 and greater deprecation warnings. #if defined(__APPLE__) && defined(__clang__) #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif #ifdef _WIN32 #include #include #endif #include "util-internal.h" #ifndef _WIN32 #include #include #include #endif #include "event2/util.h" #include "event2/event.h" #include "event2/bufferevent_ssl.h" #include "event2/bufferevent_struct.h" #include "event2/buffer.h" #include "event2/listener.h" #include "regress.h" #include "tinytest.h" #include "tinytest_macros.h" #include #include #include "openssl-compat.h" #include #ifdef _WIN32 #include #define read _read #define write _write #else #include #endif /* A pre-generated key, to save the cost of doing an RSA key generation step * during the unit tests. It is published in this file, so you would have to * be very foolish to consider using it in your own code. */ static const char KEY[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIIEogIBAAKCAQEAtK07Ili0dkJb79m/sFmHoVJTWyLoveXex2yX/BtUzzcvZEOu\n" "QLon/++5YOA48kzZm5K9mIwZkZhui1ZgJ5Bjq0LGAWTZGIn+NXjLFshPYvTKpOCW\n" "uzL0Ir0LXMsBLYJQ5A4FomLNxs4I3H/dhDSGy/rSiJB1B4w2xNiwPK08/VL3zZqk\n" "V+GsSvGIIkzhTMbqPJy9K8pqyjwOU2pgORS794yXciTGxWYjTDzJPgQ35YMDATaG\n" "jr4HHo1zxU/Lj0pndSUK5rKLYxYQ3Uc8B3AVYDl9CP/GbOoQ4LBzS68JjcAUyp6i\n" "6NfXlc2D9S9XgqVqwI+JqgJs0eW/+zPY2UEDWwIDAQABAoIBAD2HzV66FOM9YDAD\n" "2RtGskEHV2nvLpIVadRCsFPkPvK+2X3s6rgSbbLkwh4y3lHuSCGKTNVZyQ9jeSos\n" "xVxT+Q2HFQW+gYyw2gj91TQyDY8mzKhv8AVaqff2p5r3a7RC8CdqexK9UVUGL9Bg\n" "H2F5vfpTtkVZ5PEoGDLblNFlMiMW/t1SobUeBVx+Msco/xqk9lFv1A9nnepGy0Gi\n" "D+i6YNGTBsX22YhoCZl/ICxCL8lgqPei4FvBr9dBVh/jQgjuUBm2jz55p2r7+7Aw\n" "khmXHReejoVokQ2+htgSgZNKlKuDy710ZpBqnDi8ynQi82Y2qCpyg/p/xcER54B6\n" "hSftaiECgYEA2RkSoxU+nWk+BClQEUZRi88QK5W/M8oo1DvUs36hvPFkw3Jk/gz0\n" "fgd5bnA+MXj0Fc0QHvbddPjIkyoI/evq9GPV+JYIuH5zabrlI3Jvya8q9QpAcEDO\n" "KkL/O09qXVEW52S6l05nh4PLejyI7aTyTIN5nbVLac/+M8MY/qOjZksCgYEA1Q1o\n" "L8kjSavU2xhQmSgZb9W62Do60sa3e73ljrDPoiyvbExldpSdziFYxHBD/Rep0ePf\n" "eVSGS3VSwevt9/jSGo2Oa83TYYns9agBm03oR/Go/DukESdI792NsEM+PRFypVNy\n" "AohWRLj0UU6DV+zLKp0VBavtx0ATeLFX0eN17TECgYBI2O/3Bz7uhQ0JSm+SjFz6\n" "o+2SInp5P2G57aWu4VQWWY3tQ2p+EQzNaWam10UXRrXoxtmc+ktPX9e2AgnoYoyB\n" "myqGcpnUhqHlnZAb999o9r1cYidDQ4uqhLauSTSwwXAFDzjJYsa8o03Y440y6QFh\n" "CVD6yYXXqLJs3g96CqDexwKBgAHxq1+0QCQt8zVElYewO/svQhMzBNJjic0RQIT6\n" "zAo4yij80XgxhvcYiszQEW6/xobpw2JCCS+rFGQ8mOFIXfJsFD6blDAxp/3d2JXo\n" "MhRl+hrDGI4ng5zcsqxHEMxR2m/zwPiQ8eiSn3gWdVBaEsiCwmxY00ScKxFQ3PJH\n" "Vw4hAoGAdZLd8KfjjG6lg7hfpVqavstqVi9LOgkHeCfdjn7JP+76kYrgLk/XdkrP\n" "N/BHhtFVFjOi/mTQfQ5YfZImkm/1ePBy7437DT8BDkOxspa50kK4HPggHnU64h1w\n" "lhdEOj7mAgHwGwwVZWOgs9Lq6vfztnSuhqjha1daESY6kDscPIQ=\n" "-----END RSA PRIVATE KEY-----\n"; EVP_PKEY * ssl_getkey(void) { EVP_PKEY *key; BIO *bio; /* new read-only BIO backed by KEY. */ bio = BIO_new_mem_buf((char*)KEY, -1); tt_assert(bio); key = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL); BIO_free(bio); tt_assert(key); return key; end: return NULL; } X509 * ssl_getcert(EVP_PKEY *key) { /* Dummy code to make a quick-and-dirty valid certificate with OpenSSL. Don't copy this code into your own program! It does a number of things in a stupid and insecure way. */ X509 *x509 = NULL; X509_NAME *name = NULL; int nid; time_t now = time(NULL); tt_assert(key); x509 = X509_new(); tt_assert(x509); tt_assert(0 != X509_set_version(x509, 2)); tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)now)); name = X509_NAME_new(); tt_assert(name); nid = OBJ_txt2nid("commonName"); tt_assert(NID_undef != nid); tt_assert(0 != X509_NAME_add_entry_by_NID( name, nid, MBSTRING_ASC, (unsigned char*)"example.com", -1, -1, 0)); X509_set_subject_name(x509, name); X509_set_issuer_name(x509, name); X509_NAME_free(name); X509_time_adj(X509_getm_notBefore(x509), 0, &now); now += 3600; X509_time_adj(X509_getm_notAfter(x509), 0, &now); X509_set_pubkey(x509, key); tt_assert(0 != X509_sign(x509, key, EVP_sha1())); return x509; end: X509_free(x509); X509_NAME_free(name); return NULL; } static int disable_tls_11_and_12 = 0; static SSL_CTX *the_ssl_ctx = NULL; SSL_CTX * get_ssl_ctx(void) { if (the_ssl_ctx) return the_ssl_ctx; the_ssl_ctx = SSL_CTX_new(SSLv23_method()); if (!the_ssl_ctx) return NULL; if (disable_tls_11_and_12) { #ifdef SSL_OP_NO_TLSv1_2 SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_2); #endif #ifdef SSL_OP_NO_TLSv1_1 SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_1); #endif } return the_ssl_ctx; } static int test_is_done; static int n_connected; static int got_close; static int got_error; static int got_timeout; static int renegotiate_at = -1; static int stop_when_connected; static int pending_connect_events; static struct event_base *exit_base; static X509 *the_cert; EVP_PKEY *the_key; void init_ssl(void) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) SSL_library_init(); ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); if (SSLeay() != OPENSSL_VERSION_NUMBER) { TT_DECLARE("WARN", ("Version mismatch for openssl: compiled with %lx but running with %lx", (unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long)SSLeay())); } #endif } static void * ssl_test_setup(const struct testcase_t *testcase) { init_ssl(); the_key = ssl_getkey(); EVUTIL_ASSERT(the_key); the_cert = ssl_getcert(the_key); EVUTIL_ASSERT(the_cert); disable_tls_11_and_12 = 0; return basic_test_setup(testcase); } static int ssl_test_cleanup(const struct testcase_t *testcase, void *ptr) { int ret = basic_test_cleanup(testcase, ptr); if (!ret) { return ret; } test_is_done = 0; n_connected = 0; got_close = 0; got_error = 0; got_timeout = 0; renegotiate_at = -1; stop_when_connected = 0; pending_connect_events = 0; exit_base = NULL; X509_free(the_cert); EVP_PKEY_free(the_key); SSL_CTX_free(the_ssl_ctx); the_ssl_ctx = NULL; return 1; } const struct testcase_setup_t ssl_setup = { ssl_test_setup, ssl_test_cleanup }; /* ==================== Here's a simple test: we read a number from the input, increment it, and reply, until we get to 1001. */ enum regress_openssl_type { REGRESS_OPENSSL_SOCKETPAIR = 1, REGRESS_OPENSSL_FILTER = 2, REGRESS_OPENSSL_RENEGOTIATE = 4, REGRESS_OPENSSL_OPEN = 8, REGRESS_OPENSSL_DIRTY_SHUTDOWN = 16, REGRESS_OPENSSL_FD = 32, REGRESS_OPENSSL_CLIENT = 64, REGRESS_OPENSSL_SERVER = 128, REGRESS_OPENSSL_FREED = 256, REGRESS_OPENSSL_TIMEOUT = 512, REGRESS_OPENSSL_SLEEP = 1024, REGRESS_OPENSSL_CLIENT_WRITE = 2048, REGRESS_DEFERRED_CALLBACKS = 4096, }; static void bufferevent_openssl_check_fd(struct bufferevent *bev, int filter) { tt_fd_op(bufferevent_getfd(bev), !=, EVUTIL_INVALID_SOCKET); tt_fd_op(bufferevent_setfd(bev, EVUTIL_INVALID_SOCKET), ==, 0); if (filter) { tt_fd_op(bufferevent_getfd(bev), !=, EVUTIL_INVALID_SOCKET); } else { tt_fd_op(bufferevent_getfd(bev), ==, EVUTIL_INVALID_SOCKET); } end: ; } static void bufferevent_openssl_check_freed(struct bufferevent *bev) { tt_int_op(event_pending(&bev->ev_read, EVLIST_ALL, NULL), ==, 0); tt_int_op(event_pending(&bev->ev_write, EVLIST_ALL, NULL), ==, 0); end: ; } static void free_on_cb(struct bufferevent *bev, void *ctx) { TT_BLATHER(("free_on_cb: %p", bev)); bufferevent_free(bev); } static void respond_to_number(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_input(bev); char *line; int n; enum regress_openssl_type type; type = (enum regress_openssl_type)ctx; line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); if (! line) return; n = atoi(line); if (n <= 0) TT_FAIL(("Bad number: %s", line)); free(line); TT_BLATHER(("The number was %d", n)); if (n == 1001) { ++test_is_done; bufferevent_free(bev); /* Should trigger close on other side. */ return; } if ((type & REGRESS_OPENSSL_CLIENT) && n == renegotiate_at) { SSL_renegotiate(bufferevent_openssl_get_ssl(bev)); } ++n; evbuffer_add_printf(bufferevent_get_output(bev), "%d\n", n); TT_BLATHER(("Done reading; now writing.")); bufferevent_enable(bev, EV_WRITE); bufferevent_disable(bev, EV_READ); } static void done_writing_cb(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_output(bev); if (evbuffer_get_length(b)) return; TT_BLATHER(("Done writing.")); bufferevent_disable(bev, EV_WRITE); bufferevent_enable(bev, EV_READ); } static void eventcb(struct bufferevent *bev, short what, void *ctx) { X509 *peer_cert = NULL; enum regress_openssl_type type; type = (enum regress_openssl_type)ctx; TT_BLATHER(("Got event %d", (int)what)); if (what & BEV_EVENT_CONNECTED) { SSL *ssl; ++n_connected; ssl = bufferevent_openssl_get_ssl(bev); tt_assert(ssl); peer_cert = SSL_get_peer_certificate(ssl); if (type & REGRESS_OPENSSL_SERVER) { tt_assert(peer_cert == NULL); } else { tt_assert(peer_cert != NULL); } if (stop_when_connected) { if (--pending_connect_events == 0) event_base_loopexit(exit_base, NULL); } if ((type & REGRESS_OPENSSL_CLIENT_WRITE) && (type & REGRESS_OPENSSL_CLIENT)) evbuffer_add_printf(bufferevent_get_output(bev), "1\n"); } else if (what & BEV_EVENT_EOF) { TT_BLATHER(("Got a good EOF")); ++got_close; if (type & REGRESS_OPENSSL_FD) { bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); } if (type & REGRESS_OPENSSL_FREED) { bufferevent_openssl_check_freed(bev); } bufferevent_free(bev); } else if (what & BEV_EVENT_ERROR) { TT_BLATHER(("Got an error.")); ++got_error; if (type & REGRESS_OPENSSL_FD) { bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); } if (type & REGRESS_OPENSSL_FREED) { bufferevent_openssl_check_freed(bev); } bufferevent_free(bev); } else if (what & BEV_EVENT_TIMEOUT) { TT_BLATHER(("Got timeout.")); ++got_timeout; if (type & REGRESS_OPENSSL_FD) { bufferevent_openssl_check_fd(bev, type & REGRESS_OPENSSL_FILTER); } if (type & REGRESS_OPENSSL_FREED) { bufferevent_openssl_check_freed(bev); } bufferevent_free(bev); } end: if (peer_cert) X509_free(peer_cert); } static void open_ssl_bufevs(struct bufferevent **bev1_out, struct bufferevent **bev2_out, struct event_base *base, int is_open, int flags, SSL *ssl1, SSL *ssl2, evutil_socket_t *fd_pair, struct bufferevent **underlying_pair, enum regress_openssl_type type) { int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING; int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; int dirty_shutdown = type & REGRESS_OPENSSL_DIRTY_SHUTDOWN; if (fd_pair) { *bev1_out = bufferevent_openssl_socket_new( base, fd_pair[0], ssl1, state1, flags); *bev2_out = bufferevent_openssl_socket_new( base, fd_pair[1], ssl2, state2, flags); } else { *bev1_out = bufferevent_openssl_filter_new( base, underlying_pair[0], ssl1, state1, flags); *bev2_out = bufferevent_openssl_filter_new( base, underlying_pair[1], ssl2, state2, flags); } bufferevent_setcb(*bev1_out, respond_to_number, done_writing_cb, eventcb, (void*)(REGRESS_OPENSSL_CLIENT | (long)type)); bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb, eventcb, (void*)(REGRESS_OPENSSL_SERVER | (long)type)); bufferevent_openssl_set_allow_dirty_shutdown(*bev1_out, dirty_shutdown); bufferevent_openssl_set_allow_dirty_shutdown(*bev2_out, dirty_shutdown); } static void regress_bufferevent_openssl(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev1, *bev2; SSL *ssl1, *ssl2; int flags = BEV_OPT_DEFER_CALLBACKS; struct bufferevent *bev_ll[2] = { NULL, NULL }; evutil_socket_t *fd_pair = NULL; enum regress_openssl_type type; type = (enum regress_openssl_type)data->setup_data; if (type & REGRESS_OPENSSL_RENEGOTIATE) { if (OPENSSL_VERSION_NUMBER >= 0x10001000 && OPENSSL_VERSION_NUMBER < 0x1000104f) { /* 1.0.1 up to 1.0.1c has a bug where TLS1.1 and 1.2 * can't renegotiate with themselves. Disable. */ disable_tls_11_and_12 = 1; } renegotiate_at = 600; } ssl1 = SSL_new(get_ssl_ctx()); ssl2 = SSL_new(get_ssl_ctx()); SSL_use_certificate(ssl2, the_cert); SSL_use_PrivateKey(ssl2, the_key); if (!(type & REGRESS_OPENSSL_OPEN)) flags |= BEV_OPT_CLOSE_ON_FREE; if (!(type & REGRESS_OPENSSL_FILTER)) { tt_assert(type & REGRESS_OPENSSL_SOCKETPAIR); fd_pair = data->pair; } else { bev_ll[0] = bufferevent_socket_new(data->base, data->pair[0], BEV_OPT_CLOSE_ON_FREE); bev_ll[1] = bufferevent_socket_new(data->base, data->pair[1], BEV_OPT_CLOSE_ON_FREE); } open_ssl_bufevs(&bev1, &bev2, data->base, 0, flags, ssl1, ssl2, fd_pair, bev_ll, type); if (!(type & REGRESS_OPENSSL_FILTER)) { tt_fd_op(bufferevent_getfd(bev1), ==, data->pair[0]); } else { tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]); } if (type & REGRESS_OPENSSL_OPEN) { pending_connect_events = 2; stop_when_connected = 1; exit_base = data->base; event_base_dispatch(data->base); /* Okay, now the renegotiation is done. Make new * bufferevents to test opening in BUFFEREVENT_SSL_OPEN */ flags |= BEV_OPT_CLOSE_ON_FREE; bufferevent_free(bev1); bufferevent_free(bev2); bev1 = bev2 = NULL; open_ssl_bufevs(&bev1, &bev2, data->base, 1, flags, ssl1, ssl2, fd_pair, bev_ll, type); } if (!(type & REGRESS_OPENSSL_TIMEOUT)) { bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_enable(bev2, EV_READ|EV_WRITE); if (!(type & REGRESS_OPENSSL_CLIENT_WRITE)) evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); event_base_dispatch(data->base); tt_assert(test_is_done == 1); tt_assert(n_connected == 2); /* We don't handle shutdown properly yet */ if (type & REGRESS_OPENSSL_DIRTY_SHUTDOWN) { tt_int_op(got_close, ==, 1); tt_int_op(got_error, ==, 0); } else { tt_int_op(got_error, ==, 1); } tt_int_op(got_timeout, ==, 0); } else { struct timeval t = { 2, 0 }; bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_disable(bev2, EV_READ|EV_WRITE); bufferevent_set_timeouts(bev1, &t, &t); if (!(type & REGRESS_OPENSSL_CLIENT_WRITE)) evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); event_base_dispatch(data->base); tt_assert(test_is_done == 0); tt_assert(n_connected == 0); tt_int_op(got_close, ==, 0); tt_int_op(got_error, ==, 0); tt_int_op(got_timeout, ==, 1); bufferevent_free(bev2); } end: return; } static void acceptcb_deferred(evutil_socket_t fd, short events, void *arg) { struct bufferevent *bev = arg; bufferevent_enable(bev, EV_READ|EV_WRITE); } static void acceptcb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev; enum regress_openssl_type type; SSL *ssl = SSL_new(get_ssl_ctx()); type = (enum regress_openssl_type)data->setup_data; SSL_use_certificate(ssl, the_cert); SSL_use_PrivateKey(ssl, the_key); bev = bufferevent_openssl_socket_new( data->base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); tt_assert(bev); bufferevent_setcb(bev, respond_to_number, NULL, eventcb, (void*)(REGRESS_OPENSSL_SERVER)); if (type & REGRESS_OPENSSL_SLEEP) { struct timeval when = { 1, 0 }; event_base_once(data->base, -1, EV_TIMEOUT, acceptcb_deferred, bev, &when); bufferevent_disable(bev, EV_READ|EV_WRITE); } else { bufferevent_enable(bev, EV_READ|EV_WRITE); } /* Only accept once, then disable ourself. */ evconnlistener_disable(listener); end: ; } struct rwcount { evutil_socket_t fd; size_t read; size_t write; }; static int bio_rwcount_new(BIO *b) { BIO_set_init(b, 0); BIO_set_data(b, NULL); return 1; } static int bio_rwcount_free(BIO *b) { TT_BLATHER(("bio_rwcount_free: %p", b)); if (!b) return 0; if (BIO_get_shutdown(b)) { BIO_set_init(b, 0); BIO_set_data(b, NULL); } return 1; } static int bio_rwcount_read(BIO *b, char *out, int outlen) { struct rwcount *rw = BIO_get_data(b); ev_ssize_t ret = recv(rw->fd, out, outlen, 0); ++rw->read; if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) { BIO_set_retry_read(b); } return ret; } static int bio_rwcount_write(BIO *b, const char *in, int inlen) { struct rwcount *rw = BIO_get_data(b); ev_ssize_t ret = send(rw->fd, in, inlen, 0); ++rw->write; if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) { BIO_set_retry_write(b); } return ret; } static long bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr) { struct rwcount *rw = BIO_get_data(b); long ret = 0; switch (cmd) { case BIO_C_GET_FD: ret = rw->fd; break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_PENDING: ret = 0; break; case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; } return ret; } static int bio_rwcount_puts(BIO *b, const char *s) { return bio_rwcount_write(b, s, strlen(s)); } #define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1 static BIO_METHOD *methods_rwcount; static BIO_METHOD * BIO_s_rwcount(void) { if (methods_rwcount == NULL) { methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount"); if (methods_rwcount == NULL) return NULL; BIO_meth_set_write(methods_rwcount, bio_rwcount_write); BIO_meth_set_read(methods_rwcount, bio_rwcount_read); BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts); BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl); BIO_meth_set_create(methods_rwcount, bio_rwcount_new); BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free); } return methods_rwcount; } static BIO * BIO_new_rwcount(int close_flag) { BIO *result; if (!(result = BIO_new(BIO_s_rwcount()))) return NULL; BIO_set_init(result, 1); BIO_set_data(result, NULL); BIO_set_shutdown(result, !!close_flag); return result; } static void regress_bufferevent_openssl_connect(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener; struct bufferevent *bev; struct sockaddr_in sin; struct sockaddr_storage ss; ev_socklen_t slen; SSL *ssl; struct rwcount rw = { -1, 0, 0 }; enum regress_openssl_type type; type = (enum regress_openssl_type)data->setup_data; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); memset(&ss, 0, sizeof(ss)); slen = sizeof(ss); listener = evconnlistener_new_bind(base, acceptcb, data, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener); tt_assert(evconnlistener_get_fd(listener) >= 0); ssl = SSL_new(get_ssl_ctx()); tt_assert(ssl); bev = bufferevent_openssl_socket_new( data->base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); tt_assert(bev); bufferevent_setcb(bev, respond_to_number, free_on_cb, eventcb, (void*)(REGRESS_OPENSSL_CLIENT)); tt_assert(getsockname(evconnlistener_get_fd(listener), (struct sockaddr*)&ss, &slen) == 0); tt_assert(slen == sizeof(struct sockaddr_in)); tt_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET); tt_assert(0 == bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen)); /* Possible only when we have fd, since be_openssl can and will overwrite * bio otherwise before */ if (type & REGRESS_OPENSSL_SLEEP) { BIO *bio; rw.fd = bufferevent_getfd(bev); bio = BIO_new_rwcount(0); tt_assert(bio); BIO_set_data(bio, &rw); SSL_set_bio(ssl, bio, bio); } evbuffer_add_printf(bufferevent_get_output(bev), "1\n"); bufferevent_enable(bev, EV_READ|EV_WRITE); event_base_dispatch(base); tt_int_op(rw.read, <=, 100); tt_int_op(rw.write, <=, 100); end: evconnlistener_free(listener); } struct wm_context { int server; int flags; struct evbuffer *data; size_t to_read; size_t wm_high; size_t limit; size_t get; struct bufferevent *bev; struct wm_context *neighbour; }; static void wm_transfer(struct bufferevent *bev, void *arg) { struct wm_context *ctx = arg; struct evbuffer *in = bufferevent_get_input(bev); struct evbuffer *out = bufferevent_get_output(bev); size_t len = evbuffer_get_length(in); size_t drain = len < ctx->to_read ? len : ctx->to_read; if (ctx->get >= ctx->limit) { TT_BLATHER(("wm_transfer-%s(%p): break", ctx->server ? "server" : "client", bev)); bufferevent_setcb(bev, NULL, NULL, NULL, NULL); bufferevent_disable(bev, EV_READ); if (ctx->neighbour->get >= ctx->neighbour->limit) { event_base_loopbreak(bufferevent_get_base(bev)); } } else { ctx->get += drain; evbuffer_drain(in, drain); } TT_BLATHER(("wm_transfer-%s(%p): " "in: " EV_SIZE_FMT ", " "out: " EV_SIZE_FMT ", " "got: " EV_SIZE_FMT "", ctx->server ? "server" : "client", bev, evbuffer_get_length(in), evbuffer_get_length(out), ctx->get)); evbuffer_add_buffer_reference(out, ctx->data); } static void wm_eventcb(struct bufferevent *bev, short what, void *arg) { struct wm_context *ctx = arg; TT_BLATHER(("wm_eventcb-%s(%p): %i", ctx->server ? "server" : "client", bev, what)); if (what & BEV_EVENT_CONNECTED) { } else { ctx->get = 0; } } static void wm_acceptcb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) { struct wm_context *ctx = arg; struct bufferevent *bev; struct event_base *base = evconnlistener_get_base(listener); SSL *ssl = SSL_new(get_ssl_ctx()); SSL_use_certificate(ssl, the_cert); SSL_use_PrivateKey(ssl, the_key); bev = bufferevent_openssl_socket_new( base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, ctx->flags); TT_BLATHER(("wm_transfer-%s(%p): accept", ctx->server ? "server" : "client", bev)); bufferevent_setwatermark(bev, EV_READ, 0, ctx->wm_high); bufferevent_setcb(bev, wm_transfer, NULL, wm_eventcb, ctx); bufferevent_enable(bev, EV_READ|EV_WRITE); ctx->bev = bev; /* Only accept once, then disable ourself. */ evconnlistener_disable(listener); } static void regress_bufferevent_openssl_wm(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener; struct bufferevent *bev; struct sockaddr_in sin; struct sockaddr_storage ss; enum regress_openssl_type type = (enum regress_openssl_type)data->setup_data; int bev_flags = BEV_OPT_CLOSE_ON_FREE; ev_socklen_t slen; SSL *ssl; struct wm_context client, server; char *payload; size_t payload_len = 1<<10; size_t wm_high = 5<<10; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); memset(&ss, 0, sizeof(ss)); slen = sizeof(ss); if (type & REGRESS_DEFERRED_CALLBACKS) bev_flags |= BEV_OPT_DEFER_CALLBACKS; memset(&client, 0, sizeof(client)); memset(&server, 0, sizeof(server)); client.server = 0; server.server = 1; client.flags = server.flags = bev_flags; client.data = evbuffer_new(); server.data = evbuffer_new(); payload = calloc(1, payload_len); memset(payload, 'A', payload_len); evbuffer_add(server.data, payload, payload_len); evbuffer_add(client.data, payload, payload_len); client.wm_high = server.wm_high = wm_high; client.limit = server.limit = wm_high<<3; client.to_read = server.to_read = payload_len>>1; TT_BLATHER(("openssl_wm: " "payload_len = " EV_SIZE_FMT ", " "wm_high = " EV_SIZE_FMT ", " "limit = " EV_SIZE_FMT ", " "to_read: " EV_SIZE_FMT "", payload_len, wm_high, server.limit, server.to_read)); listener = evconnlistener_new_bind(base, wm_acceptcb, &server, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener); tt_assert(evconnlistener_get_fd(listener) >= 0); ssl = SSL_new(get_ssl_ctx()); tt_assert(ssl); if (type & REGRESS_OPENSSL_FILTER) { bev = bufferevent_socket_new(data->base, -1, client.flags); tt_assert(bev); bev = bufferevent_openssl_filter_new( base, bev, ssl, BUFFEREVENT_SSL_CONNECTING, client.flags); } else { bev = bufferevent_openssl_socket_new( data->base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, client.flags); } tt_assert(bev); client.bev = bev; server.neighbour = &client; client.neighbour = &server; bufferevent_setwatermark(bev, EV_READ, 0, client.wm_high); bufferevent_setcb(bev, wm_transfer, NULL, wm_eventcb, &client); tt_assert(getsockname(evconnlistener_get_fd(listener), (struct sockaddr*)&ss, &slen) == 0); tt_assert(!bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen)); tt_assert(!evbuffer_add_buffer_reference(bufferevent_get_output(bev), client.data)); tt_assert(!bufferevent_enable(bev, EV_READ|EV_WRITE)); event_base_dispatch(base); tt_int_op(client.get, ==, client.limit); tt_int_op(server.get, ==, server.limit); end: free(payload); evbuffer_free(client.data); evbuffer_free(server.data); evconnlistener_free(listener); bufferevent_free(client.bev); bufferevent_free(server.bev); /* XXX: by some reason otherise there is a leak */ if (!(type & REGRESS_OPENSSL_FILTER)) event_base_loop(base, EVLOOP_ONCE); } struct testcase_t ssl_testcases[] = { #define T(a) ((void *)(a)) { "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR) }, { "bufferevent_socketpair_write_after_connect", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR|REGRESS_OPENSSL_CLIENT_WRITE) }, { "bufferevent_filter", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER) }, { "bufferevent_filter_write_after_connect", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER|REGRESS_OPENSSL_CLIENT_WRITE) }, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) }, { "bufferevent_renegotiate_filter", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE) }, { "bufferevent_socketpair_startopen", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN) }, { "bufferevent_filter_startopen", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN) }, { "bufferevent_socketpair_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_filter_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_renegotiate_socketpair_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_renegotiate_filter_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_RENEGOTIATE | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_socketpair_startopen_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_filter_startopen_dirty_shutdown", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_OPEN | REGRESS_OPENSSL_DIRTY_SHUTDOWN) }, { "bufferevent_socketpair_fd", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FD) }, { "bufferevent_socketpair_freed", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED) }, { "bufferevent_socketpair_freed_fd", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, { "bufferevent_filter_freed_fd", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_FILTER | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, { "bufferevent_socketpair_timeout", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT) }, { "bufferevent_socketpair_timeout_freed_fd", regress_bufferevent_openssl, TT_ISOLATED, &ssl_setup, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_TIMEOUT | REGRESS_OPENSSL_FREED | REGRESS_OPENSSL_FD) }, { "bufferevent_connect", regress_bufferevent_openssl_connect, TT_FORK|TT_NEED_BASE, &ssl_setup, NULL }, { "bufferevent_connect_sleep", regress_bufferevent_openssl_connect, TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_SLEEP) }, { "bufferevent_wm", regress_bufferevent_openssl_wm, TT_FORK|TT_NEED_BASE, &ssl_setup, NULL }, { "bufferevent_wm_filter", regress_bufferevent_openssl_wm, TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_FILTER) }, { "bufferevent_wm_defer", regress_bufferevent_openssl_wm, TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_DEFERRED_CALLBACKS) }, { "bufferevent_wm_filter_defer", regress_bufferevent_openssl_wm, TT_FORK|TT_NEED_BASE, &ssl_setup, T(REGRESS_OPENSSL_FILTER|REGRESS_DEFERRED_CALLBACKS) }, #undef T END_OF_TESTCASES, }; lldpd-1.0.13/libevent/test/tinytest_local.h0000644000076400001440000000025214111362571021366 0ustar00bernatusers00000000000000 #include "util-internal.h" #ifdef _WIN32 #include #endif #include "event2/util.h" #ifdef snprintf #undef snprintf #endif #define snprintf evutil_snprintf lldpd-1.0.13/libevent/test/regress_buffer.c0000644000076400001440000024004014111362571021330 0ustar00bernatusers00000000000000/* * Copyright (c) 2003-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util-internal.h" #ifdef _WIN32 #include #include #endif #include "event2/event-config.h" #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #ifndef _WIN32 #include #include #include #include #include #endif #include #include #include #include #include #include "event2/event.h" #include "event2/buffer.h" #include "event2/buffer_compat.h" #include "event2/util.h" #include "defer-internal.h" #include "evbuffer-internal.h" #include "log-internal.h" #include "regress.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) /* Validates that an evbuffer is good. Returns false if it isn't, true if it * is*/ static int evbuffer_validate_(struct evbuffer *buf) { struct evbuffer_chain *chain; size_t sum = 0; int found_last_with_datap = 0; if (buf->first == NULL) { tt_assert(buf->last == NULL); tt_assert(buf->total_len == 0); } chain = buf->first; tt_assert(buf->last_with_datap); if (buf->last_with_datap == &buf->first) found_last_with_datap = 1; while (chain != NULL) { if (&chain->next == buf->last_with_datap) found_last_with_datap = 1; sum += chain->off; if (chain->next == NULL) { tt_assert(buf->last == chain); } tt_assert(chain->buffer_len >= chain->misalign + chain->off); chain = chain->next; } if (buf->first) tt_assert(*buf->last_with_datap); if (*buf->last_with_datap) { chain = *buf->last_with_datap; if (chain->off == 0 || buf->total_len == 0) { tt_assert(chain->off == 0) tt_assert(chain == buf->first); tt_assert(buf->total_len == 0); } chain = chain->next; while (chain != NULL) { tt_assert(chain->off == 0); chain = chain->next; } } else { tt_assert(buf->last_with_datap == &buf->first); } tt_assert(found_last_with_datap); tt_assert(sum == buf->total_len); return 1; end: return 0; } static void evbuffer_get_waste(struct evbuffer *buf, size_t *allocatedp, size_t *wastedp, size_t *usedp) { struct evbuffer_chain *chain; size_t a, w, u; int n = 0; u = a = w = 0; chain = buf->first; /* skip empty at start */ while (chain && chain->off==0) { ++n; a += chain->buffer_len; chain = chain->next; } /* first nonempty chain: stuff at the end only is wasted. */ if (chain) { ++n; a += chain->buffer_len; u += chain->off; if (chain->next && chain->next->off) w += (size_t)(chain->buffer_len - (chain->misalign + chain->off)); chain = chain->next; } /* subsequent nonempty chains */ while (chain && chain->off) { ++n; a += chain->buffer_len; w += (size_t)chain->misalign; u += chain->off; if (chain->next && chain->next->off) w += (size_t) (chain->buffer_len - (chain->misalign + chain->off)); chain = chain->next; } /* subsequent empty chains */ while (chain) { ++n; a += chain->buffer_len; } *allocatedp = a; *wastedp = w; *usedp = u; } #define evbuffer_validate(buf) \ TT_STMT_BEGIN if (!evbuffer_validate_(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END static void test_evbuffer(void *ptr) { static char buffer[512], *tmp; struct evbuffer *evb = evbuffer_new(); struct evbuffer *evb_two = evbuffer_new(); size_t sz_tmp; int i; evbuffer_validate(evb); evbuffer_add_printf(evb, "%s/%d", "hello", 1); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 7); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1)); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); evbuffer_drain(evb, strlen("hello/")); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 1); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1)); evbuffer_add_printf(evb_two, "%s", "/hello"); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb_two) == 0); tt_assert(evbuffer_get_length(evb) == 7); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7)); memset(buffer, 0, sizeof(buffer)); evbuffer_add(evb, buffer, sizeof(buffer)); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 7 + 512); tmp = (char *)evbuffer_pullup(evb, 7 + 512); tt_assert(tmp); tt_assert(!strncmp(tmp, "1/hello", 7)); tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer))); evbuffer_validate(evb); evbuffer_prepend(evb, "something", 9); evbuffer_validate(evb); evbuffer_prepend(evb, "else", 4); evbuffer_validate(evb); tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7); tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7)); evbuffer_validate(evb); evbuffer_drain(evb, -1); evbuffer_validate(evb); evbuffer_drain(evb_two, -1); evbuffer_validate(evb); for (i = 0; i < 3; ++i) { evbuffer_add(evb_two, buffer, sizeof(buffer)); evbuffer_validate(evb_two); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); evbuffer_validate(evb_two); } tt_assert(evbuffer_get_length(evb_two) == 0); tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer)); /* test remove buffer */ sz_tmp = (size_t)(sizeof(buffer)*2.5); evbuffer_remove_buffer(evb, evb_two, sz_tmp); tt_assert(evbuffer_get_length(evb_two) == sz_tmp); tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2); evbuffer_validate(evb); if (memcmp(evbuffer_pullup( evb, -1), buffer, sizeof(buffer) / 2) != 0 || memcmp(evbuffer_pullup( evb_two, -1), buffer, sizeof(buffer)) != 0) tt_abort_msg("Pullup did not preserve content"); evbuffer_validate(evb); /* testing one-vector reserve and commit */ { struct evbuffer_iovec v[1]; char *buf; int i, j, r; for (i = 0; i < 3; ++i) { r = evbuffer_reserve_space(evb, 10000, v, 1); tt_int_op(r, ==, 1); tt_assert(v[0].iov_len >= 10000); tt_assert(v[0].iov_base != NULL); evbuffer_validate(evb); buf = v[0].iov_base; for (j = 0; j < 10000; ++j) { buf[j] = j; } evbuffer_validate(evb); tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) >= 10000); evbuffer_drain(evb, j * 5000); evbuffer_validate(evb); } } end: evbuffer_free(evb); evbuffer_free(evb_two); } static void no_cleanup(const void *data, size_t datalen, void *extra) { } static void test_evbuffer_remove_buffer_with_empty(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); char buf[2] = { 'A', 'A' }; evbuffer_validate(src); evbuffer_validate(dst); /* setup the buffers */ /* we need more data in src than we will move later */ evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); evbuffer_add_reference(src, buf, sizeof(buf), no_cleanup, NULL); /* we need one buffer in dst and one empty buffer at the end */ evbuffer_add(dst, buf, sizeof(buf)); evbuffer_add_reference(dst, buf, 0, no_cleanup, NULL); evbuffer_validate(src); evbuffer_validate(dst); tt_mem_op(evbuffer_pullup(src, -1), ==, "AAAA", 4); tt_mem_op(evbuffer_pullup(dst, -1), ==, "AA", 2); /* move three bytes over */ evbuffer_remove_buffer(src, dst, 3); evbuffer_validate(src); evbuffer_validate(dst); tt_mem_op(evbuffer_pullup(src, -1), ==, "A", 1); tt_mem_op(evbuffer_pullup(dst, -1), ==, "AAAAA", 5); end: evbuffer_free(src); evbuffer_free(dst); } static void test_evbuffer_remove_buffer_with_empty2(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); struct evbuffer *buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, "foo", 3, NULL, NULL); evbuffer_add_reference(src, "foo", 3, NULL, NULL); evbuffer_add_reference(src, NULL, 0, NULL, NULL); evbuffer_add_buffer(src, buf); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, "foo", 3, NULL, NULL); evbuffer_add_reference(dst, "foo", 3, NULL, NULL); evbuffer_add_reference(dst, NULL, 0, NULL, NULL); evbuffer_add_buffer(dst, buf); tt_int_op(evbuffer_get_length(src), ==, 9); tt_int_op(evbuffer_get_length(dst), ==, 9); evbuffer_validate(src); evbuffer_validate(dst); tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoofoo", 9); tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoo", 9); evbuffer_remove_buffer(src, dst, 8); evbuffer_validate(src); evbuffer_validate(dst); tt_int_op(evbuffer_get_length(src), ==, 1); tt_int_op(evbuffer_get_length(dst), ==, 17); tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofoofoofo", 17); end: evbuffer_free(src); evbuffer_free(dst); evbuffer_free(buf); } static void test_evbuffer_remove_buffer_with_empty3(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); struct evbuffer *buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, NULL, 0, NULL, NULL); evbuffer_add_reference(src, "foo", 3, NULL, NULL); evbuffer_add_reference(src, NULL, 0, NULL, NULL); evbuffer_prepend_buffer(src, buf); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, NULL, 0, NULL, NULL); evbuffer_add_reference(dst, "foo", 3, NULL, NULL); evbuffer_add_reference(dst, NULL, 0, NULL, NULL); evbuffer_prepend_buffer(dst, buf); tt_int_op(evbuffer_get_length(src), ==, 6); tt_int_op(evbuffer_get_length(dst), ==, 6); evbuffer_validate(src); evbuffer_validate(dst); tt_mem_op(evbuffer_pullup(src, -1), ==, "foofoo", 6); tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoo", 6); evbuffer_remove_buffer(src, dst, 5); evbuffer_validate(src); evbuffer_validate(dst); tt_int_op(evbuffer_get_length(src), ==, 1); tt_int_op(evbuffer_get_length(dst), ==, 11); tt_mem_op(evbuffer_pullup(src, -1), ==, "o", 1); tt_mem_op(evbuffer_pullup(dst, -1), ==, "foofoofoofo", 11); end: evbuffer_free(src); evbuffer_free(dst); evbuffer_free(buf); } static void test_evbuffer_pullup_with_empty(void *ptr) { struct evbuffer *buf = NULL; buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, NULL, 0, NULL, NULL); evbuffer_validate(buf); tt_int_op(evbuffer_get_length(buf), ==, 3); tt_mem_op(evbuffer_pullup(buf, -1), ==, "foo", 3); evbuffer_free(buf); buf = evbuffer_new(); evbuffer_validate(buf); tt_int_op(evbuffer_get_length(buf), ==, 0); tt_int_op(evbuffer_pullup(buf, -1), ==, NULL); evbuffer_free(buf); buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(buf, NULL, 0, NULL, NULL); evbuffer_validate(buf); tt_mem_op(evbuffer_pullup(buf, 3), ==, "foo", 3); end: if (buf) evbuffer_free(buf); } static void test_evbuffer_remove_buffer_with_empty_front(void *ptr) { struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); buf2 = evbuffer_new(); tt_assert(buf2); tt_int_op(evbuffer_add_reference(buf1, "foo", 3, NULL, NULL), ==, 0); tt_int_op(evbuffer_prepend(buf1, "", 0), ==, 0); tt_int_op(evbuffer_remove_buffer(buf1, buf2, 1), ==, 1); tt_int_op(evbuffer_add(buf1, "bar", 3), ==, 0); tt_mem_op(evbuffer_pullup(buf1, -1), ==, "oobar", 5); evbuffer_validate(buf1); evbuffer_validate(buf2); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty(void *ptr) { struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); buf2 = evbuffer_new(); tt_assert(buf2); tt_int_op(evbuffer_add(buf1, "aaaaaa", 6), ==, 0); // buf1: aaaaaab // buf2: { struct evbuffer_iovec iovecs[2]; /** we want two chains, to leave one chain empty */ tt_int_op(evbuffer_reserve_space(buf1, 971, iovecs, 2), ==, 2); tt_int_op(iovecs[0].iov_len, >=, 1); tt_int_op(iovecs[1].iov_len, >=, 1); tt_assert(*(char *)(iovecs[0].iov_base) = 'b'); tt_assert(iovecs[0].iov_len = 1); tt_int_op(evbuffer_commit_space(buf1, iovecs, 1), ==, 0); } // buf1: aaaaaab // buf2: dddcc tt_int_op(evbuffer_add(buf2, "cc", 2), ==, 0); tt_int_op(evbuffer_prepend(buf2, "ddd", 3), ==, 0); // buf1: // buf2: aaaaaabdddcc tt_int_op(evbuffer_prepend_buffer(buf2, buf1), ==, 0); // buf1: aaaaaabdddcc // buf2: tt_int_op(evbuffer_add_buffer(buf1, buf2), ==, 0); // buf1: c // buf2: aaaaaabdddc tt_int_op(evbuffer_remove_buffer(buf1, buf2, 11), ==, 11); // This fails today, we observe "aaaaaabcddd" instead! tt_mem_op(evbuffer_pullup(buf2, -1), ==, "aaaaaabdddc", 11); evbuffer_validate(buf1); evbuffer_validate(buf2); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_add_buffer_with_empty(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); struct evbuffer *buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(src, "foo", 3, NULL, NULL); evbuffer_add_reference(src, NULL, 0, NULL, NULL); evbuffer_add_buffer(src, buf); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(dst, "foo", 3, NULL, NULL); evbuffer_add_reference(dst, NULL, 0, NULL, NULL); evbuffer_add_buffer(dst, buf); tt_int_op(evbuffer_get_length(src), ==, 6); tt_int_op(evbuffer_get_length(dst), ==, 6); evbuffer_validate(src); evbuffer_validate(dst); end: evbuffer_free(src); evbuffer_free(dst); evbuffer_free(buf); } static void test_evbuffer_add_buffer_with_empty2(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); struct evbuffer *buf = evbuffer_new(); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(src, NULL, 0, NULL, NULL); evbuffer_add_buffer(src, buf); evbuffer_add(buf, "foo", 3); evbuffer_add_reference(dst, NULL, 0, NULL, NULL); evbuffer_add_buffer(dst, buf); tt_int_op(evbuffer_get_length(src), ==, 3); tt_int_op(evbuffer_get_length(dst), ==, 3); evbuffer_validate(src); evbuffer_validate(dst); end: evbuffer_free(src); evbuffer_free(dst); evbuffer_free(buf); } static void test_evbuffer_reserve2(void *ptr) { /* Test the two-vector cases of reserve/commit. */ struct evbuffer *buf = evbuffer_new(); int n, i; struct evbuffer_iovec v[2]; size_t remaining; char *cp, *cp2; /* First chunk will necessarily be one chunk. Use 512 bytes of it.*/ n = evbuffer_reserve_space(buf, 1024, v, 2); tt_int_op(n, ==, 1); tt_int_op(evbuffer_get_length(buf), ==, 0); tt_assert(v[0].iov_base != NULL); tt_int_op(v[0].iov_len, >=, 1024); memset(v[0].iov_base, 'X', 512); cp = v[0].iov_base; remaining = v[0].iov_len - 512; v[0].iov_len = 512; evbuffer_validate(buf); tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); tt_int_op(evbuffer_get_length(buf), ==, 512); evbuffer_validate(buf); /* Ask for another same-chunk request, in an existing chunk. Use 8 * bytes of it. */ n = evbuffer_reserve_space(buf, 32, v, 2); tt_int_op(n, ==, 1); tt_assert(cp + 512 == v[0].iov_base); tt_int_op(remaining, ==, v[0].iov_len); memset(v[0].iov_base, 'Y', 8); v[0].iov_len = 8; tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); tt_int_op(evbuffer_get_length(buf), ==, 520); remaining -= 8; evbuffer_validate(buf); /* Now ask for a request that will be split. Use only one byte of it, though. */ n = evbuffer_reserve_space(buf, remaining+64, v, 2); tt_int_op(n, ==, 2); tt_assert(cp + 520 == v[0].iov_base); tt_int_op(remaining, ==, v[0].iov_len); tt_assert(v[1].iov_base); tt_assert(v[1].iov_len >= 64); cp2 = v[1].iov_base; memset(v[0].iov_base, 'Z', 1); v[0].iov_len = 1; tt_int_op(0, ==, evbuffer_commit_space(buf, v, 1)); tt_int_op(evbuffer_get_length(buf), ==, 521); remaining -= 1; evbuffer_validate(buf); /* Now ask for a request that will be split. Use some of the first * part and some of the second. */ n = evbuffer_reserve_space(buf, remaining+64, v, 2); evbuffer_validate(buf); tt_int_op(n, ==, 2); tt_assert(cp + 521 == v[0].iov_base); tt_int_op(remaining, ==, v[0].iov_len); tt_assert(v[1].iov_base == cp2); tt_assert(v[1].iov_len >= 64); memset(v[0].iov_base, 'W', 400); v[0].iov_len = 400; memset(v[1].iov_base, 'x', 60); v[1].iov_len = 60; tt_int_op(0, ==, evbuffer_commit_space(buf, v, 2)); tt_int_op(evbuffer_get_length(buf), ==, 981); evbuffer_validate(buf); /* Now peek to make sure stuff got made how we like. */ memset(v,0,sizeof(v)); n = evbuffer_peek(buf, -1, NULL, v, 2); tt_int_op(n, ==, 2); tt_int_op(v[0].iov_len, ==, 921); tt_int_op(v[1].iov_len, ==, 60); cp = v[0].iov_base; for (i=0; i<512; ++i) tt_int_op(cp[i], ==, 'X'); for (i=512; i<520; ++i) tt_int_op(cp[i], ==, 'Y'); for (i=520; i<521; ++i) tt_int_op(cp[i], ==, 'Z'); for (i=521; i<921; ++i) tt_int_op(cp[i], ==, 'W'); cp = v[1].iov_base; for (i=0; i<60; ++i) tt_int_op(cp[i], ==, 'x'); end: evbuffer_free(buf); } static void test_evbuffer_reserve_many(void *ptr) { /* This is a glass-box test to handle expanding a buffer with more * chunks and reallocating chunks as needed */ struct evbuffer *buf = evbuffer_new(); struct evbuffer_iovec v[8]; int n; size_t sz; int add_data = ptr && !strcmp(ptr, "add"); int fill_first = ptr && !strcmp(ptr, "fill"); char *cp1, *cp2; /* When reserving the the first chunk, we just allocate it */ n = evbuffer_reserve_space(buf, 128, v, 2); evbuffer_validate(buf); tt_int_op(n, ==, 1); tt_assert(v[0].iov_len >= 128); sz = v[0].iov_len; cp1 = v[0].iov_base; if (add_data) { *(char*)v[0].iov_base = 'X'; v[0].iov_len = 1; n = evbuffer_commit_space(buf, v, 1); tt_int_op(n, ==, 0); } else if (fill_first) { memset(v[0].iov_base, 'X', v[0].iov_len); n = evbuffer_commit_space(buf, v, 1); tt_int_op(n, ==, 0); n = evbuffer_reserve_space(buf, 128, v, 2); tt_int_op(n, ==, 1); sz = v[0].iov_len; tt_assert(v[0].iov_base != cp1); cp1 = v[0].iov_base; } /* Make another chunk get added. */ n = evbuffer_reserve_space(buf, sz+128, v, 2); evbuffer_validate(buf); tt_int_op(n, ==, 2); sz = v[0].iov_len + v[1].iov_len; tt_int_op(sz, >=, v[0].iov_len+128); if (add_data) { tt_assert(v[0].iov_base == cp1 + 1); } else { tt_assert(v[0].iov_base == cp1); } cp1 = v[0].iov_base; cp2 = v[1].iov_base; /* And a third chunk. */ n = evbuffer_reserve_space(buf, sz+128, v, 3); evbuffer_validate(buf); tt_int_op(n, ==, 3); tt_assert(cp1 == v[0].iov_base); tt_assert(cp2 == v[1].iov_base); sz = v[0].iov_len + v[1].iov_len + v[2].iov_len; /* Now force a reallocation by asking for more space in only 2 * buffers. */ n = evbuffer_reserve_space(buf, sz+128, v, 2); evbuffer_validate(buf); if (add_data) { tt_int_op(n, ==, 2); tt_assert(cp1 == v[0].iov_base); } else { tt_int_op(n, ==, 1); } end: evbuffer_free(buf); } static void test_evbuffer_reserve_with_empty(void *ptr) { struct evbuffer *buf; struct evbuffer_iovec v[2]; tt_assert(buf = evbuffer_new()); evbuffer_add(buf, "a", 1); tt_int_op(evbuffer_reserve_space(buf, 1<<12, v, 2), ==, 2); v[0].iov_len = 1; *(char *)v[0].iov_base = 'b'; tt_int_op(evbuffer_commit_space(buf, v, 1), ==, 0); evbuffer_add(buf, "c", 1); tt_mem_op(evbuffer_pullup(buf, -1), ==, "abc", 2); evbuffer_validate(buf); end: if (buf) evbuffer_free(buf); } /* regression for evbuffer_expand_fast_() with invalid last_with_datap that has * been left after evbuffer_prepend() with empty chain in it */ static void test_evbuffer_reserve_invalid_last_with_datap(void *ptr) { struct evbuffer *buf = NULL; struct evbuffer_iovec vec[2]; const int nvec = ARRAY_SIZE(vec); int i, avec; buf = evbuffer_new(); tt_assert(buf); /* prepend with an empty chain */ evbuffer_add_reference(buf, "", 0, NULL, NULL); evbuffer_prepend(buf, "foo", 3); /* after invalid last_with_datap will create new chain */ evbuffer_add(buf, "", 0); /* we need to create at least 2 "used" (in evbuffer_expand_fast_()) chains */ tt_int_op(avec = evbuffer_reserve_space(buf, 1<<12, vec, nvec), >=, 1); for (i = 0; i < avec; ++i) vec[i].iov_len = 0; tt_int_op(evbuffer_commit_space(buf, vec, avec), ==, 0); /* and an actual problem, that triggers an assert(chain == buf->first) in * evbuffer_expand_fast_() */ tt_int_op(evbuffer_reserve_space(buf, 1<<13, vec, nvec), >=, 1); evbuffer_validate(buf); end: if (buf) evbuffer_free(buf); } static void test_evbuffer_expand(void *ptr) { char data[4096]; struct evbuffer *buf; size_t a,w,u; void *buffer; memset(data, 'X', sizeof(data)); /* Make sure that expand() works on an empty buffer */ buf = evbuffer_new(); tt_int_op(evbuffer_expand(buf, 20000), ==, 0); evbuffer_validate(buf); a=w=u=0; evbuffer_get_waste(buf, &a,&w,&u); tt_assert(w == 0); tt_assert(u == 0); tt_assert(a >= 20000); tt_assert(buf->first); tt_assert(buf->first == buf->last); tt_assert(buf->first->off == 0); tt_assert(buf->first->buffer_len >= 20000); /* Make sure that expand() works as a no-op when there's enough * contiguous space already. */ buffer = buf->first->buffer; evbuffer_add(buf, data, 1024); tt_int_op(evbuffer_expand(buf, 1024), ==, 0); tt_assert(buf->first->buffer == buffer); evbuffer_validate(buf); evbuffer_free(buf); /* Make sure that expand() can work by moving misaligned data * when it makes sense to do so. */ buf = evbuffer_new(); evbuffer_add(buf, data, 400); { int n = (int)(buf->first->buffer_len - buf->first->off - 1); tt_assert(n < (int)sizeof(data)); evbuffer_add(buf, data, n); } tt_assert(buf->first == buf->last); tt_assert(buf->first->off == buf->first->buffer_len - 1); evbuffer_drain(buf, buf->first->off - 1); tt_assert(1 == evbuffer_get_length(buf)); tt_assert(buf->first->misalign > 0); tt_assert(buf->first->off == 1); buffer = buf->first->buffer; tt_assert(evbuffer_expand(buf, 40) == 0); tt_assert(buf->first == buf->last); tt_assert(buf->first->off == 1); tt_assert(buf->first->buffer == buffer); tt_assert(buf->first->misalign == 0); evbuffer_validate(buf); evbuffer_free(buf); /* add, expand, pull-up: This used to crash libevent. */ buf = evbuffer_new(); evbuffer_add(buf, data, sizeof(data)); evbuffer_add(buf, data, sizeof(data)); evbuffer_add(buf, data, sizeof(data)); evbuffer_validate(buf); evbuffer_expand(buf, 1024); evbuffer_validate(buf); evbuffer_pullup(buf, -1); evbuffer_validate(buf); end: evbuffer_free(buf); } static void test_evbuffer_expand_overflow(void *ptr) { struct evbuffer *buf; buf = evbuffer_new(); evbuffer_add(buf, "1", 1); evbuffer_expand(buf, EVBUFFER_CHAIN_MAX); evbuffer_validate(buf); evbuffer_expand(buf, EV_SIZE_MAX); evbuffer_validate(buf); end: evbuffer_free(buf); } static void test_evbuffer_add1(void *ptr) { struct evbuffer *buf; char *str; buf = evbuffer_new(); evbuffer_add(buf, "1", 1); evbuffer_validate(buf); evbuffer_expand(buf, 2048); evbuffer_validate(buf); evbuffer_add(buf, "2", 1); evbuffer_validate(buf); evbuffer_add_printf(buf, "3"); evbuffer_validate(buf); tt_assert(evbuffer_get_length(buf) == 3); str = (char *)evbuffer_pullup(buf, -1); tt_assert(str[0] == '1'); tt_assert(str[1] == '2'); tt_assert(str[2] == '3'); end: evbuffer_free(buf); } static void test_evbuffer_add2(void *ptr) { struct evbuffer *buf; static char data[4096]; int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10; char *str; int len; memset(data, 'P', sizeof(data)); buf = evbuffer_new(); evbuffer_add(buf, data, data_len); evbuffer_validate(buf); evbuffer_expand(buf, 100); evbuffer_validate(buf); evbuffer_add(buf, "2", 1); evbuffer_validate(buf); evbuffer_add_printf(buf, "3"); evbuffer_validate(buf); len = evbuffer_get_length(buf); tt_assert(len == data_len+2); str = (char *)evbuffer_pullup(buf, -1); tt_assert(str[len-3] == 'P'); tt_assert(str[len-2] == '2'); tt_assert(str[len-1] == '3'); end: evbuffer_free(buf); } static int reference_cb_called; static void reference_cb(const void *data, size_t len, void *extra) { tt_str_op(data, ==, "this is what we add as read-only memory."); tt_int_op(len, ==, strlen(data)); tt_want(extra == (void *)0xdeadaffe); ++reference_cb_called; end: ; } static void test_evbuffer_reference(void *ptr) { struct evbuffer *src = evbuffer_new(); struct evbuffer *dst = evbuffer_new(); struct evbuffer_iovec v[1]; const char *data = "this is what we add as read-only memory."; reference_cb_called = 0; tt_assert(evbuffer_add_reference(src, data, strlen(data), reference_cb, (void *)0xdeadaffe) != -1); evbuffer_reserve_space(dst, strlen(data), v, 1); tt_assert(evbuffer_remove(src, v[0].iov_base, 10) != -1); evbuffer_validate(src); evbuffer_validate(dst); /* make sure that we don't write data at the beginning */ evbuffer_prepend(src, "aaaaa", 5); evbuffer_validate(src); evbuffer_drain(src, 5); tt_assert(evbuffer_remove(src, ((char*)(v[0].iov_base)) + 10, strlen(data) - 10) != -1); v[0].iov_len = strlen(data); evbuffer_commit_space(dst, v, 1); evbuffer_validate(src); evbuffer_validate(dst); tt_int_op(reference_cb_called, ==, 1); tt_assert(!memcmp(evbuffer_pullup(dst, strlen(data)), data, strlen(data))); evbuffer_validate(dst); end: evbuffer_free(dst); evbuffer_free(src); } static void test_evbuffer_reference2(void *ptr) { struct evbuffer *buf; static char data[4096]; int data_len = MIN_BUFFER_SIZE-EVBUFFER_CHAIN_SIZE-10; char *str; int len; memset(data, 'P', sizeof(data)); buf = evbuffer_new(); evbuffer_add(buf, data, data_len); evbuffer_validate(buf); evbuffer_expand(buf, 100); evbuffer_validate(buf); evbuffer_add_reference(buf, "2", 1, no_cleanup, NULL); evbuffer_validate(buf); evbuffer_add_printf(buf, "3"); evbuffer_validate(buf); len = evbuffer_get_length(buf); tt_assert(len == data_len+2); str = (char *)evbuffer_pullup(buf, -1); tt_assert(str[len-3] == 'P'); tt_assert(str[len-2] == '2'); tt_assert(str[len-1] == '3'); end: evbuffer_free(buf); } static struct event_base *addfile_test_event_base; static int addfile_test_done_writing; static int addfile_test_total_written; static int addfile_test_total_read; static void addfile_test_writecb(evutil_socket_t fd, short what, void *arg) { struct evbuffer *b = arg; int r; evbuffer_validate(b); while (evbuffer_get_length(b)) { r = evbuffer_write(b, fd); if (r > 0) { addfile_test_total_written += r; TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written)); } else { int e = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(e)) return; tt_fail_perror("write"); event_base_loopexit(addfile_test_event_base,NULL); } evbuffer_validate(b); } addfile_test_done_writing = 1; return; end: event_base_loopexit(addfile_test_event_base,NULL); } static void addfile_test_readcb(evutil_socket_t fd, short what, void *arg) { struct evbuffer *b = arg; int e, r = 0; do { r = evbuffer_read(b, fd, 1024); if (r > 0) { addfile_test_total_read += r; TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read)); } } while (r > 0); if (r < 0) { e = evutil_socket_geterror(fd); if (! EVUTIL_ERR_RW_RETRIABLE(e)) { tt_fail_perror("read"); event_base_loopexit(addfile_test_event_base,NULL); } } if (addfile_test_done_writing && addfile_test_total_read >= addfile_test_total_written) { event_base_loopexit(addfile_test_event_base,NULL); } } static void test_evbuffer_add_file(void *ptr) { struct basic_test_data *testdata = ptr; const char *impl = testdata->setup_data; struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new(); char *tmpfilename = NULL; char *data = NULL; const char *expect_data; size_t datalen, expect_len; const char *compare; int fd = -1; int want_ismapping = -1, want_cansendfile = -1; unsigned flags = 0; int use_segment = 1, use_bigfile = 0, map_from_offset = 0, view_from_offset = 0; struct evbuffer_file_segment *seg = NULL; ev_off_t starting_offset = 0, mapping_len = -1; ev_off_t segment_offset = 0, segment_len = -1; struct event *rev=NULL, *wev=NULL; struct event_base *base = testdata->base; evutil_socket_t pair[2] = {-1, -1}; struct evutil_weakrand_state seed = { 123456789U }; /* This test is highly parameterized based on substrings of its * argument. The strings are: */ tt_assert(impl); if (strstr(impl, "nosegment")) { /* If nosegment is set, use the older evbuffer_add_file * interface */ use_segment = 0; } if (strstr(impl, "bigfile")) { /* If bigfile is set, use a 512K file. Else use a smaller * one. */ use_bigfile = 1; } if (strstr(impl, "map_offset")) { /* If map_offset is set, we build the file segment starting * from a point other than byte 0 and ending somewhere other * than the last byte. Otherwise we map the whole thing */ map_from_offset = 1; } if (strstr(impl, "offset_in_segment")) { /* If offset_in_segment is set, we add a subsection of the * file semgment starting from a point other than byte 0 of * the segment. */ view_from_offset = 1; } if (strstr(impl, "sendfile")) { /* If sendfile is set, we try to use a sendfile/splice style * backend. */ flags = EVBUF_FS_DISABLE_MMAP; want_cansendfile = 1; want_ismapping = 0; } else if (strstr(impl, "mmap")) { /* If sendfile is set, we try to use a mmap/CreateFileMapping * style backend. */ flags = EVBUF_FS_DISABLE_SENDFILE; want_ismapping = 1; want_cansendfile = 0; } else if (strstr(impl, "linear")) { /* If linear is set, we try to use a read-the-whole-thing * backend. */ flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP; want_ismapping = 0; want_cansendfile = 0; } else if (strstr(impl, "default")) { /* The caller doesn't care which backend we use. */ ; } else { /* The caller must choose a backend. */ TT_DIE(("Didn't recognize the implementation")); } if (use_bigfile) { unsigned int i; datalen = 1024*512; data = malloc(1024*512); tt_assert(data); for (i = 0; i < datalen; ++i) data[i] = (char)evutil_weakrand_(&seed); } else { data = strdup("here is a relatively small string."); tt_assert(data); datalen = strlen(data); } fd = regress_make_tmpfile(data, datalen, &tmpfilename); if (map_from_offset) { starting_offset = datalen/4 + 1; mapping_len = datalen / 2 - 1; expect_data = data + starting_offset; expect_len = mapping_len; } else { expect_data = data; expect_len = datalen; } if (view_from_offset) { tt_assert(use_segment); /* Can't do this with add_file*/ segment_offset = expect_len / 3; segment_len = expect_len / 2; expect_data = expect_data + segment_offset; expect_len = segment_len; } if (use_segment) { seg = evbuffer_file_segment_new(fd, starting_offset, mapping_len, flags); tt_assert(seg); if (want_ismapping >= 0) { if (seg->is_mapping != (unsigned)want_ismapping) tt_skip(); } if (want_cansendfile >= 0) { if (seg->can_sendfile != (unsigned)want_cansendfile) tt_skip(); } } /* Say that it drains to a fd so that we can use sendfile. */ evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD); #if defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__) /* We need to use a pair of AF_INET sockets, since Solaris doesn't support sendfile() over AF_UNIX. */ if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) tt_abort_msg("ersatz_socketpair failed"); #else if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) tt_abort_msg("socketpair failed"); #endif evutil_make_socket_nonblocking(pair[0]); evutil_make_socket_nonblocking(pair[1]); tt_assert(fd != -1); if (use_segment) { tt_assert(evbuffer_add_file_segment(src, seg, segment_offset, segment_len)!=-1); } else { tt_assert(evbuffer_add_file(src, fd, starting_offset, mapping_len) != -1); } evbuffer_validate(src); addfile_test_event_base = base; addfile_test_done_writing = 0; addfile_test_total_written = 0; addfile_test_total_read = 0; wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST, addfile_test_writecb, src); rev = event_new(base, pair[1], EV_READ|EV_PERSIST, addfile_test_readcb, dest); event_add(wev, NULL); event_add(rev, NULL); event_base_dispatch(base); evbuffer_validate(src); evbuffer_validate(dest); tt_assert(addfile_test_done_writing); tt_int_op(addfile_test_total_written, ==, expect_len); tt_int_op(addfile_test_total_read, ==, expect_len); compare = (char *)evbuffer_pullup(dest, expect_len); tt_assert(compare != NULL); if (memcmp(compare, expect_data, expect_len)) { tt_abort_msg("Data from add_file differs."); } evbuffer_validate(dest); end: if (data) free(data); if (seg) evbuffer_file_segment_free(seg); if (src) evbuffer_free(src); if (dest) evbuffer_free(dest); if (pair[0] >= 0) evutil_closesocket(pair[0]); if (pair[1] >= 0) evutil_closesocket(pair[1]); if (wev) event_free(wev); if (rev) event_free(rev); if (tmpfilename) { unlink(tmpfilename); free(tmpfilename); } } static int file_segment_cleanup_cb_called_count = 0; static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL; static int file_segment_cleanup_cb_called_with_flags = 0; static void* file_segment_cleanup_cb_called_with_arg = NULL; static void file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg) { ++file_segment_cleanup_cb_called_count; file_segment_cleanup_cb_called_with = seg; file_segment_cleanup_cb_called_with_flags = flags; file_segment_cleanup_cb_called_with_arg = arg; } static void test_evbuffer_file_segment_add_cleanup_cb(void* ptr) { char *tmpfilename = NULL; int fd = -1; struct evbuffer *evb = NULL; struct evbuffer_file_segment *seg = NULL, *segptr; char const* arg = "token"; fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename); tt_int_op(fd, >=, 0); evb = evbuffer_new(); tt_assert(evb); segptr = seg = evbuffer_file_segment_new(fd, 0, -1, 0); tt_assert(seg); evbuffer_file_segment_add_cleanup_cb( seg, &file_segment_cleanup_cp, (void*)arg); tt_assert(fd != -1); tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1); evbuffer_validate(evb); tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); evbuffer_file_segment_free(seg); seg = NULL; /* Prevent double-free. */ tt_int_op(file_segment_cleanup_cb_called_count, ==, 0); evbuffer_free(evb); evb = NULL; /* pevent double-free */ tt_int_op(file_segment_cleanup_cb_called_count, ==, 1); tt_assert(file_segment_cleanup_cb_called_with == segptr); tt_assert(file_segment_cleanup_cb_called_with_flags == 0); tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg); end: if (evb) evbuffer_free(evb); if (seg) evbuffer_file_segment_free(seg); if (tmpfilename) { unlink(tmpfilename); free(tmpfilename); } } #ifndef EVENT__DISABLE_MM_REPLACEMENT static void * failing_malloc(size_t how_much) { errno = ENOMEM; return NULL; } #endif static void test_evbuffer_readln(void *ptr) { struct evbuffer *evb = evbuffer_new(); struct evbuffer *evb_tmp = evbuffer_new(); const char *s; char *cp = NULL; size_t sz; #define tt_line_eq(content) \ TT_STMT_BEGIN \ if (!cp || sz != strlen(content) || strcmp(cp, content)) { \ TT_DIE(("Wanted %s; got %s [%d]", content, cp, (int)sz)); \ } \ TT_STMT_END /* Test EOL_ANY. */ s = "complex silly newline\r\n\n\r\n\n\rmore\0\n"; evbuffer_add(evb, s, strlen(s)+2); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); tt_line_eq("complex silly newline"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); if (!cp || sz != 5 || memcmp(cp, "more\0\0", 6)) tt_abort_msg("Not as expected"); tt_uint_op(evbuffer_get_length(evb), ==, 0); evbuffer_validate(evb); s = "\nno newline"; evbuffer_add(evb, s, strlen(s)); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); tt_line_eq(""); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_ANY); tt_assert(!cp); evbuffer_validate(evb); evbuffer_drain(evb, evbuffer_get_length(evb)); tt_assert(evbuffer_get_length(evb) == 0); evbuffer_validate(evb); /* Test EOL_CRLF */ s = "Line with\rin the middle\nLine with good crlf\r\n\nfinal\n"; evbuffer_add(evb, s, strlen(s)); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); tt_line_eq("Line with\rin the middle"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); tt_line_eq("Line with good crlf"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); tt_line_eq(""); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); tt_line_eq("final"); s = "x"; evbuffer_validate(evb); evbuffer_add(evb, s, 1); evbuffer_validate(evb); free(cp); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF); tt_assert(!cp); evbuffer_validate(evb); /* Test CRLF_STRICT */ s = " and a bad crlf\nand a good one\r\n\r\nMore\r"; evbuffer_add(evb, s, strlen(s)); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq("x and a bad crlf\nand a good one"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq(""); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_assert(!cp); evbuffer_validate(evb); evbuffer_add(evb, "\n", 1); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq("More"); free(cp); tt_assert(evbuffer_get_length(evb) == 0); evbuffer_validate(evb); s = "An internal CR\r is not an eol\r\nNor is a lack of one"; evbuffer_add(evb, s, strlen(s)); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq("An internal CR\r is not an eol"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_assert(!cp); evbuffer_validate(evb); evbuffer_add(evb, "\r\n", 2); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq("Nor is a lack of one"); free(cp); tt_assert(evbuffer_get_length(evb) == 0); evbuffer_validate(evb); /* Test LF */ s = "An\rand a nl\n\nText"; evbuffer_add(evb, s, strlen(s)); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_line_eq("An\rand a nl"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_line_eq(""); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_assert(!cp); free(cp); evbuffer_add(evb, "\n", 1); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_line_eq("Text"); free(cp); evbuffer_validate(evb); /* Test NUL */ tt_int_op(evbuffer_get_length(evb), ==, 0); { char x[] = "NUL\n\0\0" "The all-zeros character which may serve\0" "to accomplish time fill\0and media fill"; /* Add all but the final NUL of x. */ evbuffer_add(evb, x, sizeof(x)-1); } cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); tt_line_eq("NUL\n"); free(cp); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); tt_line_eq(""); free(cp); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); tt_line_eq("The all-zeros character which may serve"); free(cp); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); tt_line_eq("to accomplish time fill"); free(cp); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_NUL); tt_ptr_op(cp, ==, NULL); evbuffer_drain(evb, -1); /* Test CRLF_STRICT - across boundaries*/ s = " and a bad crlf\nand a good one\r"; evbuffer_add(evb_tmp, s, strlen(s)); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_tmp); evbuffer_validate(evb); s = "\n\r"; evbuffer_add(evb_tmp, s, strlen(s)); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_tmp); evbuffer_validate(evb); s = "\nMore\r"; evbuffer_add(evb_tmp, s, strlen(s)); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_tmp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq(" and a bad crlf\nand a good one"); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq(""); free(cp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_assert(!cp); free(cp); evbuffer_validate(evb); evbuffer_add(evb, "\n", 1); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_CRLF_STRICT); tt_line_eq("More"); free(cp); cp = NULL; evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 0); /* Test memory problem*/ s = "one line\ntwo line\nblue line"; evbuffer_add(evb_tmp, s, strlen(s)); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_tmp); evbuffer_validate(evb); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_line_eq("one line"); free(cp); cp = NULL; evbuffer_validate(evb); /* the next call to readline should fail */ #ifndef EVENT__DISABLE_MM_REPLACEMENT event_set_mem_functions(failing_malloc, realloc, free); cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_assert(cp == NULL); evbuffer_validate(evb); /* now we should get the next line back */ event_set_mem_functions(malloc, realloc, free); #endif cp = evbuffer_readln(evb, &sz, EVBUFFER_EOL_LF); tt_line_eq("two line"); free(cp); cp = NULL; evbuffer_validate(evb); end: evbuffer_free(evb); evbuffer_free(evb_tmp); if (cp) free(cp); } static void test_evbuffer_search_eol(void *ptr) { struct evbuffer *buf = evbuffer_new(); struct evbuffer_ptr ptr1, ptr2; const char *s; size_t eol_len; s = "string! \r\n\r\nx\n"; evbuffer_add(buf, s, strlen(s)); eol_len = -1; ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_CRLF); tt_int_op(ptr1.pos, ==, 8); tt_int_op(eol_len, ==, 2); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); tt_int_op(ptr2.pos, ==, 8); tt_int_op(eol_len, ==, 2); evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF); tt_int_op(ptr2.pos, ==, 9); tt_int_op(eol_len, ==, 1); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_CRLF_STRICT); tt_int_op(ptr2.pos, ==, 10); tt_int_op(eol_len, ==, 2); eol_len = -1; ptr1 = evbuffer_search_eol(buf, NULL, &eol_len, EVBUFFER_EOL_LF); tt_int_op(ptr1.pos, ==, 9); tt_int_op(eol_len, ==, 1); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); tt_int_op(ptr2.pos, ==, 9); tt_int_op(eol_len, ==, 1); evbuffer_ptr_set(buf, &ptr1, 1, EVBUFFER_PTR_ADD); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); tt_int_op(ptr2.pos, ==, 11); tt_int_op(eol_len, ==, 1); tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); eol_len = -1; ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF); tt_int_op(ptr2.pos, ==, -1); tt_int_op(eol_len, ==, 0); end: evbuffer_free(buf); } static void test_evbuffer_iterative(void *ptr) { struct evbuffer *buf = evbuffer_new(); const char *abc = "abcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyzabcdefghijklmnopqrstvuwxyz"; unsigned i, j, sum, n; sum = 0; n = 0; for (i = 0; i < 1000; ++i) { for (j = 1; j < strlen(abc); ++j) { char format[32]; evutil_snprintf(format, sizeof(format), "%%%u.%us", j, j); evbuffer_add_printf(buf, format, abc); /* Only check for rep violations every so often. Walking over the whole list of chains can get pretty expensive as it gets long. */ if ((n % 337) == 0) evbuffer_validate(buf); sum += j; n++; } } evbuffer_validate(buf); tt_uint_op(sum, ==, evbuffer_get_length(buf)); { size_t a,w,u; a=w=u=0; evbuffer_get_waste(buf, &a, &w, &u); if (0) printf("Allocated: %u.\nWasted: %u.\nUsed: %u.", (unsigned)a, (unsigned)w, (unsigned)u); tt_assert( ((double)w)/a < .125); } end: evbuffer_free(buf); } static void test_evbuffer_find(void *ptr) { unsigned char* p; const char* test1 = "1234567890\r\n"; const char* test2 = "1234567890\r"; #define EVBUFFER_INITIAL_LENGTH 256 char test3[EVBUFFER_INITIAL_LENGTH]; unsigned int i; struct evbuffer * buf = evbuffer_new(); tt_assert(buf); /* make sure evbuffer_find doesn't match past the end of the buffer */ evbuffer_add(buf, (unsigned char*)test1, strlen(test1)); evbuffer_validate(buf); evbuffer_drain(buf, strlen(test1)); evbuffer_validate(buf); evbuffer_add(buf, (unsigned char*)test2, strlen(test2)); evbuffer_validate(buf); p = evbuffer_find(buf, (unsigned char*)"\r\n", 2); tt_want(p == NULL); /* * drain the buffer and do another find; in r309 this would * read past the allocated buffer causing a valgrind error. */ evbuffer_drain(buf, strlen(test2)); evbuffer_validate(buf); for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i) test3[i] = 'a'; test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x'; evbuffer_add(buf, (unsigned char *)test3, EVBUFFER_INITIAL_LENGTH); evbuffer_validate(buf); p = evbuffer_find(buf, (unsigned char *)"xy", 2); tt_want(p == NULL); /* simple test for match at end of allocated buffer */ p = evbuffer_find(buf, (unsigned char *)"ax", 2); tt_assert(p != NULL); tt_want(strncmp((char*)p, "ax", 2) == 0); end: if (buf) evbuffer_free(buf); } static void test_evbuffer_ptr_set(void *ptr) { struct evbuffer *buf = evbuffer_new(); struct evbuffer_ptr pos; struct evbuffer_iovec v[1]; tt_assert(buf); tt_int_op(evbuffer_get_length(buf), ==, 0); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); tt_assert(pos.pos == 0); tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1); tt_assert(pos.pos == -1); tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1); tt_assert(pos.pos == -1); /* create some chains */ evbuffer_reserve_space(buf, 5000, v, 1); v[0].iov_len = 5000; memset(v[0].iov_base, 1, v[0].iov_len); evbuffer_commit_space(buf, v, 1); evbuffer_validate(buf); evbuffer_reserve_space(buf, 4000, v, 1); v[0].iov_len = 4000; memset(v[0].iov_base, 2, v[0].iov_len); evbuffer_commit_space(buf, v, 1); evbuffer_reserve_space(buf, 3000, v, 1); v[0].iov_len = 3000; memset(v[0].iov_base, 3, v[0].iov_len); evbuffer_commit_space(buf, v, 1); evbuffer_validate(buf); tt_int_op(evbuffer_get_length(buf), ==, 12000); tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_SET) == -1); tt_assert(pos.pos == -1); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); tt_assert(pos.pos == 0); tt_assert(evbuffer_ptr_set(buf, &pos, 13000, EVBUFFER_PTR_ADD) == -1); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); tt_assert(pos.pos == 0); tt_assert(evbuffer_ptr_set(buf, &pos, 10000, EVBUFFER_PTR_ADD) == 0); tt_assert(pos.pos == 10000); tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); tt_assert(pos.pos == 11000); tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0); tt_assert(pos.pos == 12000); tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1); tt_assert(pos.pos == -1); end: if (buf) evbuffer_free(buf); } static void test_evbuffer_search(void *ptr) { struct evbuffer *buf = evbuffer_new(); struct evbuffer *tmp = evbuffer_new(); struct evbuffer_ptr pos, end; tt_assert(buf); tt_assert(tmp); pos = evbuffer_search(buf, "x", 1, NULL); tt_int_op(pos.pos, ==, -1); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search(buf, "x", 1, &pos); tt_int_op(pos.pos, ==, -1); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "x", 1, &pos, &pos); tt_int_op(pos.pos, ==, -1); tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "x", 1, &pos, NULL); tt_int_op(pos.pos, ==, -1); /* set up our chains */ evbuffer_add_printf(tmp, "hello"); /* 5 chars */ evbuffer_add_buffer(buf, tmp); evbuffer_add_printf(tmp, "foo"); /* 3 chars */ evbuffer_add_buffer(buf, tmp); evbuffer_add_printf(tmp, "cat"); /* 3 chars */ evbuffer_add_buffer(buf, tmp); evbuffer_add_printf(tmp, "attack"); evbuffer_add_buffer(buf, tmp); pos = evbuffer_search(buf, "attack", 6, NULL); tt_int_op(pos.pos, ==, 11); pos = evbuffer_search(buf, "attacker", 8, NULL); tt_int_op(pos.pos, ==, -1); /* test continuing search */ pos = evbuffer_search(buf, "oc", 2, NULL); tt_int_op(pos.pos, ==, 7); pos = evbuffer_search(buf, "cat", 3, &pos); tt_int_op(pos.pos, ==, 8); pos = evbuffer_search(buf, "tacking", 7, &pos); tt_int_op(pos.pos, ==, -1); evbuffer_ptr_set(buf, &pos, 5, EVBUFFER_PTR_SET); pos = evbuffer_search(buf, "foo", 3, &pos); tt_int_op(pos.pos, ==, 5); evbuffer_ptr_set(buf, &pos, 2, EVBUFFER_PTR_ADD); pos = evbuffer_search(buf, "tat", 3, &pos); tt_int_op(pos.pos, ==, 10); /* test bounded search. */ /* Set "end" to the first t in "attack". */ evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET); pos = evbuffer_search_range(buf, "foo", 3, NULL, &end); tt_int_op(pos.pos, ==, 5); pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end); tt_int_op(pos.pos, ==, 5); pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end); tt_int_op(pos.pos, ==, -1); pos = evbuffer_search_range(buf, "ack", 3, NULL, &end); tt_int_op(pos.pos, ==, -1); /* Set "end" after the last byte in the buffer. */ tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "attack", 6, NULL, &end); tt_int_op(pos.pos, ==, 11); tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); tt_int_op(pos.pos, ==, 11); tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "attack", 6, &pos, &end); tt_int_op(pos.pos, ==, -1); tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0); pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL); tt_int_op(pos.pos, ==, -1); end: if (buf) evbuffer_free(buf); if (tmp) evbuffer_free(tmp); } static void log_change_callback(struct evbuffer *buffer, const struct evbuffer_cb_info *cbinfo, void *arg) { size_t old_len = cbinfo->orig_size; size_t new_len = old_len + cbinfo->n_added - cbinfo->n_deleted; struct evbuffer *out = arg; evbuffer_add_printf(out, "%lu->%lu; ", (unsigned long)old_len, (unsigned long)new_len); } static void self_draining_callback(struct evbuffer *evbuffer, size_t old_len, size_t new_len, void *arg) { if (new_len > old_len) evbuffer_drain(evbuffer, new_len); } static void test_evbuffer_callbacks(void *ptr) { struct evbuffer *buf = evbuffer_new(); struct evbuffer *buf_out1 = evbuffer_new(); struct evbuffer *buf_out2 = evbuffer_new(); struct evbuffer_cb_entry *cb1, *cb2; tt_assert(buf); tt_assert(buf_out1); tt_assert(buf_out2); cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); /* Let's run through adding and deleting some stuff from the buffer * and turning the callbacks on and off and removing them. The callback * adds a summary of length changes to buf_out1/buf_out2 when called. */ /* size: 0-> 36. */ evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2); evbuffer_validate(buf); evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED); evbuffer_drain(buf, 10); /*36->26*/ evbuffer_validate(buf); evbuffer_prepend(buf, "Hello", 5);/*26->31*/ evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED); evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/ evbuffer_remove_cb_entry(buf, cb1); evbuffer_validate(buf); evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/; tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL)); evbuffer_add(buf, "X", 1); /* 0->1 */ tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2)); evbuffer_validate(buf); tt_str_op((const char *) evbuffer_pullup(buf_out1, -1), ==, "0->36; 36->26; 26->31; 31->38; "); tt_str_op((const char *) evbuffer_pullup(buf_out2, -1), ==, "0->36; 31->38; 38->0; 0->1; "); evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1)); evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2)); /* Let's test the obsolete buffer_setcb function too. */ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); tt_assert(cb1 != NULL); cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); tt_assert(cb2 != NULL); tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, 0); evbuffer_add_printf(buf, "This should get drained right away."); tt_uint_op(evbuffer_get_length(buf), ==, 0); tt_uint_op(evbuffer_get_length(buf_out1), ==, 0); tt_uint_op(evbuffer_get_length(buf_out2), ==, 0); tt_int_op(evbuffer_setcb(buf, NULL, NULL), ==, 0); evbuffer_add_printf(buf, "This will not."); tt_str_op((const char *) evbuffer_pullup(buf, -1), ==, "This will not."); evbuffer_validate(buf); evbuffer_drain(buf, evbuffer_get_length(buf)); evbuffer_validate(buf); #if 0 /* Now let's try a suspended callback. */ cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1); cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2); evbuffer_cb_suspend(buf,cb2); evbuffer_prepend(buf,"Hello world",11); /*0->11*/ evbuffer_validate(buf); evbuffer_cb_suspend(buf,cb1); evbuffer_add(buf,"more",4); /* 11->15 */ evbuffer_cb_unsuspend(buf,cb2); evbuffer_drain(buf, 4); /* 15->11 */ evbuffer_cb_unsuspend(buf,cb1); evbuffer_drain(buf, evbuffer_get_length(buf)); /* 11->0 */ tt_str_op(evbuffer_pullup(buf_out1, -1), ==, "0->11; 11->11; 11->0; "); tt_str_op(evbuffer_pullup(buf_out2, -1), ==, "0->15; 15->11; 11->0; "); #endif /* the next call to readline should fail */ #ifndef EVENT__DISABLE_MM_REPLACEMENT event_set_mem_functions(failing_malloc, realloc, free); tt_int_op(evbuffer_setcb(buf, self_draining_callback, NULL), ==, -1); evbuffer_validate(buf); event_set_mem_functions(malloc, realloc, free); #endif end: if (buf) evbuffer_free(buf); if (buf_out1) evbuffer_free(buf_out1); if (buf_out2) evbuffer_free(buf_out2); } static int ref_done_cb_called_count = 0; static void *ref_done_cb_called_with = NULL; static const void *ref_done_cb_called_with_data = NULL; static size_t ref_done_cb_called_with_len = 0; static void ref_done_cb(const void *data, size_t len, void *info) { ++ref_done_cb_called_count; ref_done_cb_called_with = info; ref_done_cb_called_with_data = data; ref_done_cb_called_with_len = len; } static void test_evbuffer_add_reference(void *ptr) { const char chunk1[] = "If you have found the answer to such a problem"; const char chunk2[] = "you ought to write it up for publication"; /* -- Knuth's "Notes on the Exercises" from TAOCP */ char tmp[16]; size_t len1 = strlen(chunk1), len2=strlen(chunk2); struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); evbuffer_add_reference(buf1, chunk1, len1, ref_done_cb, (void*)111); evbuffer_add(buf1, ", ", 2); evbuffer_add_reference(buf1, chunk2, len2, ref_done_cb, (void*)222); tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); /* Make sure we can drain a little from a reference. */ tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); tt_int_op(memcmp(tmp, "If you", 6), ==, 0); tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); tt_int_op(memcmp(tmp, " have", 5), ==, 0); /* Make sure that prepending does not meddle with immutable data */ tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); evbuffer_validate(buf1); /* Make sure that when the chunk is over, the callback is invoked. */ evbuffer_drain(buf1, 7); /* Remove prepended stuff. */ evbuffer_drain(buf1, len1-11-1); /* remove all but one byte of chunk1 */ tt_int_op(ref_done_cb_called_count, ==, 0); evbuffer_remove(buf1, tmp, 1); tt_int_op(tmp[0], ==, 'm'); tt_assert(ref_done_cb_called_with == (void*)111); tt_assert(ref_done_cb_called_with_data == chunk1); tt_assert(ref_done_cb_called_with_len == len1); tt_int_op(ref_done_cb_called_count, ==, 1); evbuffer_validate(buf1); /* Drain some of the remaining chunk, then add it to another buffer */ evbuffer_drain(buf1, 6); /* Remove the ", you ". */ buf2 = evbuffer_new(); tt_assert(buf2); tt_int_op(ref_done_cb_called_count, ==, 1); evbuffer_add(buf2, "I ", 2); evbuffer_add_buffer(buf2, buf1); tt_int_op(ref_done_cb_called_count, ==, 1); evbuffer_remove(buf2, tmp, 16); tt_int_op(memcmp("I ought to write", tmp, 16), ==, 0); evbuffer_drain(buf2, evbuffer_get_length(buf2)); tt_int_op(ref_done_cb_called_count, ==, 2); tt_assert(ref_done_cb_called_with == (void*)222); evbuffer_validate(buf2); /* Now add more stuff to buf1 and make sure that it gets removed on * free. */ evbuffer_add(buf1, "You shake and shake the ", 24); evbuffer_add_reference(buf1, "ketchup bottle", 14, ref_done_cb, (void*)3333); evbuffer_add(buf1, ". Nothing comes and then a lot'll.", 35); evbuffer_free(buf1); buf1 = NULL; tt_int_op(ref_done_cb_called_count, ==, 3); tt_assert(ref_done_cb_called_with == (void*)3333); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_multicast(void *ptr) { const char chunk1[] = "If you have found the answer to such a problem"; const char chunk2[] = "you ought to write it up for publication"; /* -- Knuth's "Notes on the Exercises" from TAOCP */ char tmp[16]; size_t len1 = strlen(chunk1), len2=strlen(chunk2); struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); evbuffer_add(buf1, chunk1, len1); evbuffer_add(buf1, ", ", 2); evbuffer_add(buf1, chunk2, len2); tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); buf2 = evbuffer_new(); tt_assert(buf2); tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); /* nested references are not allowed */ tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1); tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1); /* both buffers contain the same amount of data */ tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1)); /* Make sure we can drain a little from the first buffer. */ tt_int_op(evbuffer_remove(buf1, tmp, 6), ==, 6); tt_int_op(memcmp(tmp, "If you", 6), ==, 0); tt_int_op(evbuffer_remove(buf1, tmp, 5), ==, 5); tt_int_op(memcmp(tmp, " have", 5), ==, 0); /* Make sure that prepending does not meddle with immutable data */ tt_int_op(evbuffer_prepend(buf1, "I have ", 7), ==, 0); tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); evbuffer_validate(buf1); /* Make sure we can drain a little from the second buffer. */ tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); tt_int_op(memcmp(tmp, "If you", 6), ==, 0); tt_int_op(evbuffer_remove(buf2, tmp, 5), ==, 5); tt_int_op(memcmp(tmp, " have", 5), ==, 0); /* Make sure that prepending does not meddle with immutable data */ tt_int_op(evbuffer_prepend(buf2, "I have ", 7), ==, 0); tt_int_op(memcmp(chunk1, "If you", 6), ==, 0); evbuffer_validate(buf2); /* Make sure the data can be read from the second buffer when the first is freed */ evbuffer_free(buf1); buf1 = NULL; tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); tt_int_op(memcmp(tmp, "I have", 6), ==, 0); tt_int_op(evbuffer_remove(buf2, tmp, 6), ==, 6); tt_int_op(memcmp(tmp, " foun", 6), ==, 0); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_multicast_drain(void *ptr) { const char chunk1[] = "If you have found the answer to such a problem"; const char chunk2[] = "you ought to write it up for publication"; /* -- Knuth's "Notes on the Exercises" from TAOCP */ size_t len1 = strlen(chunk1), len2=strlen(chunk2); struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); evbuffer_add(buf1, chunk1, len1); evbuffer_add(buf1, ", ", 2); evbuffer_add(buf1, chunk2, len2); tt_int_op(evbuffer_get_length(buf1), ==, len1+len2+2); buf2 = evbuffer_new(); tt_assert(buf2); tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0); tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); tt_int_op(evbuffer_drain(buf1, evbuffer_get_length(buf1)), ==, 0); tt_int_op(evbuffer_get_length(buf2), ==, len1+len2+2); tt_int_op(evbuffer_drain(buf2, evbuffer_get_length(buf2)), ==, 0); evbuffer_validate(buf1); evbuffer_validate(buf2); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void check_prepend(struct evbuffer *buffer, const struct evbuffer_cb_info *cbinfo, void *arg) { tt_int_op(cbinfo->orig_size, ==, 3); tt_int_op(cbinfo->n_added, ==, 8096); tt_int_op(cbinfo->n_deleted, ==, 0); end: ; } /* Some cases that we didn't get in test_evbuffer() above, for more coverage. */ static void test_evbuffer_prepend(void *ptr) { struct evbuffer *buf1 = NULL, *buf2 = NULL; char tmp[128], *buffer = malloc(8096); int n; buf1 = evbuffer_new(); tt_assert(buf1); /* Case 0: The evbuffer is entirely empty. */ evbuffer_prepend(buf1, "This string has 29 characters", 29); evbuffer_validate(buf1); /* Case 1: Prepend goes entirely in new chunk. */ evbuffer_prepend(buf1, "Short.", 6); evbuffer_validate(buf1); /* Case 2: prepend goes entirely in first chunk. */ evbuffer_drain(buf1, 6+11); evbuffer_prepend(buf1, "it", 2); evbuffer_validate(buf1); tt_assert(!memcmp(buf1->first->buffer+buf1->first->misalign, "it has", 6)); /* Case 3: prepend is split over multiple chunks. */ evbuffer_prepend(buf1, "It is no longer true to say ", 28); evbuffer_validate(buf1); n = evbuffer_remove(buf1, tmp, sizeof(tmp)-1); tt_int_op(n, >=, 0); tmp[n]='\0'; tt_str_op(tmp,==,"It is no longer true to say it has 29 characters"); buf2 = evbuffer_new(); tt_assert(buf2); /* Case 4: prepend a buffer to an empty buffer. */ n = 999; evbuffer_add_printf(buf1, "Here is string %d. ", n++); evbuffer_prepend_buffer(buf2, buf1); evbuffer_validate(buf2); /* Case 5: prepend a buffer to a nonempty buffer. */ evbuffer_add_printf(buf1, "Here is string %d. ", n++); evbuffer_prepend_buffer(buf2, buf1); evbuffer_validate(buf2); evbuffer_validate(buf1); n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1); tt_int_op(n, >=, 0); tmp[n]='\0'; tt_str_op(tmp,==,"Here is string 1000. Here is string 999. "); /* Case 5: evbuffer_prepend() will need a new buffer, with callbacks */ memset(buffer, 'A', 8096); evbuffer_free(buf2); buf2 = evbuffer_new(); tt_assert(buf2); evbuffer_prepend(buf2, "foo", 3); evbuffer_add_cb(buf2, check_prepend, NULL); evbuffer_prepend(buf2, buffer, 8096); evbuffer_remove_cb(buf2, check_prepend, NULL); evbuffer_validate(buf2); tt_nstr_op(8096,(char *)evbuffer_pullup(buf2, 8096),==,buffer); evbuffer_drain(buf2, 8096); tt_nstr_op(3,(char *)evbuffer_pullup(buf2, 3),==,"foo"); evbuffer_drain(buf2, 3); end: free(buffer); if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_empty_reference_prepend(void *ptr) { struct evbuffer *buf = NULL; buf = evbuffer_new(); tt_assert(buf); /** empty chain could leave invalid last_with_datap */ evbuffer_add_reference(buf, "", 0, NULL, NULL); evbuffer_validate(buf); evbuffer_prepend(buf, "foo", 3); evbuffer_validate(buf); tt_assert(!strncmp((char *)evbuffer_pullup(buf, -1), "foo", 3)); evbuffer_validate(buf); end: if (buf) evbuffer_free(buf); } static void test_evbuffer_empty_reference_prepend_buffer(void *ptr) { struct evbuffer *buf1 = NULL, *buf2 = NULL; buf1 = evbuffer_new(); tt_assert(buf1); buf2 = evbuffer_new(); tt_assert(buf2); /** empty chain could leave invalid last_with_datap */ evbuffer_add_reference(buf1, "", 0, NULL, NULL); evbuffer_validate(buf1); evbuffer_add(buf2, "foo", 3); evbuffer_validate(buf2); evbuffer_prepend_buffer(buf2, buf1); evbuffer_validate(buf2); tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), "foo", 3)); evbuffer_validate(buf2); tt_assert(evbuffer_pullup(buf1, -1) == NULL); evbuffer_validate(buf2); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } static void test_evbuffer_peek_first_gt(void *info) { struct evbuffer *buf = NULL, *tmp_buf = NULL; struct evbuffer_ptr ptr; struct evbuffer_iovec v[2]; buf = evbuffer_new(); tmp_buf = evbuffer_new(); evbuffer_add_printf(tmp_buf, "Contents of chunk 100\n"); evbuffer_add_buffer(buf, tmp_buf); evbuffer_add_printf(tmp_buf, "Contents of chunk 1\n"); evbuffer_add_buffer(buf, tmp_buf); evbuffer_ptr_set(buf, &ptr, 0, EVBUFFER_PTR_SET); /** The only case that matters*/ tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); /** Just in case */ tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); evbuffer_ptr_set(buf, &ptr, 20, EVBUFFER_PTR_ADD); tt_int_op(evbuffer_peek(buf, -1, &ptr, NULL, 0), ==, 2); tt_int_op(evbuffer_peek(buf, -1, &ptr, v, 2), ==, 2); tt_int_op(evbuffer_peek(buf, 2, &ptr, NULL, 0), ==, 1); tt_int_op(evbuffer_peek(buf, 2, &ptr, v, 2), ==, 1); tt_int_op(evbuffer_peek(buf, 3, &ptr, NULL, 0), ==, 2); tt_int_op(evbuffer_peek(buf, 3, &ptr, v, 2), ==, 2); end: if (buf) evbuffer_free(buf); if (tmp_buf) evbuffer_free(tmp_buf); } static void test_evbuffer_peek(void *info) { struct evbuffer *buf = NULL, *tmp_buf = NULL; int i; struct evbuffer_iovec v[20]; struct evbuffer_ptr ptr; #define tt_iov_eq(v, s) \ tt_int_op((v)->iov_len, ==, strlen(s)); \ tt_assert(!memcmp((v)->iov_base, (s), strlen(s))) /* Let's make a very fragmented buffer. */ buf = evbuffer_new(); tmp_buf = evbuffer_new(); for (i = 0; i < 16; ++i) { evbuffer_add_printf(tmp_buf, "Contents of chunk [%d]\n", i); evbuffer_add_buffer(buf, tmp_buf); } /* How many chunks do we need for everything? */ i = evbuffer_peek(buf, -1, NULL, NULL, 0); tt_int_op(i, ==, 16); /* Simple peek: get everything. */ i = evbuffer_peek(buf, -1, NULL, v, 20); tt_int_op(i, ==, 16); /* we used only 16 chunks. */ tt_iov_eq(&v[0], "Contents of chunk [0]\n"); tt_iov_eq(&v[3], "Contents of chunk [3]\n"); tt_iov_eq(&v[12], "Contents of chunk [12]\n"); tt_iov_eq(&v[15], "Contents of chunk [15]\n"); /* Just get one chunk worth. */ memset(v, 0, sizeof(v)); i = evbuffer_peek(buf, -1, NULL, v, 1); tt_int_op(i, ==, 1); tt_iov_eq(&v[0], "Contents of chunk [0]\n"); tt_assert(v[1].iov_base == NULL); /* Suppose we want at least the first 40 bytes. */ memset(v, 0, sizeof(v)); i = evbuffer_peek(buf, 40, NULL, v, 16); tt_int_op(i, ==, 2); tt_iov_eq(&v[0], "Contents of chunk [0]\n"); tt_iov_eq(&v[1], "Contents of chunk [1]\n"); tt_assert(v[2].iov_base == NULL); /* How many chunks do we need for 100 bytes? */ memset(v, 0, sizeof(v)); i = evbuffer_peek(buf, 100, NULL, NULL, 0); tt_int_op(i, ==, 5); tt_assert(v[0].iov_base == NULL); /* Now we ask for more bytes than we provide chunks for */ memset(v, 0, sizeof(v)); i = evbuffer_peek(buf, 60, NULL, v, 1); tt_int_op(i, ==, 3); tt_iov_eq(&v[0], "Contents of chunk [0]\n"); tt_assert(v[1].iov_base == NULL); /* Now we ask for more bytes than the buffer has. */ memset(v, 0, sizeof(v)); i = evbuffer_peek(buf, 65536, NULL, v, 20); tt_int_op(i, ==, 16); /* we used only 16 chunks. */ tt_iov_eq(&v[0], "Contents of chunk [0]\n"); tt_iov_eq(&v[3], "Contents of chunk [3]\n"); tt_iov_eq(&v[12], "Contents of chunk [12]\n"); tt_iov_eq(&v[15], "Contents of chunk [15]\n"); tt_assert(v[16].iov_base == NULL); /* What happens if we try an empty buffer? */ memset(v, 0, sizeof(v)); i = evbuffer_peek(tmp_buf, -1, NULL, v, 20); tt_int_op(i, ==, 0); tt_assert(v[0].iov_base == NULL); memset(v, 0, sizeof(v)); i = evbuffer_peek(tmp_buf, 50, NULL, v, 20); tt_int_op(i, ==, 0); tt_assert(v[0].iov_base == NULL); /* Okay, now time to have fun with pointers. */ memset(v, 0, sizeof(v)); evbuffer_ptr_set(buf, &ptr, 30, EVBUFFER_PTR_SET); i = evbuffer_peek(buf, 50, &ptr, v, 20); tt_int_op(i, ==, 3); tt_iov_eq(&v[0], " of chunk [1]\n"); tt_iov_eq(&v[1], "Contents of chunk [2]\n"); tt_iov_eq(&v[2], "Contents of chunk [3]\n"); /*more than we asked for*/ /* advance to the start of another chain. */ memset(v, 0, sizeof(v)); evbuffer_ptr_set(buf, &ptr, 14, EVBUFFER_PTR_ADD); i = evbuffer_peek(buf, 44, &ptr, v, 20); tt_int_op(i, ==, 2); tt_iov_eq(&v[0], "Contents of chunk [2]\n"); tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/ /* peek at the end of the buffer */ memset(v, 0, sizeof(v)); tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0); i = evbuffer_peek(buf, 44, &ptr, v, 20); tt_int_op(i, ==, 0); tt_assert(v[0].iov_base == NULL); end: if (buf) evbuffer_free(buf); if (tmp_buf) evbuffer_free(tmp_buf); } /* Check whether evbuffer freezing works right. This is called twice, once with the argument "start" and once with the argument "end". When we test "start", we freeze the start of an evbuffer and make sure that modifying the start of the buffer doesn't work. When we test "end", we freeze the end of an evbuffer and make sure that modifying the end of the buffer doesn't work. */ static void test_evbuffer_freeze(void *ptr) { struct basic_test_data *testdata = ptr; evutil_socket_t *pair = testdata->pair; struct evbuffer *buf = NULL, *buf_two = NULL, *tmp_buf = NULL; const char string[] = /* Year's End, Richard Wilbur */ "I've known the wind by water banks to shake\n" "The late leaves down, which frozen where they fell\n" "And held in ice as dancers in a spell\n" "Fluttered all winter long into a lake..."; const int start = !strcmp(testdata->setup_data, "start"); const char tmpfilecontent[] = "file_freeze_test_file"; char *cp; char charbuf[128]; char *tmpfilename = NULL; int fd = -1; int r; size_t orig_length, len; struct evbuffer_iovec v[1]; if (!start) tt_str_op(testdata->setup_data, ==, "end"); buf = evbuffer_new(); buf_two = evbuffer_new(); tmp_buf = evbuffer_new(); tt_assert(tmp_buf); evbuffer_add(buf, string, strlen(string)); evbuffer_add(buf_two, "abc", 3); evbuffer_add(tmp_buf, "xyz", 3); evbuffer_freeze(buf, start); /* Freeze the start or the end.*/ evbuffer_freeze(buf_two, start); #define FREEZE_EQ(a, startcase, endcase) \ do { \ if (start) { \ tt_int_op((a), ==, (startcase)); \ } else { \ tt_int_op((a), ==, (endcase)); \ } \ } while (0) orig_length = evbuffer_get_length(buf); /* These functions all manipulate the end of buf. */ r = evbuffer_add(buf, "abc", 0); FREEZE_EQ(r, 0, -1); r = evbuffer_reserve_space(buf, 10, v, 1); FREEZE_EQ(r, 1, -1); if (r == 1) { memset(v[0].iov_base, 'X', 10); v[0].iov_len = 10; } r = evbuffer_commit_space(buf, v, 1); FREEZE_EQ(r, 0, -1); r = evbuffer_add_reference(buf, string, 5, NULL, NULL); FREEZE_EQ(r, 0, -1); r = evbuffer_add_printf(buf, "Hello %s", "world"); FREEZE_EQ(r, 11, -1); r = evbuffer_add_buffer(buf, tmp_buf); FREEZE_EQ(r, 0, -1); len = strlen(tmpfilecontent); fd = regress_make_tmpfile(tmpfilecontent, len, &tmpfilename); r = evbuffer_add_file(buf, fd, 0, len); FREEZE_EQ(r, 0, -1); if (start) evbuffer_add(tmp_buf, "xyz", 3); tt_assert(evbuffer_get_length(tmp_buf)); len = evbuffer_get_length(tmp_buf); evbuffer_write(tmp_buf, pair[0]); r = evbuffer_read(buf, pair[1], -1); FREEZE_EQ(r, len, -1); if (!start) tt_int_op(orig_length, ==, evbuffer_get_length(buf)); orig_length = evbuffer_get_length(buf); /* These functions all manipulate the start of buf. */ r = evbuffer_remove(buf, charbuf, 1); FREEZE_EQ(r, -1, 1); r = evbuffer_drain(buf, 3); FREEZE_EQ(r, -1, 0); r = evbuffer_prepend(buf, "dummy", 5); FREEZE_EQ(r, -1, 0); cp = evbuffer_readln(buf, NULL, EVBUFFER_EOL_LF); FREEZE_EQ(cp==NULL, 1, 0); if (cp) free(cp); evbuffer_add(tmp_buf, "xyz", 3); tt_assert(evbuffer_get_length(tmp_buf)); r = evbuffer_remove_buffer(buf, tmp_buf, 3); FREEZE_EQ(r, -1, 3); r = evbuffer_drain(buf, 3); FREEZE_EQ(r, -1, 0); r = evbuffer_prepend_buffer(buf, tmp_buf); FREEZE_EQ(r, -1, 0); len = evbuffer_get_length(buf); r = evbuffer_write(buf, pair[0]); evbuffer_read(tmp_buf, pair[1], -1); FREEZE_EQ(r, -1, len); len = evbuffer_get_length(buf_two); r = evbuffer_write_atmost(buf_two, pair[0], -1); evbuffer_read(tmp_buf, pair[1], -1); FREEZE_EQ(r, -1, len); if (start) tt_int_op(orig_length, ==, evbuffer_get_length(buf)); end: if (buf) evbuffer_free(buf); if (buf_two) evbuffer_free(buf_two); if (tmp_buf) evbuffer_free(tmp_buf); if (tmpfilename) { unlink(tmpfilename); free(tmpfilename); } } static void test_evbuffer_add_iovec(void * ptr) { struct evbuffer * buf = NULL; struct evbuffer_iovec vec[4]; const char * data[] = { "Guilt resembles a sword with two edges.", "On the one hand, it cuts for Justice, imposing practical morality upon those who fear it.", "Conscience does not always adhere to rational judgment.", "Guilt is always a self-imposed burden, but it is not always rightly imposed." /* -- R.A. Salvatore, _Sojurn_ */ }; size_t expected_length = 0; size_t returned_length = 0; int i; buf = evbuffer_new(); tt_assert(buf); for (i = 0; i < 4; i++) { vec[i].iov_len = strlen(data[i]); vec[i].iov_base = (char*) data[i]; expected_length += vec[i].iov_len; } returned_length = evbuffer_add_iovec(buf, vec, 4); tt_int_op(returned_length, ==, evbuffer_get_length(buf)); tt_int_op(evbuffer_get_length(buf), ==, expected_length); for (i = 0; i < 4; i++) { char charbuf[1024]; memset(charbuf, 0, 1024); evbuffer_remove(buf, charbuf, strlen(data[i])); tt_assert(strcmp(charbuf, data[i]) == 0); } tt_assert(evbuffer_get_length(buf) == 0); end: if (buf) { evbuffer_free(buf); } } static void test_evbuffer_copyout(void *dummy) { const char string[] = "Still they skirmish to and fro, men my messmates on the snow " "When we headed off the aurochs turn for turn; " "When the rich Allobrogenses never kept amanuenses, " "And our only plots were piled in lakes at Berne."; /* -- Kipling, "In The Neolithic Age" */ char tmp[1024]; struct evbuffer_ptr ptr; struct evbuffer *buf; (void)dummy; buf = evbuffer_new(); tt_assert(buf); tt_int_op(strlen(string), ==, 206); /* Ensure separate chains */ evbuffer_add_reference(buf, string, 80, no_cleanup, NULL); evbuffer_add_reference(buf, string+80, 80, no_cleanup, NULL); evbuffer_add(buf, string+160, strlen(string)-160); tt_int_op(206, ==, evbuffer_get_length(buf)); /* First, let's test plain old copyout. */ /* Copy a little from the beginning. */ tt_int_op(10, ==, evbuffer_copyout(buf, tmp, 10)); tt_int_op(0, ==, memcmp(tmp, "Still they", 10)); /* Now copy more than a little from the beginning */ memset(tmp, 0, sizeof(tmp)); tt_int_op(100, ==, evbuffer_copyout(buf, tmp, 100)); tt_int_op(0, ==, memcmp(tmp, string, 100)); /* Copy too much; ensure truncation. */ memset(tmp, 0, sizeof(tmp)); tt_int_op(206, ==, evbuffer_copyout(buf, tmp, 230)); tt_int_op(0, ==, memcmp(tmp, string, 206)); /* That was supposed to be nondestructive, btw */ tt_int_op(206, ==, evbuffer_get_length(buf)); /* Now it's time to test copyout_from! First, let's start in the * first chain. */ evbuffer_ptr_set(buf, &ptr, 15, EVBUFFER_PTR_SET); memset(tmp, 0, sizeof(tmp)); tt_int_op(10, ==, evbuffer_copyout_from(buf, &ptr, tmp, 10)); tt_int_op(0, ==, memcmp(tmp, "mish to an", 10)); /* Right up to the end of the first chain */ memset(tmp, 0, sizeof(tmp)); tt_int_op(65, ==, evbuffer_copyout_from(buf, &ptr, tmp, 65)); tt_int_op(0, ==, memcmp(tmp, string+15, 65)); /* Span into the second chain */ memset(tmp, 0, sizeof(tmp)); tt_int_op(90, ==, evbuffer_copyout_from(buf, &ptr, tmp, 90)); tt_int_op(0, ==, memcmp(tmp, string+15, 90)); /* Span into the third chain */ memset(tmp, 0, sizeof(tmp)); tt_int_op(160, ==, evbuffer_copyout_from(buf, &ptr, tmp, 160)); tt_int_op(0, ==, memcmp(tmp, string+15, 160)); /* Overrun */ memset(tmp, 0, sizeof(tmp)); tt_int_op(206-15, ==, evbuffer_copyout_from(buf, &ptr, tmp, 999)); tt_int_op(0, ==, memcmp(tmp, string+15, 206-15)); /* That was supposed to be nondestructive, too */ tt_int_op(206, ==, evbuffer_get_length(buf)); end: if (buf) evbuffer_free(buf); } static void * setup_passthrough(const struct testcase_t *testcase) { return testcase->setup_data; } static int cleanup_passthrough(const struct testcase_t *testcase, void *ptr) { (void) ptr; return 1; } static const struct testcase_setup_t nil_setup = { setup_passthrough, cleanup_passthrough }; struct testcase_t evbuffer_testcases[] = { { "evbuffer", test_evbuffer, 0, NULL, NULL }, { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL }, { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL }, { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL }, { "remove_buffer_with_empty_front", test_evbuffer_remove_buffer_with_empty_front, 0, NULL, NULL }, { "remove_buffer_adjust_last_with_datap_with_empty", test_evbuffer_remove_buffer_adjust_last_with_datap_with_empty, 0, NULL, NULL }, { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL }, { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL }, { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL }, { "reserve_many", test_evbuffer_reserve_many, 0, NULL, NULL }, { "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" }, { "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" }, { "reserve_with_empty", test_evbuffer_reserve_with_empty, 0, NULL, NULL }, { "reserve_invalid_last_with_datap", test_evbuffer_reserve_invalid_last_with_datap, TT_FORK, NULL, NULL }, { "expand", test_evbuffer_expand, 0, NULL, NULL }, { "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL }, { "add1", test_evbuffer_add1, 0, NULL, NULL }, { "add2", test_evbuffer_add2, 0, NULL, NULL }, { "reference", test_evbuffer_reference, 0, NULL, NULL }, { "reference2", test_evbuffer_reference2, 0, NULL, NULL }, { "iterative", test_evbuffer_iterative, 0, NULL, NULL }, { "readln", test_evbuffer_readln, TT_NO_LOGS, &basic_setup, NULL }, { "search_eol", test_evbuffer_search_eol, 0, NULL, NULL }, { "find", test_evbuffer_find, 0, NULL, NULL }, { "ptr_set", test_evbuffer_ptr_set, 0, NULL, NULL }, { "search", test_evbuffer_search, 0, NULL, NULL }, { "callbacks", test_evbuffer_callbacks, 0, NULL, NULL }, { "add_reference", test_evbuffer_add_reference, 0, NULL, NULL }, { "multicast", test_evbuffer_multicast, 0, NULL, NULL }, { "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL }, { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL }, { "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL }, { "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL }, { "peek", test_evbuffer_peek, 0, NULL, NULL }, { "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL }, { "freeze_start", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"start" }, { "freeze_end", test_evbuffer_freeze, TT_NEED_SOCKETPAIR, &basic_setup, (void*)"end" }, { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL}, { "copyout", test_evbuffer_copyout, 0, NULL, NULL}, { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL }, { "pullup_with_empty", test_evbuffer_pullup_with_empty, 0, NULL, NULL }, #define ADDFILE_TEST(name, parameters) \ { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \ &basic_setup, (void*)(parameters) } #define ADDFILE_TEST_GROUP(name, parameters) \ ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \ ADDFILE_TEST(name "_mmap", "mmap " parameters), \ ADDFILE_TEST(name "_linear", "linear " parameters) ADDFILE_TEST_GROUP("add_file", ""), ADDFILE_TEST("add_file_nosegment", "default nosegment"), ADDFILE_TEST_GROUP("add_big_file", "bigfile"), ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"), ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"), ADDFILE_TEST("add_file_offset_nosegment", "default nosegment bigfile map_offset"), ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"), ADDFILE_TEST_GROUP("add_file_offset3", "bigfile offset_in_segment map_offset"), END_OF_TESTCASES }; lldpd-1.0.13/libevent/test/regress_thread.h0000644000076400001440000000474414111362571021344 0ustar00bernatusers00000000000000/* * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef REGRESS_THREAD_H_INCLUDED_ #define REGRESS_THREAD_H_INCLUDED_ #if defined(_WIN32) /** _WIN32 */ #define THREAD_T void * /* HANDLE */ #define THREAD_FN unsigned __stdcall #define THREAD_RETURN() return (0) #define THREAD_SELF() GetCurrentThreadId() #define THREAD_START(threadvar, fn, arg) do { \ uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \ (threadvar) = (THREAD_T)threadhandle; \ thread_setup(threadvar); \ } while (0) #define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE) #else /* !_WIN32 */ #include #define THREAD_T pthread_t #define THREAD_FN void * #define THREAD_RETURN() return (NULL) #define THREAD_SELF() pthread_self() #define THREAD_START(threadvar, fn, arg) do { \ if (!pthread_create(&(threadvar), NULL, fn, arg)) \ thread_setup(threadvar); \ } while (0) #define THREAD_JOIN(th) pthread_join(th, NULL) #endif /* \!_WIN32 */ void thread_setup(THREAD_T pthread); #endif lldpd-1.0.13/libevent/test/regress_listener.c0000644000076400001440000002330014111362571021702 0ustar00bernatusers00000000000000/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util-internal.h" #ifdef _WIN32 #include #include #endif #include #ifndef _WIN32 #include #include # ifdef _XOPEN_SOURCE_EXTENDED # include # endif #include #endif #ifdef EVENT__HAVE_SYS_RESOURCE_H #include #endif #include #include "event2/listener.h" #include "event2/event.h" #include "event2/util.h" #include "regress.h" #include "tinytest.h" #include "tinytest_macros.h" static void acceptcb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) { int *ptr = arg; --*ptr; TT_BLATHER(("Got one for %p", ptr)); evutil_closesocket(fd); if (! *ptr) evconnlistener_disable(listener); } static void regress_pick_a_port(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener1 = NULL, *listener2 = NULL; struct sockaddr_in sin; int count1 = 2, count2 = 1; struct sockaddr_storage ss1, ss2; struct sockaddr_in *sin1, *sin2; ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2); unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC; evutil_socket_t fd1, fd2, fd3; fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET; if (data->setup_data && strstr((char*)data->setup_data, "ts")) { flags |= LEV_OPT_THREADSAFE; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* "You pick!" */ listener1 = evconnlistener_new_bind(base, acceptcb, &count1, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener1); listener2 = evconnlistener_new_bind(base, acceptcb, &count2, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener2); tt_assert(evconnlistener_get_fd(listener1) != EVUTIL_INVALID_SOCKET); tt_assert(evconnlistener_get_fd(listener2) != EVUTIL_INVALID_SOCKET); tt_assert(getsockname(evconnlistener_get_fd(listener1), (struct sockaddr*)&ss1, &slen1) == 0); tt_assert(getsockname(evconnlistener_get_fd(listener2), (struct sockaddr*)&ss2, &slen2) == 0); tt_int_op(ss1.ss_family, ==, AF_INET); tt_int_op(ss2.ss_family, ==, AF_INET); sin1 = (struct sockaddr_in*)&ss1; sin2 = (struct sockaddr_in*)&ss2; tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001); tt_int_op(sin1->sin_port, !=, sin2->sin_port); tt_ptr_op(evconnlistener_get_base(listener1), ==, base); tt_ptr_op(evconnlistener_get_base(listener2), ==, base); fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET; evutil_socket_connect_(&fd1, (struct sockaddr*)&ss1, slen1); evutil_socket_connect_(&fd2, (struct sockaddr*)&ss1, slen1); evutil_socket_connect_(&fd3, (struct sockaddr*)&ss2, slen2); #ifdef _WIN32 Sleep(100); /* XXXX this is a stupid stopgap. */ #endif event_base_dispatch(base); tt_int_op(count1, ==, 0); tt_int_op(count2, ==, 0); end: if (fd1>=0) EVUTIL_CLOSESOCKET(fd1); if (fd2>=0) EVUTIL_CLOSESOCKET(fd2); if (fd3>=0) EVUTIL_CLOSESOCKET(fd3); if (listener1) evconnlistener_free(listener1); if (listener2) evconnlistener_free(listener2); } static void errorcb(struct evconnlistener *lis, void *data_) { int *data = data_; *data = 1000; evconnlistener_disable(lis); } static void regress_listener_error(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener = NULL; int count = 1; unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; if (data->setup_data && strstr((char*)data->setup_data, "ts")) { flags |= LEV_OPT_THREADSAFE; } /* send, so that pair[0] will look 'readable'*/ tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0); /* Start a listener with a bogus socket. */ listener = evconnlistener_new(base, acceptcb, &count, flags, 0, data->pair[0]); tt_assert(listener); evconnlistener_set_error_cb(listener, errorcb); tt_assert(listener); event_base_dispatch(base); tt_int_op(count,==,1000); /* set by error cb */ end: if (listener) evconnlistener_free(listener); } static void acceptcb_free(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg) { int *ptr = arg; --*ptr; TT_BLATHER(("Got one for %p", ptr)); evutil_closesocket(fd); if (! *ptr) evconnlistener_free(listener); } static void regress_listener_close_accepted_fd(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener = NULL; struct sockaddr_in sin; struct sockaddr_storage ss; ev_socklen_t slen = sizeof(ss); int count = 1; unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; evutil_socket_t fd = EVUTIL_INVALID_SOCKET; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* "You pick!" */ /* Start a listener with a bogus socket. */ listener = evconnlistener_new_bind(base, acceptcb_free, &count, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener); tt_assert(getsockname(evconnlistener_get_fd(listener), (struct sockaddr*)&ss, &slen) == 0); evutil_socket_connect_(&fd, (struct sockaddr*)&ss, slen); event_base_dispatch(base); end: ; } static void regress_listener_immediate_close(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener = NULL; struct sockaddr_in sin; struct sockaddr_storage ss; ev_socklen_t slen = sizeof(ss); int count = 1; unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; evutil_socket_t fd1 = EVUTIL_INVALID_SOCKET, fd2 = EVUTIL_INVALID_SOCKET; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ sin.sin_port = 0; /* "You pick!" */ /* Start a listener with a bogus socket. */ listener = evconnlistener_new_bind(base, acceptcb, &count, flags, -1, (struct sockaddr *)&sin, sizeof(sin)); tt_assert(listener); tt_assert(getsockname(evconnlistener_get_fd(listener), (struct sockaddr*)&ss, &slen) == 0); evutil_socket_connect_(&fd1, (struct sockaddr*)&ss, slen); evutil_socket_connect_(&fd2, (struct sockaddr*)&ss, slen); event_base_dispatch(base); tt_int_op(count, ==, 0); end: if (listener) evconnlistener_free(listener); } #ifdef EVENT__HAVE_SETRLIMIT static void regress_listener_error_unlock(void *arg) { struct basic_test_data *data = arg; struct event_base *base = data->base; struct evconnlistener *listener = NULL; unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE; tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0); /* Start a listener with a bogus socket. */ listener = evconnlistener_new(base, acceptcb, NULL, flags, 0, data->pair[0]); tt_assert(listener); /** accept() must errored out with EMFILE */ { struct rlimit rl; rl.rlim_cur = rl.rlim_max = data->pair[1]; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { TT_DIE(("Can't change RLIMIT_NOFILE")); } } event_base_loop(base, EVLOOP_ONCE); /** with lock debugging, can fail on lock->count assertion */ end: if (listener) evconnlistener_free(listener); } #endif struct testcase_t listener_testcases[] = { { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE, &basic_setup, NULL}, { "randport_ts", regress_pick_a_port, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"ts"}, #ifdef EVENT__HAVE_SETRLIMIT { "error_unlock", regress_listener_error_unlock, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL}, #endif { "error", regress_listener_error, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, NULL}, { "error_ts", regress_listener_error, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, (char*)"ts"}, { "close_accepted_fd", regress_listener_close_accepted_fd, TT_FORK|TT_NEED_BASE, &basic_setup, NULL, }, { "immediate_close", regress_listener_immediate_close, TT_FORK|TT_NEED_BASE, &basic_setup, NULL, }, END_OF_TESTCASES, }; struct testcase_t listener_iocp_testcases[] = { { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL}, { "error", regress_listener_error, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_ENABLE_IOCP, &basic_setup, NULL}, END_OF_TESTCASES, }; lldpd-1.0.13/libevent/test/test-eof.c0000644000076400001440000000604114111362571020054 0ustar00bernatusers00000000000000/* * Copyright (c) 2002-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../util-internal.h" #include "event2/event-config.h" #ifdef _WIN32 #include #else #include #endif #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #ifdef EVENT__HAVE_SYS_SOCKET_H #include #endif #include #include #include #include #include #include #include int test_okay = 1; int called = 0; struct timeval timeout = {60, 0}; static void read_cb(evutil_socket_t fd, short event, void *arg) { char buf[256]; int len; if (EV_TIMEOUT & event) { printf("%s: Timeout!\n", __func__); exit(1); } len = recv(fd, buf, sizeof(buf), 0); printf("%s: read %d%s\n", __func__, len, len ? "" : " - means EOF"); if (len) { if (!called) event_add(arg, &timeout); } else if (called == 1) test_okay = 0; called++; } int main(int argc, char **argv) { struct event ev; const char *test = "test string"; evutil_socket_t pair[2]; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); (void) WSAStartup(wVersionRequested, &wsaData); #endif if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) return (1); if (send(pair[0], test, (int)strlen(test)+1, 0) < 0) return (1); shutdown(pair[0], EVUTIL_SHUT_WR); /* Initialize the event library */ event_init(); /* Initialize one event */ event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev); event_add(&ev, &timeout); event_dispatch(); return (test_okay); } lldpd-1.0.13/libevent/test/regress_testutils.c0000644000076400001440000001457614111362571022134 0ustar00bernatusers00000000000000/* * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../util-internal.h" #ifdef _WIN32 #include #include #include #endif #include "event2/event-config.h" #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #ifndef _WIN32 #include #include #include #include #include #endif #ifdef EVENT__HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_NETDB_H #include #endif #include #include #include #include #include #include "event2/dns.h" #include "event2/dns_struct.h" #include "event2/event.h" #include "event2/event_compat.h" #include "event2/util.h" #include "event2/listener.h" #include "event2/bufferevent.h" #include "log-internal.h" #include "regress.h" #include "regress_testutils.h" /* globals */ static struct evdns_server_port *dns_port; evutil_socket_t dns_sock = -1; /* Helper: return the port that a socket is bound on, in host order. */ int regress_get_socket_port(evutil_socket_t fd) { struct sockaddr_storage ss; ev_socklen_t socklen = sizeof(ss); if (getsockname(fd, (struct sockaddr*)&ss, &socklen) != 0) return -1; if (ss.ss_family == AF_INET) return ntohs( ((struct sockaddr_in*)&ss)->sin_port); else if (ss.ss_family == AF_INET6) return ntohs( ((struct sockaddr_in6*)&ss)->sin6_port); else return -1; } struct evdns_server_port * regress_get_dnsserver(struct event_base *base, ev_uint16_t *portnum, evutil_socket_t *psock, evdns_request_callback_fn_type cb, void *arg) { struct evdns_server_port *port = NULL; evutil_socket_t sock; struct sockaddr_in my_addr; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { tt_abort_perror("socket"); } evutil_make_socket_nonblocking(sock); memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(*portnum); my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { evutil_closesocket(sock); tt_abort_perror("bind"); } port = evdns_add_server_port_with_base(base, sock, 0, cb, arg); if (!*portnum) *portnum = regress_get_socket_port(sock); if (psock) *psock = sock; return port; end: return NULL; } void regress_clean_dnsserver(void) { if (dns_port) { evdns_close_server_port(dns_port); dns_port = NULL; } if (dns_sock >= 0) { evutil_closesocket(dns_sock); dns_sock = -1; } } static void strtolower(char *s) { while (*s) { *s = EVUTIL_TOLOWER_(*s); ++s; } } void regress_dns_server_cb(struct evdns_server_request *req, void *data) { struct regress_dns_server_table *tab = data; char *question; if (req->nquestions != 1) TT_DIE(("Only handling one question at a time; got %d", req->nquestions)); question = req->questions[0]->name; while (tab->q && evutil_ascii_strcasecmp(question, tab->q) && strcmp("*", tab->q)) ++tab; if (tab->q == NULL) TT_DIE(("Unexpected question: '%s'", question)); ++tab->seen; if (tab->lower) strtolower(question); if (!strcmp(tab->anstype, "err")) { int err = atoi(tab->ans); tt_assert(! evdns_server_request_respond(req, err)); return; } else if (!strcmp(tab->anstype, "errsoa")) { int err = atoi(tab->ans); char soa_record[] = "\x04" "dns1" "\x05" "icann" "\x03" "org" "\0" "\x0a" "hostmaster" "\x05" "icann" "\x03" "org" "\0" "\x77\xde\x5e\xba" /* serial */ "\x00\x00\x1c\x20" /* refreshtime = 2h */ "\x00\x00\x0e\x10" /* retry = 1h */ "\x00\x12\x75\x00" /* expiration = 14d */ "\x00\x00\x0e\x10" /* min.ttl = 1h */ ; evdns_server_request_add_reply( req, EVDNS_AUTHORITY_SECTION, "example.com", EVDNS_TYPE_SOA, EVDNS_CLASS_INET, 42, sizeof(soa_record) - 1, 0, soa_record); tt_assert(! evdns_server_request_respond(req, err)); return; } else if (!strcmp(tab->anstype, "A")) { struct in_addr in; if (!evutil_inet_pton(AF_INET, tab->ans, &in)) { TT_DIE(("Bad A value %s in table", tab->ans)); } evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, 100); } else if (!strcmp(tab->anstype, "AAAA")) { struct in6_addr in6; if (!evutil_inet_pton(AF_INET6, tab->ans, &in6)) { TT_DIE(("Bad AAAA value %s in table", tab->ans)); } evdns_server_request_add_aaaa_reply(req, question, 1, &in6.s6_addr, 100); } else { TT_DIE(("Weird table entry with type '%s'", tab->anstype)); } tt_assert(! evdns_server_request_respond(req, 0)) return; end: tt_want(! evdns_server_request_drop(req)); } int regress_dnsserver(struct event_base *base, ev_uint16_t *port, struct regress_dns_server_table *search_table) { dns_port = regress_get_dnsserver(base, port, &dns_sock, regress_dns_server_cb, search_table); return dns_port != NULL; } int regress_get_listener_addr(struct evconnlistener *lev, struct sockaddr *sa, ev_socklen_t *socklen) { evutil_socket_t s = evconnlistener_get_fd(lev); if (s <= 0) return -1; return getsockname(s, sa, socklen); } lldpd-1.0.13/libevent/test/regress_http.c0000644000076400001440000040210414111362571021037 0ustar00bernatusers00000000000000/* * Copyright (c) 2003-2007 Niels Provos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util-internal.h" #ifdef _WIN32 #include #include #include #endif #include "event2/event-config.h" #include #include #ifdef EVENT__HAVE_SYS_TIME_H #include #endif #include #ifndef _WIN32 #include #include #include #include #endif #include #include #include #include #include #include "event2/dns.h" #include "event2/event.h" #include "event2/http.h" #include "event2/buffer.h" #include "event2/bufferevent.h" #include "event2/bufferevent_ssl.h" #include "event2/util.h" #include "event2/listener.h" #include "log-internal.h" #include "http-internal.h" #include "regress.h" #include "regress_testutils.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /* set if a test needs to call loopexit on a base */ static struct event_base *exit_base; static char const BASIC_REQUEST_BODY[] = "This is funny"; static void http_basic_cb(struct evhttp_request *req, void *arg); static void http_timeout_cb(struct evhttp_request *req, void *arg); static void http_large_cb(struct evhttp_request *req, void *arg); static void http_chunked_cb(struct evhttp_request *req, void *arg); static void http_post_cb(struct evhttp_request *req, void *arg); static void http_put_cb(struct evhttp_request *req, void *arg); static void http_delete_cb(struct evhttp_request *req, void *arg); static void http_delay_cb(struct evhttp_request *req, void *arg); static void http_large_delay_cb(struct evhttp_request *req, void *arg); static void http_badreq_cb(struct evhttp_request *req, void *arg); static void http_dispatcher_cb(struct evhttp_request *req, void *arg); static void http_on_complete_cb(struct evhttp_request *req, void *arg); #define HTTP_BIND_IPV6 1 #define HTTP_BIND_SSL 2 #define HTTP_SSL_FILTER 4 static int http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask) { int port; struct evhttp_bound_socket *sock; int ipv6 = mask & HTTP_BIND_IPV6; if (ipv6) sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport); else sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport); if (sock == NULL) { if (ipv6) return -1; else event_errx(1, "Could not start web server"); } port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock)); if (port < 0) return -1; *pport = (ev_uint16_t) port; return 0; } #ifdef EVENT__HAVE_OPENSSL static struct bufferevent * https_bev(struct event_base *base, void *arg) { SSL *ssl = SSL_new(get_ssl_ctx()); SSL_use_certificate(ssl, ssl_getcert(ssl_getkey())); SSL_use_PrivateKey(ssl, ssl_getkey()); return bufferevent_openssl_socket_new( base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE); } #endif static struct evhttp * http_setup_gencb(ev_uint16_t *pport, struct event_base *base, int mask, void (*cb)(struct evhttp_request *, void *), void *cbarg) { struct evhttp *myhttp; /* Try a few different ports */ myhttp = evhttp_new(base); if (http_bind(myhttp, pport, mask) < 0) return NULL; #ifdef EVENT__HAVE_OPENSSL if (mask & HTTP_BIND_SSL) { init_ssl(); evhttp_set_bevcb(myhttp, https_bev, NULL); } #endif evhttp_set_gencb(myhttp, cb, cbarg); /* Register a callback for certain types of requests */ evhttp_set_cb(myhttp, "/test", http_basic_cb, myhttp); evhttp_set_cb(myhttp, "/test nonconformant", http_basic_cb, myhttp); evhttp_set_cb(myhttp, "/timeout", http_timeout_cb, myhttp); evhttp_set_cb(myhttp, "/large", http_large_cb, base); evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base); evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base); evhttp_set_cb(myhttp, "/postit", http_post_cb, base); evhttp_set_cb(myhttp, "/putit", http_put_cb, base); evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base); evhttp_set_cb(myhttp, "/delay", http_delay_cb, base); evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base); evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base); evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base); evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base); return (myhttp); } static struct evhttp * http_setup(ev_uint16_t *pport, struct event_base *base, int mask) { return http_setup_gencb(pport, base, mask, NULL, NULL); } #ifndef NI_MAXSERV #define NI_MAXSERV 1024 #endif static evutil_socket_t http_connect(const char *address, ev_uint16_t port) { /* Stupid code for connecting */ struct evutil_addrinfo ai, *aitop; char strport[NI_MAXSERV]; struct sockaddr *sa; size_t slen; evutil_socket_t fd; memset(&ai, 0, sizeof(ai)); ai.ai_family = AF_INET; ai.ai_socktype = SOCK_STREAM; evutil_snprintf(strport, sizeof(strport), "%d", port); if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) { event_warn("getaddrinfo"); return (-1); } sa = aitop->ai_addr; slen = aitop->ai_addrlen; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) event_err(1, "socket failed"); evutil_make_socket_nonblocking(fd); if (connect(fd, sa, slen) == -1) { #ifdef _WIN32 int tmp_err = WSAGetLastError(); if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL && tmp_err != WSAEWOULDBLOCK) event_err(1, "connect failed"); #else if (errno != EINPROGRESS) event_err(1, "connect failed"); #endif } evutil_freeaddrinfo(aitop); return (fd); } /* Helper: do a strcmp on the contents of buf and the string s. */ static int evbuffer_datacmp(struct evbuffer *buf, const char *s) { size_t b_sz = evbuffer_get_length(buf); size_t s_sz = strlen(s); unsigned char *d; int r; if (b_sz < s_sz) return -1; d = evbuffer_pullup(buf, s_sz); if (!d) d = (unsigned char *)""; if ((r = memcmp(d, s, s_sz))) return r; if (b_sz > s_sz) return 1; else return 0; } /* Helper: Return true iff buf contains s */ static int evbuffer_contains(struct evbuffer *buf, const char *s) { struct evbuffer_ptr ptr; ptr = evbuffer_search(buf, s, strlen(s), NULL); return ptr.pos != -1; } static void http_readcb(struct bufferevent *bev, void *arg) { const char *what = BASIC_REQUEST_BODY; struct event_base *my_base = arg; if (evbuffer_contains(bufferevent_get_input(bev), what)) { struct evhttp_request *req = evhttp_request_new(NULL, NULL); enum message_read_status done; /* req->kind = EVHTTP_RESPONSE; */ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; if (done == 1 && evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) test_ok++; out: evhttp_request_free(req); bufferevent_disable(bev, EV_READ); if (exit_base) event_base_loopexit(exit_base, NULL); else if (my_base) event_base_loopexit(my_base, NULL); else { fprintf(stderr, "No way to exit loop!\n"); exit(1); } } } static void http_writecb(struct bufferevent *bev, void *arg) { if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { /* enable reading of the reply */ bufferevent_enable(bev, EV_READ); test_ok++; } } static void http_errorcb(struct bufferevent *bev, short what, void *arg) { /** For ssl */ if (what & BEV_EVENT_CONNECTED) return; test_ok = -2; event_base_loopexit(arg, NULL); } static int found_multi = 0; static int found_multi2 = 0; static void http_basic_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); struct evhttp_connection *evcon; int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL; TT_BLATHER(("%s: called\n", __func__)); evbuffer_add_printf(evb, BASIC_REQUEST_BODY); evcon = evhttp_request_get_connection(req); tt_assert(evhttp_connection_get_server(evcon) == arg); { const struct sockaddr *sa; char addrbuf[128]; sa = evhttp_connection_get_addr(evcon); tt_assert(sa); if (sa->sa_family == AF_INET) { evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf)); tt_assert(!strncmp(addrbuf, "127.0.0.1:", strlen("127.0.0.1:"))); } else if (sa->sa_family == AF_INET6) { evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf)); tt_assert(!strncmp(addrbuf, "[::1]:", strlen("[::1]:"))); } else { tt_fail_msg("Unsupported family"); } } /* For multi-line headers test */ { const char *multi = evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi"); if (multi) { found_multi = !strcmp(multi,"aaaaaaaa a END"); if (strcmp("END", multi + strlen(multi) - 3) == 0) test_ok++; if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last")) test_ok++; } } { const char *multi2 = evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS"); if (multi2) { found_multi2 = !strcmp(multi2,"libevent 2.1"); } } /* injecting a bad content-length */ if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative")) evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "-100"); /* allow sending of an empty reply */ evhttp_send_reply(req, HTTP_OK, "Everything is fine", !empty ? evb : NULL); end: evbuffer_free(evb); } static void http_timeout_reply_cb(evutil_socket_t fd, short events, void *arg) { struct evhttp_request *req = arg; evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL); test_ok++; } static void http_timeout_cb(struct evhttp_request *req, void *arg) { struct timeval when = { 0, 100 }; event_base_once(exit_base, -1, EV_TIMEOUT, http_timeout_reply_cb, req, &when); } static void http_large_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); int i; for (i = 0; i < 1<<20; ++i) { evbuffer_add_printf(evb, BASIC_REQUEST_BODY); } evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); } static char const* const CHUNKS[] = { "This is funny", "but not hilarious.", "bwv 1052" }; struct chunk_req_state { struct event_base *base; struct evhttp_request *req; int i; }; static void http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg) { struct evbuffer *evb = evbuffer_new(); struct chunk_req_state *state = arg; struct timeval when = { 0, 0 }; evbuffer_add_printf(evb, "%s", CHUNKS[state->i]); evhttp_send_reply_chunk(state->req, evb); evbuffer_free(evb); if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) { event_base_once(state->base, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when); } else { evhttp_send_reply_end(state->req); free(state); } } static void http_chunked_cb(struct evhttp_request *req, void *arg) { struct timeval when = { 0, 0 }; struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state)); TT_BLATHER(("%s: called\n", __func__)); memset(state, 0, sizeof(struct chunk_req_state)); state->req = req; state->base = arg; if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) { evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39"); } /* generate a chunked/streamed reply */ evhttp_send_reply_start(req, HTTP_OK, "Everything is fine"); /* but trickle it across several iterations to ensure we're not * assuming it comes all at once */ event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when); } static struct bufferevent * create_bev(struct event_base *base, evutil_socket_t fd, int ssl_mask, int flags_) { int flags = BEV_OPT_DEFER_CALLBACKS | flags_; struct bufferevent *bev = NULL; if (!ssl_mask) { bev = bufferevent_socket_new(base, fd, flags); } else { #ifdef EVENT__HAVE_OPENSSL SSL *ssl = SSL_new(get_ssl_ctx()); if (ssl_mask & HTTP_SSL_FILTER) { struct bufferevent *underlying = bufferevent_socket_new(base, fd, flags); bev = bufferevent_openssl_filter_new( base, underlying, ssl, BUFFEREVENT_SSL_CONNECTING, flags); } else { bev = bufferevent_openssl_socket_new( base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags); } bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); #endif } return bev; } static void http_half_writecb(struct bufferevent *bev, void *arg) { if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { if (!test_ok) { const char http_request[] = "host\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); } /* enable reading of the reply */ bufferevent_enable(bev, EV_READ); test_ok++; } } static void http_basic_test_impl(void *arg, int ssl, const char *request_line) { struct basic_test_data *data = arg; struct bufferevent *bev = NULL; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0, port2 = 0; int server_flags = ssl ? HTTP_BIND_SSL : 0; struct evhttp *http = http_setup(&port, data->base, server_flags); struct evbuffer *out; exit_base = data->base; /* bind to a second socket */ if (http_bind(http, &port2, server_flags) == -1) { fprintf(stdout, "FAILED (bind)\n"); exit(1); } fd = http_connect("127.0.0.1", port); /* Stupid thing to send a request */ bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, http_readcb, http_half_writecb, http_errorcb, data->base); out = bufferevent_get_output(bev); /* first half of the http request */ evbuffer_add_printf(out, "%s\r\n" "Host: some", request_line); test_ok = 0; event_base_dispatch(data->base); tt_int_op(test_ok, ==, 3); /* connect to the second port */ bufferevent_free(bev); fd = http_connect("127.0.0.1", port2); /* Stupid thing to send a request */ bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, data->base); out = bufferevent_get_output(bev); evbuffer_add_printf(out, "%s\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n", request_line); test_ok = 0; event_base_dispatch(data->base); tt_int_op(test_ok, ==, 2); /* Connect to the second port again. This time, send an absolute uri. */ bufferevent_free(bev); fd = http_connect("127.0.0.1", port2); /* Stupid thing to send a request */ bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, data->base); http_request = "GET http://somehost.net/test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); test_ok = 0; event_base_dispatch(data->base); tt_int_op(test_ok, ==, 2); evhttp_free(http); end: if (bev) bufferevent_free(bev); } static void http_basic_test(void *arg)\ { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1"); } static void http_basic_trailing_space_test(void *arg) { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1 "); } static void http_delay_reply(evutil_socket_t fd, short what, void *arg) { struct evhttp_request *req = arg; evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL); ++test_ok; } static void http_delay_cb(struct evhttp_request *req, void *arg) { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 200 * 1000; event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv); } static void http_badreq_cb(struct evhttp_request *req, void *arg) { struct evbuffer *buf = evbuffer_new(); evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8"); evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1"); evhttp_send_reply(req, HTTP_OK, "OK", buf); evbuffer_free(buf); } static void http_badreq_errorcb(struct bufferevent *bev, short what, void *arg) { TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg)); /* ignore */ } static void http_badreq_readcb(struct bufferevent *bev, void *arg) { const char *what = "Hello, 127.0.0.1"; const char *bad_request = "400 Bad Request"; if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) { TT_FAIL(("%s:bad request detected", __func__)); bufferevent_disable(bev, EV_READ); event_base_loopexit(arg, NULL); return; } if (evbuffer_contains(bufferevent_get_input(bev), what)) { struct evhttp_request *req = evhttp_request_new(NULL, NULL); enum message_read_status done; /* req->kind = EVHTTP_RESPONSE; */ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; if (done == 1 && evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) test_ok++; out: evhttp_request_free(req); evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev))); } shutdown(bufferevent_getfd(bev), EVUTIL_SHUT_WR); } static void http_badreq_successcb(evutil_socket_t fd, short what, void *arg) { TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg)); event_base_loopexit(exit_base, NULL); } static void http_bad_request_test(void *arg) { struct basic_test_data *data = arg; struct timeval tv; struct bufferevent *bev = NULL; evutil_socket_t fd = EVUTIL_INVALID_SOCKET; const char *http_request; ev_uint16_t port=0, port2=0; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; exit_base = data->base; /* bind to a second socket */ if (http_bind(http, &port2, 0) == -1) TT_DIE(("Bind socket failed")); /* NULL request test */ fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_badreq_readcb, http_writecb, http_badreq_errorcb, data->base); bufferevent_enable(bev, EV_READ); /* real NULL request */ http_request = ""; bufferevent_write(bev, http_request, strlen(http_request)); shutdown(fd, EVUTIL_SHUT_WR); timerclear(&tv); tv.tv_usec = 10000; event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv); event_base_dispatch(data->base); bufferevent_free(bev); evutil_closesocket(fd); if (test_ok != 0) { fprintf(stdout, "FAILED\n"); exit(1); } /* Second answer (BAD REQUEST) on connection close */ /* connect to the second port */ fd = http_connect("127.0.0.1", port2); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_badreq_readcb, http_writecb, http_badreq_errorcb, data->base); bufferevent_enable(bev, EV_READ); /* first half of the http request */ http_request = "GET /badrequest HTTP/1.0\r\n" \ "Connection: Keep-Alive\r\n" \ "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); timerclear(&tv); tv.tv_usec = 10000; event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv); event_base_dispatch(data->base); tt_int_op(test_ok, ==, 2); end: evhttp_free(http); if (bev) bufferevent_free(bev); if (fd >= 0) evutil_closesocket(fd); } static struct evhttp_connection *delayed_client; static void http_large_delay_cb(struct evhttp_request *req, void *arg) { struct timeval tv; evutil_timerclear(&tv); tv.tv_usec = 500000; event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv); evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF); } /* * HTTP DELETE test, just piggyback on the basic test */ static void http_delete_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL; /* Expecting a DELETE request */ if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) { fprintf(stdout, "FAILED (delete type)\n"); exit(1); } TT_BLATHER(("%s: called\n", __func__)); evbuffer_add_printf(evb, BASIC_REQUEST_BODY); /* allow sending of an empty reply */ evhttp_send_reply(req, HTTP_OK, "Everything is fine", !empty ? evb : NULL); evbuffer_free(evb); } static void http_delete_test(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev; evutil_socket_t fd = EVUTIL_INVALID_SOCKET; const char *http_request; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; test_ok = 0; tt_assert(http); fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, data->base); http_request = "DELETE /deleteit HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(data->base); bufferevent_free(bev); evutil_closesocket(fd); fd = EVUTIL_INVALID_SOCKET; evhttp_free(http); tt_int_op(test_ok, ==, 2); end: if (fd >= 0) evutil_closesocket(fd); } static void http_sent_cb(struct evhttp_request *req, void *arg) { ev_uintptr_t val = (ev_uintptr_t)arg; struct evbuffer *b; if (val != 0xDEADBEEF) { fprintf(stdout, "FAILED on_complete_cb argument\n"); exit(1); } b = evhttp_request_get_output_buffer(req); if (evbuffer_get_length(b) != 0) { fprintf(stdout, "FAILED on_complete_cb output buffer not written\n"); exit(1); } TT_BLATHER(("%s: called\n", __func__)); ++test_ok; } static void http_on_complete_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF); TT_BLATHER(("%s: called\n", __func__)); evbuffer_add_printf(evb, BASIC_REQUEST_BODY); /* allow sending of an empty reply */ evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); ++test_ok; } static void http_on_complete_test(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev; evutil_socket_t fd = EVUTIL_INVALID_SOCKET; const char *http_request; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; test_ok = 0; fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, data->base); http_request = "GET /oncomplete HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(data->base); bufferevent_free(bev); evhttp_free(http); tt_int_op(test_ok, ==, 4); end: if (fd >= 0) evutil_closesocket(fd); } static void http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg) { char **output = arg; if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) { char buf[4096]; int n; n = evbuffer_remove(bufferevent_get_input(bev), buf, sizeof(buf)-1); if (n >= 0) { buf[n]='\0'; if (*output) free(*output); *output = strdup(buf); } event_base_loopexit(exit_base, NULL); } } static void http_allowed_methods_test(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev1, *bev2, *bev3; evutil_socket_t fd1=-1, fd2=-1, fd3=-1; const char *http_request; char *result1=NULL, *result2=NULL, *result3=NULL; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; test_ok = 0; fd1 = http_connect("127.0.0.1", port); tt_assert(fd1 != EVUTIL_INVALID_SOCKET); /* GET is out; PATCH is in. */ evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH); /* Stupid thing to send a request */ bev1 = bufferevent_socket_new(data->base, fd1, 0); bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_setcb(bev1, NULL, NULL, http_allowed_methods_eventcb, &result1); http_request = "GET /index.html HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev1, http_request, strlen(http_request)); event_base_dispatch(data->base); fd2 = http_connect("127.0.0.1", port); tt_assert(fd2 != EVUTIL_INVALID_SOCKET); bev2 = bufferevent_socket_new(data->base, fd2, 0); bufferevent_enable(bev2, EV_READ|EV_WRITE); bufferevent_setcb(bev2, NULL, NULL, http_allowed_methods_eventcb, &result2); http_request = "PATCH /test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev2, http_request, strlen(http_request)); event_base_dispatch(data->base); fd3 = http_connect("127.0.0.1", port); tt_assert(fd3 != EVUTIL_INVALID_SOCKET); bev3 = bufferevent_socket_new(data->base, fd3, 0); bufferevent_enable(bev3, EV_READ|EV_WRITE); bufferevent_setcb(bev3, NULL, NULL, http_allowed_methods_eventcb, &result3); http_request = "FLOOP /test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev3, http_request, strlen(http_request)); event_base_dispatch(data->base); bufferevent_free(bev1); bufferevent_free(bev2); bufferevent_free(bev3); evhttp_free(http); /* Method known but disallowed */ tt_assert(result1); tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 "))); /* Method known and allowed */ tt_assert(result2); tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 "))); /* Method unknown */ tt_assert(result3); tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 "))); end: if (result1) free(result1); if (result2) free(result2); if (result3) free(result3); if (fd1 >= 0) evutil_closesocket(fd1); if (fd2 >= 0) evutil_closesocket(fd2); if (fd3 >= 0) evutil_closesocket(fd3); } static void http_request_no_action_done(struct evhttp_request *, void *); static void http_request_done(struct evhttp_request *, void *); static void http_request_empty_done(struct evhttp_request *, void *); static void http_connection_test_(struct basic_test_data *data, int persistent, const char *address, struct evdns_base *dnsbase, int ipv6, int family, int ssl) { ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evhttp *http; int mask = 0; if (ipv6) mask |= HTTP_BIND_IPV6; if (ssl) mask |= HTTP_BIND_SSL; http = http_setup(&port, data->base, mask); test_ok = 0; if (!http && ipv6) { tt_skip(); } tt_assert(http); if (ssl) { #ifdef EVENT__HAVE_OPENSSL SSL *ssl = SSL_new(get_ssl_ctx()); struct bufferevent *bev = bufferevent_openssl_socket_new( data->base, -1, ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); evcon = evhttp_connection_base_bufferevent_new(data->base, dnsbase, bev, address, port); #else tt_skip(); #endif } else { evcon = evhttp_connection_base_new(data->base, dnsbase, address, port); } tt_assert(evcon); evhttp_connection_set_family(evcon, family); tt_assert(evhttp_connection_get_base(evcon) == data->base); exit_base = data->base; tt_assert(evhttp_connection_get_server(evcon) == NULL); /* * At this point, we want to schedule a request to the HTTP * server using our make request method. */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { fprintf(stdout, "FAILED\n"); exit(1); } event_base_dispatch(data->base); tt_assert(test_ok); /* try to make another request over the same connection */ test_ok = 0; req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* * if our connections are not supposed to be persistent; request * a close from the server. */ if (!persistent) evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { tt_abort_msg("couldn't make request"); } event_base_dispatch(data->base); /* make another request: request empty reply */ test_ok = 0; req = evhttp_request_new(http_request_empty_done, data->base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_connection_test(void *arg) { http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0); } static void http_persist_connection_test(void *arg) { http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 0); } static struct regress_dns_server_table search_table[] = { { "localhost", "A", "127.0.0.1", 0, 0 }, { NULL, NULL, NULL, 0, 0 } }; static void http_connection_async_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evdns_base *dns_base = NULL; ev_uint16_t portnum = 0; char address[64]; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; tt_assert(regress_dnsserver(data->base, &portnum, search_table)); dns_base = evdns_base_new(data->base, 0/* init name servers */); tt_assert(dns_base); /* Add ourself as the only nameserver, and make sure we really are * the only nameserver. */ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); evdns_base_nameserver_ip_add(dns_base, address); test_ok = 0; evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port); tt_assert(evcon); /* * At this point, we want to schedule a request to the HTTP * server using our make request method. */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { fprintf(stdout, "FAILED\n"); exit(1); } event_base_dispatch(data->base); tt_assert(test_ok); /* try to make another request over the same connection */ test_ok = 0; req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* * if our connections are not supposed to be persistent; request * a close from the server. */ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { tt_abort_msg("couldn't make request"); } event_base_dispatch(data->base); /* make another request: request empty reply */ test_ok = 0; req = evhttp_request_new(http_request_empty_done, data->base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); if (dns_base) evdns_base_free(dns_base, 0); regress_clean_dnsserver(); } static void http_autofree_connection_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req[2] = { NULL }; struct evhttp *http = http_setup(&port, data->base, 0); size_t i; test_ok = 0; evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); /* * At this point, we want to schedule two request to the HTTP * server using our make request method. */ req[0] = evhttp_request_new(http_request_empty_done, data->base); req[1] = evhttp_request_new(http_request_empty_done, data->base); /* Add the information that we care about */ for (i = 0; i < ARRAY_SIZE(req); ++i) { evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Host", "somehost"); evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Connection", "close"); evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Empty", "itis"); if (evhttp_make_request(evcon, req[i], EVHTTP_REQ_GET, "/test") == -1) { tt_abort_msg("couldn't make request"); } } /* * Tell libevent to free the connection when the request completes * We then set the evcon pointer to NULL since we don't want to free it * when this function ends. */ evhttp_connection_free_on_completion(evcon); evcon = NULL; for (i = 0; i < ARRAY_SIZE(req); ++i) event_base_dispatch(data->base); /* at this point, the http server should have no connection */ tt_assert(TAILQ_FIRST(&http->connections) == NULL); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_request_never_call(struct evhttp_request *req, void *arg) { fprintf(stdout, "FAILED\n"); exit(1); } static void http_failed_request_done(struct evhttp_request *req, void *arg) { tt_assert(!req); end: event_base_loopexit(arg, NULL); } #ifndef _WIN32 static void http_timed_out_request_done(struct evhttp_request *req, void *arg) { tt_assert(req); tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK); end: event_base_loopexit(arg, NULL); } #endif static void http_request_error_cb_with_cancel(enum evhttp_request_error error, void *arg) { if (error != EVREQ_HTTP_REQUEST_CANCEL) { fprintf(stderr, "FAILED\n"); exit(1); } test_ok = 1; { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 500 * 1000; event_base_loopexit(exit_base, &tv); } } static void http_do_cancel(evutil_socket_t fd, short what, void *arg) { struct evhttp_request *req = arg; evhttp_cancel_request(req); ++test_ok; } static void http_no_write(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg) { fprintf(stdout, "FAILED\n"); exit(1); } static void http_free_evcons(struct evhttp_connection **evcons) { struct evhttp_connection *evcon, **orig = evcons; if (!evcons) return; while ((evcon = *evcons++)) { evhttp_connection_free(evcon); } free(orig); } /** fill the backlog to force server drop packages for timeouts */ static struct evhttp_connection ** http_fill_backlog(struct event_base *base, int port) { #define BACKLOG_SIZE 256 struct evhttp_connection **evcon = malloc(sizeof(*evcon) * (BACKLOG_SIZE + 1)); int i; for (i = 0; i < BACKLOG_SIZE; ++i) { struct evhttp_request *req; evcon[i] = evhttp_connection_base_new(base, NULL, "127.0.0.1", port); tt_assert(evcon[i]); evhttp_connection_set_timeout(evcon[i], 5); req = evhttp_request_new(http_request_never_call, NULL); tt_assert(req); tt_int_op(evhttp_make_request(evcon[i], req, EVHTTP_REQ_GET, "/delay"), !=, -1); } evcon[i] = NULL; return evcon; end: fprintf(stderr, "Couldn't fill the backlog"); return NULL; } enum http_cancel_test_type { BASIC = 1, BY_HOST = 2, NO_NS = 4, INACTIVE_SERVER = 8, SERVER_TIMEOUT = 16, NS_TIMEOUT = 32, }; static struct evhttp_request * http_cancel_test_bad_request_new(enum http_cancel_test_type type, struct event_base *base) { #ifndef _WIN32 if (!(type & NO_NS) && (type & SERVER_TIMEOUT)) return evhttp_request_new(http_timed_out_request_done, base); else #endif if ((type & INACTIVE_SERVER) || (type & NO_NS)) return evhttp_request_new(http_failed_request_done, base); else return NULL; } static void http_cancel_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct bufferevent *bufev = NULL; struct timeval tv; struct evdns_base *dns_base = NULL; ev_uint16_t portnum = 0; char address[64]; struct evhttp *inactive_http = NULL; struct event_base *inactive_base = NULL; struct evhttp_connection **evcons = NULL; struct event_base *base_to_fill = data->base; enum http_cancel_test_type type = (enum http_cancel_test_type)data->setup_data; struct evhttp *http = http_setup(&port, data->base, 0); if (type & BY_HOST) { const char *timeout = (type & NS_TIMEOUT) ? "6" : "3"; tt_assert(regress_dnsserver(data->base, &portnum, search_table)); dns_base = evdns_base_new(data->base, 0/* init name servers */); tt_assert(dns_base); /** XXX: Hack the port to make timeout after resolving */ if (type & NO_NS) ++portnum; evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); evdns_base_nameserver_ip_add(dns_base, address); evdns_base_set_option(dns_base, "timeout:", timeout); evdns_base_set_option(dns_base, "initial-probe-timeout:", timeout); evdns_base_set_option(dns_base, "attempts:", "1"); } exit_base = data->base; test_ok = 0; if (type & INACTIVE_SERVER) { port = 0; inactive_base = event_base_new(); inactive_http = http_setup(&port, inactive_base, 0); base_to_fill = inactive_base; } if (type & SERVER_TIMEOUT) evcons = http_fill_backlog(base_to_fill, port); evcon = evhttp_connection_base_new( data->base, dns_base, type & BY_HOST ? "localhost" : "127.0.0.1", port); if (type & INACTIVE_SERVER) evhttp_connection_set_timeout(evcon, 5); tt_assert(evcon); bufev = evhttp_connection_get_bufferevent(evcon); /* Guarantee that we stack in connect() not after waiting EV_READ after * write() */ if (type & SERVER_TIMEOUT) evbuffer_add_cb(bufferevent_get_output(bufev), http_no_write, NULL); /* * At this point, we want to schedule a request to the HTTP * server using our make request method. */ req = evhttp_request_new(http_request_never_call, NULL); evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"), !=, -1); evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv); event_base_dispatch(data->base); if (type & NO_NS || type & INACTIVE_SERVER) tt_int_op(test_ok, ==, 2); /** no servers responses */ else tt_int_op(test_ok, ==, 3); /* try to make another request over the same connection */ test_ok = 0; http_free_evcons(evcons); if (type & SERVER_TIMEOUT) evcons = http_fill_backlog(base_to_fill, port); req = http_cancel_test_bad_request_new(type, data->base); if (!req) req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"), !=, -1); event_base_dispatch(data->base); /* make another request: request empty reply */ test_ok = 0; http_free_evcons(evcons); if (type & SERVER_TIMEOUT) evcons = http_fill_backlog(base_to_fill, port); req = http_cancel_test_bad_request_new(type, data->base); if (!req) req = evhttp_request_new(http_request_empty_done, data->base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis"); /* We give ownership of the request to the connection */ tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"), !=, -1); event_base_dispatch(data->base); end: http_free_evcons(evcons); if (bufev) evbuffer_remove_cb(bufferevent_get_output(bufev), http_no_write, NULL); if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); if (dns_base) evdns_base_free(dns_base, 0); regress_clean_dnsserver(); if (inactive_http) evhttp_free(inactive_http); if (inactive_base) event_base_free(inactive_base); } static void http_request_no_action_done(struct evhttp_request *req, void *arg) { EVUTIL_ASSERT(exit_base); event_base_loopexit(exit_base, NULL); } static void http_request_done(struct evhttp_request *req, void *arg) { const char *what = arg; if (!req) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { fprintf(stderr, "FAILED\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { fprintf(stderr, "FAILED\n"); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { fprintf(stderr, "FAILED\n"); exit(1); } test_ok = 1; EVUTIL_ASSERT(exit_base); event_base_loopexit(exit_base, NULL); } static void http_request_expect_error(struct evhttp_request *req, void *arg) { if (evhttp_request_get_response_code(req) == HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } test_ok = 1; EVUTIL_ASSERT(arg); event_base_loopexit(arg, NULL); } /* test virtual hosts */ static void http_virtual_host_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evhttp *second = NULL, *third = NULL; evutil_socket_t fd; struct bufferevent *bev; const char *http_request; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; /* virtual host */ second = evhttp_new(NULL); evhttp_set_cb(second, "/funnybunny", http_basic_cb, http); third = evhttp_new(NULL); evhttp_set_cb(third, "/blackcoffee", http_basic_cb, http); if (evhttp_add_virtual_host(http, "foo.com", second) == -1) { tt_abort_msg("Couldn't add vhost"); } if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) { tt_abort_msg("Couldn't add wildcarded vhost"); } /* add some aliases to the vhosts */ tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0); tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); /* make a request with a different host and expect an error */ req = evhttp_request_new(http_request_expect_error, data->base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/funnybunny") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_assert(test_ok == 1); test_ok = 0; /* make a request with the right host and expect a response */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/funnybunny") == -1) { fprintf(stdout, "FAILED\n"); exit(1); } event_base_dispatch(data->base); tt_assert(test_ok == 1); test_ok = 0; /* make a request with the right host and expect a response */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/blackcoffee") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_assert(test_ok == 1) test_ok = 0; /* make a request with the right host and expect a response */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/funnybunny") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_assert(test_ok == 1) test_ok = 0; /* make a request with the right host and expect a response */ req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); /* Add the Host header. This time with the optional port. */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/blackcoffee") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_assert(test_ok == 1) test_ok = 0; /* Now make a raw request with an absolute URI. */ fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, NULL); /* The host in the URI should override the Host: header */ http_request = "GET http://manolito.info/funnybunny HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(data->base); tt_int_op(test_ok, ==, 2); bufferevent_free(bev); evutil_closesocket(fd); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } /* test date header and content length */ static void http_request_empty_done(struct evhttp_request *req, void *arg) { if (!req) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) { fprintf(stderr, "FAILED\n"); exit(1); } if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"), "0")) { fprintf(stderr, "FAILED\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) { fprintf(stderr, "FAILED\n"); exit(1); } test_ok = 1; EVUTIL_ASSERT(arg); event_base_loopexit(arg, NULL); } /* * HTTP DISPATCHER test */ void http_dispatcher_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = evbuffer_new(); TT_BLATHER(("%s: called\n", __func__)); evbuffer_add_printf(evb, "DISPATCHER_TEST"); evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); } static void http_dispatcher_test_done(struct evhttp_request *req, void *arg) { struct event_base *base = arg; const char *what = "DISPATCHER_TEST"; if (!req) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { fprintf(stderr, "FAILED (content type)\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { fprintf(stderr, "FAILED (length %lu vs %lu)\n", (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { fprintf(stderr, "FAILED (data)\n"); exit(1); } test_ok = 1; event_base_loopexit(base, NULL); } static void http_dispatcher_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); /* also bind to local host */ evhttp_connection_set_local_address(evcon, "127.0.0.1"); /* * At this point, we want to schedule an HTTP GET request * server using our make request method. */ req = evhttp_request_new(http_dispatcher_test_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } /* * HTTP POST test. */ void http_postrequest_done(struct evhttp_request *, void *); #define POST_DATA "Okay. Not really printf" static void http_post_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); /* * At this point, we want to schedule an HTTP POST request * server using our make request method. */ req = evhttp_request_new(http_postrequest_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA); if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_int_op(test_ok, ==, 1); test_ok = 0; req = evhttp_request_new(http_postrequest_done, data->base); tt_assert(req); /* Now try with 100-continue. */ /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue"); evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA); if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_int_op(test_ok, ==, 1); evhttp_connection_free(evcon); evhttp_free(http); end: ; } void http_post_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb; TT_BLATHER(("%s: called\n", __func__)); /* Yes, we are expecting a post request */ if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) { fprintf(stdout, "FAILED (post type)\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) { fprintf(stdout, "FAILED (length: %lu vs %lu)\n", (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA)); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) { fprintf(stdout, "FAILED (data)\n"); fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1)); fprintf(stdout, "Want:%s\n", POST_DATA); exit(1); } evb = evbuffer_new(); evbuffer_add_printf(evb, BASIC_REQUEST_BODY); evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); evbuffer_free(evb); } void http_postrequest_done(struct evhttp_request *req, void *arg) { const char *what = BASIC_REQUEST_BODY; struct event_base *base = arg; if (req == NULL) { fprintf(stderr, "FAILED (timeout)\n"); exit(1); } if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED (response code)\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { fprintf(stderr, "FAILED (content type)\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { fprintf(stderr, "FAILED (length %lu vs %lu)\n", (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { fprintf(stderr, "FAILED (data)\n"); exit(1); } test_ok = 1; event_base_loopexit(base, NULL); } /* * HTTP PUT test, basically just like POST, but ... */ void http_putrequest_done(struct evhttp_request *, void *); #define PUT_DATA "Hi, I'm some PUT data" static void http_put_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); /* * Schedule the HTTP PUT request */ req = evhttp_request_new(http_putrequest_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost"); evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA); if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); evhttp_connection_free(evcon); evhttp_free(http); tt_int_op(test_ok, ==, 1); end: ; } void http_put_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb; TT_BLATHER(("%s: called\n", __func__)); /* Expecting a PUT request */ if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) { fprintf(stdout, "FAILED (put type)\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) { fprintf(stdout, "FAILED (length: %lu vs %lu)\n", (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA)); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) { fprintf(stdout, "FAILED (data)\n"); fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1)); fprintf(stdout, "Want:%s\n", PUT_DATA); exit(1); } evb = evbuffer_new(); evbuffer_add_printf(evb, "That ain't funny"); evhttp_send_reply(req, HTTP_OK, "Everything is great", evb); evbuffer_free(evb); } void http_putrequest_done(struct evhttp_request *req, void *arg) { struct event_base *base = arg; const char *what = "That ain't funny"; if (req == NULL) { fprintf(stderr, "FAILED (timeout)\n"); exit(1); } if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED (response code)\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) { fprintf(stderr, "FAILED (content type)\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) { fprintf(stderr, "FAILED (length %lu vs %lu)\n", (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what)); exit(1); } if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) { fprintf(stderr, "FAILED (data)\n"); exit(1); } test_ok = 1; event_base_loopexit(base, NULL); } static void http_failure_readcb(struct bufferevent *bev, void *arg) { const char *what = "400 Bad Request"; if (evbuffer_contains(bufferevent_get_input(bev), what)) { test_ok = 2; bufferevent_disable(bev, EV_READ); event_base_loopexit(arg, NULL); } } /* * Testing that the HTTP server can deal with a malformed request. */ static void http_failure_test(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev; evutil_socket_t fd = EVUTIL_INVALID_SOCKET; const char *http_request; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); bufferevent_setcb(bev, http_failure_readcb, http_writecb, http_errorcb, data->base); http_request = "illegal request\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(data->base); bufferevent_free(bev); evhttp_free(http); tt_int_op(test_ok, ==, 2); end: if (fd >= 0) evutil_closesocket(fd); } static void close_detect_done(struct evhttp_request *req, void *arg) { struct timeval tv; tt_assert(req); tt_assert(evhttp_request_get_response_code(req) == HTTP_OK); test_ok = 1; end: evutil_timerclear(&tv); tv.tv_usec = 150000; event_base_loopexit(arg, &tv); } static void close_detect_launch(evutil_socket_t fd, short what, void *arg) { struct evhttp_connection *evcon = arg; struct event_base *base = evhttp_connection_get_base(evcon); struct evhttp_request *req; req = evhttp_request_new(close_detect_done, base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { tt_fail_msg("Couldn't make request"); } } static void close_detect_cb(struct evhttp_request *req, void *arg) { struct evhttp_connection *evcon = arg; struct event_base *base = evhttp_connection_get_base(evcon); struct timeval tv; if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) { tt_abort_msg("Failed"); } evutil_timerclear(&tv); tv.tv_sec = 0; /* longer than the http time out */ tv.tv_usec = 600000; /* longer than the http time out */ /* launch a new request on the persistent connection in .3 seconds */ event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv); end: ; } static void http_close_detection_(struct basic_test_data *data, int with_delay) { ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; const struct timeval sec_tenth = { 0, 100000 }; struct evhttp *http = http_setup(&port, data->base, 0); test_ok = 0; /* .1 second timeout */ evhttp_set_timeout_tv(http, &sec_tenth); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); evhttp_connection_set_timeout_tv(evcon, &sec_tenth); tt_assert(evcon); delayed_client = evcon; /* * At this point, we want to schedule a request to the HTTP * server using our make request method. */ req = evhttp_request_new(close_detect_cb, evcon); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) { tt_abort_msg("couldn't make request"); } event_base_dispatch(data->base); /* at this point, the http server should have no connection */ tt_assert(TAILQ_FIRST(&http->connections) == NULL); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_close_detection_test(void *arg) { http_close_detection_(arg, 0); } static void http_close_detection_delay_test(void *arg) { http_close_detection_(arg, 1); } static void http_highport_test(void *arg) { struct basic_test_data *data = arg; int i = -1; struct evhttp *myhttp = NULL; /* Try a few different ports */ for (i = 0; i < 50; ++i) { myhttp = evhttp_new(data->base); if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) { test_ok = 1; evhttp_free(myhttp); return; } evhttp_free(myhttp); } tt_fail_msg("Couldn't get a high port"); } static void http_bad_header_test(void *ptr) { struct evkeyvalq headers; TAILQ_INIT(&headers); tt_want(evhttp_add_header(&headers, "One", "Two") == 0); tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0); tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1); tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1); tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1); tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1); evhttp_clear_headers(&headers); } static int validate_header( const struct evkeyvalq* headers, const char *key, const char *value) { const char *real_val = evhttp_find_header(headers, key); tt_assert(real_val != NULL); tt_want(strcmp(real_val, value) == 0); end: return (0); } static void http_parse_query_test(void *ptr) { struct evkeyvalq headers; int r; TAILQ_INIT(&headers); r = evhttp_parse_query("http://www.test.com/?q=test", &headers); tt_want(validate_header(&headers, "q", "test") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers); tt_want(validate_header(&headers, "q", "test") == 0); tt_want(validate_header(&headers, "foo", "bar") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers); tt_want(validate_header(&headers, "q", "test foo") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers); tt_want(validate_header(&headers, "q", "test\nfoo") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers); tt_want(validate_header(&headers, "q", "test\rfoo") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers); tt_int_op(r, ==, -1); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers); tt_want(validate_header(&headers, "q", "test this") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers); tt_int_op(r, ==, 0); tt_want(validate_header(&headers, "q", "test") == 0); tt_want(validate_header(&headers, "q2", "foo") == 0); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers); tt_int_op(r, ==, -1); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers); tt_int_op(r, ==, -1); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers); tt_int_op(r, ==, -1); evhttp_clear_headers(&headers); r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers); tt_int_op(r, ==, 0); tt_want(validate_header(&headers, "q", "") == 0); tt_want(validate_header(&headers, "q2", "") == 0); tt_want(validate_header(&headers, "q3", "") == 0); evhttp_clear_headers(&headers); end: evhttp_clear_headers(&headers); } static void http_parse_query_str_test(void *ptr) { struct evkeyvalq headers; int r; TAILQ_INIT(&headers); r = evhttp_parse_query_str("http://www.test.com/?q=test", &headers); tt_assert(evhttp_find_header(&headers, "q") == NULL); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); r = evhttp_parse_query_str("q=test", &headers); tt_want(validate_header(&headers, "q", "test") == 0); tt_int_op(r, ==, 0); evhttp_clear_headers(&headers); end: evhttp_clear_headers(&headers); } static void http_parse_uri_test(void *ptr) { const int nonconform = (ptr != NULL); const unsigned parse_flags = nonconform ? EVHTTP_URI_NONCONFORMANT : 0; struct evhttp_uri *uri = NULL; char url_tmp[4096]; #define URI_PARSE(uri) \ evhttp_uri_parse_with_flags((uri), parse_flags) #define TT_URI(want) do { \ char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \ tt_want(ret != NULL); \ tt_want(ret == url_tmp); \ if (strcmp(ret,want) != 0) \ TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \ } while(0) tt_want(evhttp_uri_join(NULL, 0, 0) == NULL); tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL); tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL); /* bad URIs: parsing */ #define BAD(s) do { \ if (URI_PARSE(s) != NULL) \ TT_FAIL(("Expected error parsing \"%s\"",s)); \ } while(0) /* Nonconformant URIs we can parse: parsing */ #define NCF(s) do { \ uri = URI_PARSE(s); \ if (uri != NULL && !nonconform) { \ TT_FAIL(("Expected error parsing \"%s\"",s)); \ } else if (uri == NULL && nonconform) { \ TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \ s)); \ } \ if (uri) { \ tt_want(evhttp_uri_join(uri, url_tmp, \ sizeof(url_tmp))); \ evhttp_uri_free(uri); \ } \ } while(0) NCF("http://www.test.com/ why hello"); NCF("http://www.test.com/why-hello\x01"); NCF("http://www.test.com/why-hello?\x01"); NCF("http://www.test.com/why-hello#\x01"); BAD("http://www.\x01.test.com/why-hello"); BAD("http://www.%7test.com/why-hello"); NCF("http://www.test.com/why-hell%7o"); BAD("h%3ttp://www.test.com/why-hello"); NCF("http://www.test.com/why-hello%7"); NCF("http://www.test.com/why-hell%7o"); NCF("http://www.test.com/foo?ba%r"); NCF("http://www.test.com/foo#ba%r"); BAD("99:99/foo"); BAD("http://www.test.com:999x/"); BAD("http://www.test.com:x/"); BAD("http://[hello-there]/"); BAD("http://[::1]]/"); BAD("http://[::1/"); BAD("http://[foob/"); BAD("http://[/"); BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:" "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/"); BAD("http://[vX.foo]/"); BAD("http://[vX.foo]/"); BAD("http://[v.foo]/"); BAD("http://[v5.fo%o]/"); BAD("http://[v5X]/"); BAD("http://[v5]/"); BAD("http://[]/"); BAD("http://f\x01red@www.example.com/"); BAD("http://f%0red@www.example.com/"); BAD("http://www.example.com:9999999999999999999999999999999999999/"); BAD("http://www.example.com:hihi/"); BAD("://www.example.com/"); /* bad URIs: joining */ uri = evhttp_uri_new(); tt_want(0==evhttp_uri_set_host(uri, "www.example.com")); tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL); /* not enough space: */ tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL); /* host is set, but path doesn't start with "/": */ tt_want(0==evhttp_uri_set_path(uri, "hi_mom")); tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL); tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL); tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL); evhttp_uri_free(uri); uri = URI_PARSE("mailto:foo@bar"); tt_want(uri != NULL); tt_want(evhttp_uri_get_host(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto")); tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar")); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("mailto:foo@bar"); evhttp_uri_free(uri); uri = evhttp_uri_new(); /* Bad URI usage: setting invalid values */ tt_want(-1 == evhttp_uri_set_scheme(uri,"")); tt_want(-1 == evhttp_uri_set_scheme(uri,"33")); tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!")); tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@")); tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]")); tt_want(-1 == evhttp_uri_set_host(uri,"[")); tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com")); tt_want(-1 == evhttp_uri_set_port(uri,-3)); tt_want(-1 == evhttp_uri_set_path(uri,"hello?world")); tt_want(-1 == evhttp_uri_set_query(uri,"hello#world")); tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world")); /* Valid URI usage: setting valid values */ tt_want(0 == evhttp_uri_set_scheme(uri,"http")); tt_want(0 == evhttp_uri_set_scheme(uri,NULL)); tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass")); tt_want(0 == evhttp_uri_set_userinfo(uri,NULL)); tt_want(0 == evhttp_uri_set_host(uri,"www.example.com")); tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4")); tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]")); tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]")); tt_want(0 == evhttp_uri_set_host(uri,NULL)); tt_want(0 == evhttp_uri_set_host(uri,"")); tt_want(0 == evhttp_uri_set_port(uri, -1)); tt_want(0 == evhttp_uri_set_port(uri, 80)); tt_want(0 == evhttp_uri_set_port(uri, 65535)); tt_want(0 == evhttp_uri_set_path(uri, "")); tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html")); tt_want(0 == evhttp_uri_set_path(uri, NULL)); tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2")); tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg")); tt_want(0 == evhttp_uri_set_query(uri, "")); tt_want(0 == evhttp_uri_set_query(uri, NULL)); tt_want(0 == evhttp_uri_set_fragment(uri, "")); tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am")); tt_want(0 == evhttp_uri_set_fragment(uri, NULL)); evhttp_uri_free(uri); /* Valid parsing */ uri = URI_PARSE("http://www.test.com/?q=t%33est"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://www.test.com/?q=t%33est"); evhttp_uri_free(uri); uri = URI_PARSE("http://%77ww.test.com"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://%77ww.test.com"); evhttp_uri_free(uri); uri = URI_PARSE("http://www.test.com?q=test"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://www.test.com?q=test"); evhttp_uri_free(uri); uri = URI_PARSE("http://www.test.com#fragment"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment"); TT_URI("http://www.test.com#fragment"); evhttp_uri_free(uri); uri = URI_PARSE("http://8000/"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://8000/"); evhttp_uri_free(uri); uri = URI_PARSE("http://:8000/"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == 8000); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://:8000/"); evhttp_uri_free(uri); uri = URI_PARSE("http://www.test.com:/"); /* empty port */ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want_str_op(evhttp_uri_get_path(uri), ==, "/"); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://www.test.com/"); evhttp_uri_free(uri); uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */ tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("http://www.test.com"); evhttp_uri_free(uri); uri = URI_PARSE("ftp://www.test.com/?q=test"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("ftp://www.test.com/?q=test"); evhttp_uri_free(uri); uri = URI_PARSE("ftp://[::1]:999/?q=test"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == 999); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("ftp://[::1]:999/?q=test"); evhttp_uri_free(uri); uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("ftp://[ff00::127.0.0.1]/?q=test"); evhttp_uri_free(uri); uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test"); evhttp_uri_free(uri); uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); tt_want(evhttp_uri_get_port(uri) == 42); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0); tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0); TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment"); evhttp_uri_free(uri); uri = URI_PARSE("scheme://user@foo.com/#fragment"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0); TT_URI("scheme://user@foo.com/#fragment"); evhttp_uri_free(uri); uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0); tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0); tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0); TT_URI("scheme://%75ser@foo.com/#frag@ment"); evhttp_uri_free(uri); uri = URI_PARSE("file:///some/path/to/the/file"); tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("file:///some/path/to/the/file"); evhttp_uri_free(uri); uri = URI_PARSE("///some/path/to/the-file"); tt_want(uri != NULL); tt_want(evhttp_uri_get_scheme(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("///some/path/to/the-file"); evhttp_uri_free(uri); uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred"); tt_want(uri != NULL); tt_want(evhttp_uri_get_scheme(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_host(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0); tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0); TT_URI("/s:ome/path/to/the-file?q=99#fred"); evhttp_uri_free(uri); uri = URI_PARSE("relative/path/with/co:lon"); tt_want(uri != NULL); tt_want(evhttp_uri_get_scheme(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_host(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(evhttp_uri_get_fragment(uri) == NULL); TT_URI("relative/path/with/co:lon"); evhttp_uri_free(uri); uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed"); tt_want(uri != NULL); tt_want(evhttp_uri_get_scheme(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_host(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0); tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0); tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0); TT_URI("bob?q=99&q2=q?33#fr?ed"); evhttp_uri_free(uri); uri = URI_PARSE("#fr?ed"); tt_want(uri != NULL); tt_want(evhttp_uri_get_scheme(uri) == NULL); tt_want(evhttp_uri_get_userinfo(uri) == NULL); tt_want(evhttp_uri_get_host(uri) == NULL); tt_want(evhttp_uri_get_port(uri) == -1); tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0); tt_want(evhttp_uri_get_query(uri) == NULL); tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0); TT_URI("#fr?ed"); evhttp_uri_free(uri); #undef URI_PARSE #undef TT_URI #undef BAD } static void http_uriencode_test(void *ptr) { char *s=NULL, *s2=NULL; size_t sz; int bytes_decoded; #define ENC(from,want,plus) do { \ s = evhttp_uriencode((from), -1, (plus)); \ tt_assert(s); \ tt_str_op(s,==,(want)); \ sz = -1; \ s2 = evhttp_uridecode((s), (plus), &sz); \ tt_assert(s2); \ tt_str_op(s2,==,(from)); \ tt_int_op(sz,==,strlen(from)); \ free(s); \ free(s2); \ s = s2 = NULL; \ } while (0) #define DEC(from,want,dp) do { \ s = evhttp_uridecode((from),(dp),&sz); \ tt_assert(s); \ tt_str_op(s,==,(want)); \ tt_int_op(sz,==,strlen(want)); \ free(s); \ s = NULL; \ } while (0) #define OLD_DEC(from,want) do { \ s = evhttp_decode_uri((from)); \ tt_assert(s); \ tt_str_op(s,==,(want)); \ free(s); \ s = NULL; \ } while (0) ENC("Hello", "Hello",0); ENC("99", "99",0); ENC("", "",0); ENC( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0); ENC(" ", "%20",0); ENC(" ", "+",1); ENC("\xff\xf0\xe0", "%FF%F0%E0",0); ENC("\x01\x19", "%01%19",1); ENC("http://www.ietf.org/rfc/rfc3986.txt", "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1); ENC("1+2=3", "1%2B2%3D3",1); ENC("1+2=3", "1%2B2%3D3",0); /* Now try encoding with internal NULs. */ s = evhttp_uriencode("hello\0world", 11, 0); tt_assert(s); tt_str_op(s,==,"hello%00world"); free(s); s = NULL; /* Now try decoding just part of string. */ s = malloc(6 + 1 /* NUL byte */); bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0); tt_assert(s); tt_int_op(bytes_decoded,==,6); tt_str_op(s,==,"hello%"); free(s); s = NULL; /* Now try out some decoding cases that we don't generate with * encode_uri: Make sure that malformed stuff doesn't crash... */ DEC("%%xhello th+ere \xff", "%%xhello th+ere \xff", 0); /* Make sure plus decoding works */ DEC("plus+should%20work+", "plus should work ",1); /* Try some lowercase hex */ DEC("%f0%a0%b0", "\xf0\xa0\xb0",1); /* Try an internal NUL. */ sz = 0; s = evhttp_uridecode("%00%00x%00%00", 1, &sz); tt_int_op(sz,==,5); tt_assert(!memcmp(s, "\0\0x\0\0", 5)); free(s); s = NULL; /* Try with size == NULL */ sz = 0; s = evhttp_uridecode("%00%00x%00%00", 1, NULL); tt_assert(!memcmp(s, "\0\0x\0\0", 5)); free(s); s = NULL; /* Test out the crazy old behavior of the deprecated * evhttp_decode_uri */ OLD_DEC("http://example.com/normal+path/?key=val+with+spaces", "http://example.com/normal+path/?key=val with spaces"); end: if (s) free(s); if (s2) free(s2); #undef ENC #undef DEC #undef OLD_DEC } static void http_base_test(void *ptr) { struct event_base *base = NULL; struct bufferevent *bev; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0; struct evhttp *http; test_ok = 0; base = event_base_new(); tt_assert(base); http = http_setup(&port, base, 0); fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = bufferevent_socket_new(base, fd, 0); bufferevent_setcb(bev, http_readcb, http_writecb, http_errorcb, base); bufferevent_base_set(base, bev); http_request = "GET /test HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); event_base_dispatch(base); bufferevent_free(bev); evutil_closesocket(fd); evhttp_free(http); tt_int_op(test_ok, ==, 2); end: if (base) event_base_free(base); } /* * the server is just going to close the connection if it times out during * reading the headers. */ static void http_incomplete_readcb(struct bufferevent *bev, void *arg) { test_ok = -1; event_base_loopexit(exit_base,NULL); } static void http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg) { /** For ssl */ if (what & BEV_EVENT_CONNECTED) return; if (what == (BEV_EVENT_READING|BEV_EVENT_EOF)) test_ok++; else test_ok = -2; event_base_loopexit(exit_base,NULL); } static void http_incomplete_writecb(struct bufferevent *bev, void *arg) { if (arg != NULL) { evutil_socket_t fd = *(evutil_socket_t *)arg; /* terminate the write side to simulate EOF */ shutdown(fd, EVUTIL_SHUT_WR); } if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { /* enable reading of the reply */ bufferevent_enable(bev, EV_READ); test_ok++; } } static void http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl) { struct bufferevent *bev; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0; struct timeval tv_start, tv_end; struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); exit_base = data->base; test_ok = 0; evhttp_set_timeout(http, 1); fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = create_bev(data->base, fd, ssl, 0); bufferevent_setcb(bev, http_incomplete_readcb, http_incomplete_writecb, http_incomplete_errorcb, use_timeout ? NULL : &fd); http_request = "GET /test HTTP/1.1\r\n" "Host: somehost\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(data->base); evutil_gettimeofday(&tv_end, NULL); evutil_timersub(&tv_end, &tv_start, &tv_end); bufferevent_free(bev); if (use_timeout) { evutil_closesocket(fd); fd = EVUTIL_INVALID_SOCKET; } evhttp_free(http); if (use_timeout && tv_end.tv_sec >= 3) { tt_abort_msg("time"); } else if (!use_timeout && tv_end.tv_sec >= 1) { /* we should be done immediately */ tt_abort_msg("time"); } tt_int_op(test_ok, ==, 2); end: if (fd >= 0) evutil_closesocket(fd); } static void http_incomplete_test(void *arg) { http_incomplete_test_(arg, 0, 0); } static void http_incomplete_timeout_test(void *arg) { http_incomplete_test_(arg, 1, 0); } /* * the server is going to reply with chunked data. */ static void http_chunked_readcb(struct bufferevent *bev, void *arg) { /* nothing here */ } static void http_chunked_errorcb(struct bufferevent *bev, short what, void *arg) { struct evhttp_request *req = NULL; /** SSL */ if (what & BEV_EVENT_CONNECTED) return; if (!test_ok) goto out; test_ok = -1; if ((what & BEV_EVENT_EOF) != 0) { const char *header; enum message_read_status done; req = evhttp_request_new(NULL, NULL); /* req->kind = EVHTTP_RESPONSE; */ done = evhttp_parse_firstline_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; done = evhttp_parse_headers_(req, bufferevent_get_input(bev)); if (done != ALL_DATA_READ) goto out; header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding"); if (header == NULL || strcmp(header, "chunked")) goto out; header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection"); if (header == NULL || strcmp(header, "close")) goto out; header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); if (header == NULL) goto out; /* 13 chars */ if (strcmp(header, "d")) { free((void*)header); goto out; } free((void*)header); if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13), "This is funny", 13)) goto out; evbuffer_drain(bufferevent_get_input(bev), 13 + 2); header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); if (header == NULL) goto out; /* 18 chars */ if (strcmp(header, "12")) goto out; free((char *)header); if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18), "but not hilarious.", 18)) goto out; evbuffer_drain(bufferevent_get_input(bev), 18 + 2); header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); if (header == NULL) goto out; /* 8 chars */ if (strcmp(header, "8")) { free((void*)header); goto out; } free((char *)header); if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8), "bwv 1052.", 8)) goto out; evbuffer_drain(bufferevent_get_input(bev), 8 + 2); header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF); if (header == NULL) goto out; /* 0 chars */ if (strcmp(header, "0")) { free((void*)header); goto out; } free((void *)header); test_ok = 2; } out: if (req) evhttp_request_free(req); event_base_loopexit(arg, NULL); } static void http_chunked_writecb(struct bufferevent *bev, void *arg) { if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) { /* enable reading of the reply */ bufferevent_enable(bev, EV_READ); test_ok++; } } static void http_chunked_request_done(struct evhttp_request *req, void *arg) { if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } if (evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding") == NULL) { fprintf(stderr, "FAILED\n"); exit(1); } if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) { fprintf(stderr, "FAILED\n"); exit(1); } if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8), "This is funnybut not hilarious.bwv 1052", 13 + 18 + 8)) { fprintf(stderr, "FAILED\n"); exit(1); } test_ok = 1; event_base_loopexit(arg, NULL); } static void http_chunk_out_test_impl(void *arg, int ssl) { struct basic_test_data *data = arg; struct bufferevent *bev = NULL; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0; struct timeval tv_start, tv_end; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; int i; struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); exit_base = data->base; test_ok = 0; fd = http_connect("127.0.0.1", port); tt_assert(fd != EVUTIL_INVALID_SOCKET); /* Stupid thing to send a request */ bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, http_chunked_readcb, http_chunked_writecb, http_chunked_errorcb, data->base); http_request = "GET /chunked HTTP/1.1\r\n" "Host: somehost\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(data->base); bufferevent_free(bev); bev = NULL; evutil_gettimeofday(&tv_end, NULL); evutil_timersub(&tv_end, &tv_start, &tv_end); tt_int_op(tv_end.tv_sec, <, 1); tt_int_op(test_ok, ==, 2); /* now try again with the regular connection object */ bev = create_bev(data->base, -1, ssl, BEV_OPT_CLOSE_ON_FREE); evcon = evhttp_connection_base_bufferevent_new( data->base, NULL, bev, "127.0.0.1", port); tt_assert(evcon); /* make two requests to check the keepalive behavior */ for (i = 0; i < 2; i++) { test_ok = 0; req = evhttp_request_new(http_chunked_request_done, data->base); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_assert(test_ok == 1); } end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_chunk_out_test(void *arg) { http_chunk_out_test_impl(arg, 0); } static void http_stream_out_test_impl(void *arg, int ssl) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct bufferevent *bev; struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); test_ok = 0; exit_base = data->base; bev = create_bev(data->base, -1, ssl, 0); evcon = evhttp_connection_base_bufferevent_new( data->base, NULL, bev, "127.0.0.1", port); tt_assert(evcon); /* * At this point, we want to schedule a request to the HTTP * server using our make request method. */ req = evhttp_request_new(http_request_done, (void *)"This is funnybut not hilarious.bwv 1052"); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_stream_out_test(void *arg) { http_stream_out_test_impl(arg, 0); } static void http_stream_in_chunk(struct evhttp_request *req, void *arg) { struct evbuffer *reply = arg; if (evhttp_request_get_response_code(req) != HTTP_OK) { fprintf(stderr, "FAILED\n"); exit(1); } evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req)); } static void http_stream_in_done(struct evhttp_request *req, void *arg) { if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) { fprintf(stderr, "FAILED\n"); exit(1); } event_base_loopexit(exit_base, NULL); } /** * Makes a request and reads the response in chunks. */ static void http_stream_in_test_(struct basic_test_data *data, char const *url, size_t expected_len, char const *expected) { struct evhttp_connection *evcon; struct evbuffer *reply = evbuffer_new(); struct evhttp_request *req = NULL; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); exit_base = data->base; evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port); tt_assert(evcon); req = evhttp_request_new(http_stream_in_done, reply); evhttp_request_set_chunked_cb(req, http_stream_in_chunk); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); if (evbuffer_get_length(reply) != expected_len) { TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n", (unsigned long)evbuffer_get_length(reply), (unsigned long)expected_len, (char*)evbuffer_pullup(reply, -1))); } if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) { tt_abort_msg("Memory mismatch"); } test_ok = 1; end: if (reply) evbuffer_free(reply); if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_stream_in_test(void *arg) { http_stream_in_test_(arg, "/chunked", 13 + 18 + 8, "This is funnybut not hilarious.bwv 1052"); http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY), BASIC_REQUEST_BODY); } static void http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg) { tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK); end: evhttp_cancel_request(req); event_base_loopexit(arg, NULL); } static void http_stream_in_cancel_done(struct evhttp_request *req, void *arg) { /* should never be called */ tt_fail_msg("In cancel done"); } static void http_stream_in_cancel_test(void *arg) { struct basic_test_data *data = arg; struct evhttp_connection *evcon; struct evhttp_request *req = NULL; ev_uint16_t port = 0; struct evhttp *http = http_setup(&port, data->base, 0); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); req = evhttp_request_new(http_stream_in_cancel_done, data->base); evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk); /* We give ownership of the request to the connection */ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); test_ok = 1; end: evhttp_connection_free(evcon); evhttp_free(http); } static void http_connection_fail_done(struct evhttp_request *req, void *arg) { struct evhttp_connection *evcon = arg; struct event_base *base = evhttp_connection_get_base(evcon); /* An ENETUNREACH error results in an unrecoverable * evhttp_connection error (see evhttp_connection_fail_()). The * connection will be reset, and the user will be notified with a NULL * req parameter. */ tt_assert(!req); evhttp_connection_free(evcon); test_ok = 1; end: event_base_loopexit(base, NULL); } /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH * error on connection. */ static void http_connection_fail_test_impl(void *arg, int ssl) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct bufferevent *bev; struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0); exit_base = data->base; test_ok = 0; /* auto detect a port */ evhttp_free(http); bev = create_bev(data->base, -1, ssl, 0); /* Pick an unroutable address. This administratively scoped multicast * address should do when working with TCP. */ evcon = evhttp_connection_base_bufferevent_new( data->base, NULL, bev, "239.10.20.30", 80); tt_assert(evcon); /* * At this point, we want to schedule an HTTP GET request * server using our make request method. */ req = evhttp_request_new(http_connection_fail_done, evcon); tt_assert(req); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) { tt_abort_msg("Couldn't make request"); } event_base_dispatch(data->base); tt_int_op(test_ok, ==, 1); end: ; } static void http_connection_fail_test(void *arg) { http_connection_fail_test_impl(arg, 0); } static void http_connection_retry_done(struct evhttp_request *req, void *arg) { tt_assert(req); tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK); if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) { tt_abort_msg("(content type)\n"); } tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0); test_ok = 1; end: event_base_loopexit(arg,NULL); } struct http_server { ev_uint16_t port; int ssl; struct evhttp *http; }; static struct event_base *http_make_web_server_base=NULL; static void http_make_web_server(evutil_socket_t fd, short what, void *arg) { struct http_server *hs = (struct http_server *)arg; hs->http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0); } static void http_simple_test_impl(void *arg, int ssl, int dirty, const char *uri) { struct basic_test_data *data = arg; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct bufferevent *bev; struct http_server hs = { 0, ssl, NULL, }; struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0); exit_base = data->base; test_ok = 0; bev = create_bev(data->base, -1, ssl, 0); #ifdef EVENT__HAVE_OPENSSL bufferevent_openssl_set_allow_dirty_shutdown(bev, dirty); #endif evcon = evhttp_connection_base_bufferevent_new( data->base, NULL, bev, "127.0.0.1", hs.port); tt_assert(evcon); evhttp_connection_set_local_address(evcon, "127.0.0.1"); req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY); tt_assert(req); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri) == -1) tt_abort_msg("Couldn't make request"); event_base_dispatch(data->base); tt_int_op(test_ok, ==, 1); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_simple_test(void *arg) { http_simple_test_impl(arg, 0, 0, "/test"); } static void http_simple_nonconformant_test(void *arg) { http_simple_test_impl(arg, 0, 0, "/test nonconformant"); } static void http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl) { struct basic_test_data *data = arg; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; struct timeval tv, tv_start, tv_end; struct bufferevent *bev; struct http_server hs = { 0, ssl, NULL, }; struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0); exit_base = data->base; test_ok = 0; /* auto detect a port */ evhttp_free(http); bev = create_bev(data->base, -1, ssl, 0); evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port); tt_assert(evcon); if (dns_base) tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR)); evhttp_connection_set_timeout(evcon, 1); /* also bind to local host */ evhttp_connection_set_local_address(evcon, "127.0.0.1"); /* * At this point, we want to schedule an HTTP GET request * server using our make request method. */ req = evhttp_request_new(http_connection_retry_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) { tt_abort_msg("Couldn't make request"); } evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(data->base); evutil_gettimeofday(&tv_end, NULL); evutil_timersub(&tv_end, &tv_start, &tv_end); tt_int_op(tv_end.tv_sec, <, 1); tt_int_op(test_ok, ==, 1); /* * now test the same but with retries */ test_ok = 0; /** Shutdown dns server, to test conn_address reusing */ if (dns_base) regress_clean_dnsserver(); { const struct timeval tv_timeout = { 0, 500000 }; const struct timeval tv_retry = { 0, 500000 }; evhttp_connection_set_timeout_tv(evcon, &tv_timeout); evhttp_connection_set_initial_retry_tv(evcon, &tv_retry); } evhttp_connection_set_retries(evcon, 1); req = evhttp_request_new(http_connection_retry_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) { tt_abort_msg("Couldn't make request"); } evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(data->base); evutil_gettimeofday(&tv_end, NULL); /* fails fast, .5 sec to wait to retry, fails fast again. */ test_timeval_diff_leq(&tv_start, &tv_end, 500, 200); tt_assert(test_ok == 1); /* * now test the same but with retries and give it a web server * at the end */ test_ok = 0; evhttp_connection_set_timeout(evcon, 1); evhttp_connection_set_retries(evcon, 3); req = evhttp_request_new(http_dispatcher_test_done, data->base); tt_assert(req); /* Add the information that we care about */ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost"); if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) { tt_abort_msg("Couldn't make request"); } /* start up a web server .2 seconds after the connection tried * to send a request */ evutil_timerclear(&tv); tv.tv_usec = 200000; http_make_web_server_base = data->base; event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv); evutil_gettimeofday(&tv_start, NULL); event_base_dispatch(data->base); evutil_gettimeofday(&tv_end, NULL); /* We'll wait twice as long as we did last time. */ test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400); tt_int_op(test_ok, ==, 1); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(hs.http); } static void http_connection_retry_conn_address_test_impl(void *arg, int ssl) { struct basic_test_data *data = arg; ev_uint16_t portnum = 0; struct evdns_base *dns_base = NULL; char address[64]; tt_assert(regress_dnsserver(data->base, &portnum, search_table)); dns_base = evdns_base_new(data->base, 0/* init name servers */); tt_assert(dns_base); /* Add ourself as the only nameserver, and make sure we really are * the only nameserver. */ evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum); evdns_base_nameserver_ip_add(dns_base, address); http_connection_retry_test_basic(arg, "localhost", dns_base, ssl); end: if (dns_base) evdns_base_free(dns_base, 0); /** dnsserver will be cleaned in http_connection_retry_test_basic() */ } static void http_connection_retry_conn_address_test(void *arg) { http_connection_retry_conn_address_test_impl(arg, 0); } static void http_connection_retry_test_impl(void *arg, int ssl) { http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl); } static void http_connection_retry_test(void *arg) { http_connection_retry_test_impl(arg, 0); } static void http_primitives(void *ptr) { char *escaped = NULL; struct evhttp *http = NULL; escaped = evhttp_htmlescape("