lldpd-0.7.7/0000755000076400001440000000000012237716103007627 500000000000000lldpd-0.7.7/libevent/0000755000076400001440000000000012237716102011436 500000000000000lldpd-0.7.7/libevent/evport.c0000644000076400001440000002744412074262762013063 00000000000000/* * 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 #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" /* * Default value for ed_nevents, which is the maximum file descriptor number we * can handle. If an event comes in for a file descriptor F > nevents, we will * grow the array of file descriptors, doubling its size. */ #define DEFAULT_NFDS 16 /* * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on * any particular call. You can speed things up by increasing this, but it will * (obviously) require more memory. */ #define EVENTS_PER_GETN 8 /* * 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 { short fdi_what; /* combinations of EV_READ and EV_WRITE */ }; #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 */ int ed_nevents; /* number of allocated fdi's */ struct fd_info *ed_fds; /* allocated fdi table */ /* fdi's that we need to reassoc */ int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */ }; 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 *); const struct eventop evportops = { "evport", evport_init, evport_add, evport_del, evport_dispatch, evport_dealloc, 1, /* need reinit */ 0, /* features */ 0, /* fdinfo length */ }; /* * Initialize the event port implementation. */ static void* evport_init(struct event_base *base) { struct evport_data *evpd; int i; if (!(evpd = mm_calloc(1, sizeof(struct evport_data)))) return (NULL); if ((evpd->ed_port = port_create()) == -1) { mm_free(evpd); return (NULL); } /* * Initialize file descriptor structure */ evpd->ed_fds = mm_calloc(DEFAULT_NFDS, sizeof(struct fd_info)); if (evpd->ed_fds == NULL) { close(evpd->ed_port); mm_free(evpd); return (NULL); } evpd->ed_nevents = DEFAULT_NFDS; for (i = 0; i < EVENTS_PER_GETN; i++) evpd->ed_pending[i] = -1; evsig_init(base); return (evpd); } #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_nevents > 0); EVUTIL_ASSERT(evpd->ed_port > 0); EVUTIL_ASSERT(evpd->ed_fds > 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); EVUTIL_ASSERT(pevt->portev_user == NULL); } #else #define check_evportop(epop) #define check_event(pevt) #endif /* CHECK_INVARIANTS */ /* * Doubles the size of the allocated file descriptor array. */ static int grow(struct evport_data *epdp, int factor) { struct fd_info *tmp; int oldsize = epdp->ed_nevents; int newsize = factor * oldsize; EVUTIL_ASSERT(factor > 1); check_evportop(epdp); tmp = mm_realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize); if (NULL == tmp) return -1; epdp->ed_fds = tmp; memset((char*) (epdp->ed_fds + oldsize), 0, (newsize - oldsize)*sizeof(struct fd_info)); epdp->ed_nevents = newsize; check_evportop(epdp); return 0; } /* * (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, NULL) == -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[EVENTS_PER_GETN]; /* * 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 (EVENTS_PER_GETN)) 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 < EVENTS_PER_GETN; ++i) { struct fd_info *fdi = NULL; if (epdp->ed_pending[i] != -1) { fdi = &(epdp->ed_fds[epdp->ed_pending[i]]); } if (fdi != NULL && FDI_HAS_EVENTS(fdi)) { int fd = epdp->ed_pending[i]; reassociate(epdp, fdi, fd); epdp->ed_pending[i] = -1; } } EVBASE_RELEASE_LOCK(base, th_base_lock); res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, (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) { struct fd_info *fdi; port_event_t *pevt = &pevtlist[i]; int fd = (int) pevt->portev_object; check_evportop(epdp); check_event(pevt); epdp->ed_pending[i] = fd; /* * 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; EVUTIL_ASSERT(epdp->ed_nevents > fd); fdi = &(epdp->ed_fds[fd]); evmap_io_active(base, fd, res); } /* end of all events gotten */ 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; int factor; (void)p; check_evportop(evpd); /* * If necessary, grow the file descriptor info table */ factor = 1; while (fd >= factor * evpd->ed_nevents) factor *= 2; if (factor > 1) { if (-1 == grow(evpd, factor)) { return (-1); } } fdi = &evpd->ed_fds[fd]; 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; int i; int associated = 1; (void)p; check_evportop(evpd); if (evpd->ed_nevents < fd) { return (-1); } for (i = 0; i < EVENTS_PER_GETN; ++i) { if (evpd->ed_pending[i] == fd) { associated = 0; break; } } fdi = &evpd->ed_fds[fd]; if (events & EV_READ) fdi->fdi_what &= ~EV_READ; if (events & EV_WRITE) fdi->fdi_what &= ~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) { evpd->ed_pending[i] = -1; } } 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_fds) mm_free(evpd->ed_fds); mm_free(evpd); } lldpd-0.7.7/libevent/bufferevent_async.c0000644000076400001440000004347212074262762015253 00000000000000/* * 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" #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 #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, be_async_destruct, _bufferevent_generic_adj_timeouts, be_async_flush, be_async_ctrl, }; static inline struct bufferevent_async * upcast(struct bufferevent *bev) { struct bufferevent_async *bev_a; if (bev->be_ops != &bufferevent_ops_async) 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; _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); } 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; _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); 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 (bev_p->options & BEV_OPT_CLOSE_ON_FREE) { /* XXXX possible double-close */ evutil_closesocket(fd); } /* delete this in case non-blocking connect was used */ if (event_initialized(&bev->ev_write)) { event_del(&bev->ev_write); _bufferevent_del_generic_timeout_cbs(bev); } } /* 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); _bufferevent_run_eventcb(bev, ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR); 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); if (evbuffer_get_length(bev->input) >= bev->wm_read.low) _bufferevent_run_readcb(bev); bev_async_consider_reading(bev_a); } else if (!ok) { what |= BEV_EVENT_ERROR; bev_a->ok = 0; _bufferevent_run_eventcb(bev, what); } else if (!nbytes) { what |= BEV_EVENT_EOF; bev_a->ok = 0; _bufferevent_run_eventcb(bev, what); } } _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); if (evbuffer_get_length(bev->output) <= bev->wm_write.low) _bufferevent_run_writecb(bev); bev_async_consider_writing(bev_a); } else if (!ok) { what |= BEV_EVENT_ERROR; bev_a->ok = 0; _bufferevent_run_eventcb(bev, what); } else if (!nbytes) { what |= BEV_EVENT_EOF; bev_a->ok = 0; _bufferevent_run_eventcb(bev, what); } } _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) { int err = GetLastError(); /* We may have alrady associated this fd with a port. * Let's hope it's this port, and that the error code * for doing this neer changes. */ if (err != ERROR_INVALID_PARAMETER) 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); bev_a->ok = fd >= 0; if (bev_a->ok) _bufferevent_init_generic_timeout_cbs(bev); 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; _bufferevent_init_generic_timeout_cbs(bev); /* 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 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) return -1; _evbuffer_overlapped_set_fd(bev->input, data->fd); _evbuffer_overlapped_set_fd(bev->output, data->fd); 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)INVALID_SOCKET && (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) { closesocket(fd); } bev_a->ok = 0; return 0; } case BEV_CTRL_GET_UNDERLYING: default: return -1; } } lldpd-0.7.7/libevent/Doxyfile0000644000076400001440000002373612074262762013106 00000000000000# 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 = libevent # Place all output under 'doxygen/' OUTPUT_DIRECTORY = doxygen/ # 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 = \ include/event2/buffer.h \ include/event2/buffer_compat.h \ include/event2/bufferevent.h \ include/event2/bufferevent_compat.h \ include/event2/bufferevent_ssl.h \ include/event2/dns.h \ include/event2/dns_compat.h \ include/event2/event.h \ include/event2/event_compat.h \ include/event2/http.h \ include/event2/http_compat.h \ include/event2/listener.h \ include/event2/rpc.h \ include/event2/rpc_compat.h \ include/event2/tag.h \ include/event2/tag_compat.h \ include/event2/thread.h \ 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 = YES #--------------------------------------------------------------------------- # 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 = YES # 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 = NO # 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-0.7.7/libevent/log.c0000644000076400001440000001175312074262762012321 00000000000000/* $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" #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 _warn_helper(int severity, const char *errstr, const char *fmt, va_list ap); static void event_log(int severity, const char *msg); static void event_exit(int errcode) EV_NORETURN; static event_fatal_cb fatal_fn = NULL; 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); _warn_helper(_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); _warn_helper(_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); _warn_helper(_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); _warn_helper(_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); _warn_helper(_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); _warn_helper(_EVENT_LOG_WARN, NULL, fmt, ap); va_end(ap); } void event_msgx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _warn_helper(_EVENT_LOG_MSG, NULL, fmt, ap); va_end(ap); } void _event_debugx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _warn_helper(_EVENT_LOG_DEBUG, NULL, fmt, ap); va_end(ap); } static void _warn_helper(int severity, const char *errstr, const char *fmt, va_list ap) { char buf[1024]; size_t len; 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-0.7.7/libevent/evrpc.c0000644000076400001440000007126512074262762012663 00000000000000/* * 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" #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 != NULL) 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: if (rpc_state != NULL) 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: if (rpc_state != NULL) 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: if (rpc_state != NULL) 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 (connection->timeout == -1) connection->timeout = 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) { evcon->timeout = 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 */ if (req != NULL) 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, EVCON_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-0.7.7/libevent/evutil.h0000644000076400001440000000331112074262762013044 00000000000000/* * 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 _EVUTIL_H_ #define _EVUTIL_H_ /** @file evutil.h Utility and compatibility functions for Libevent. The header is deprecated in Libevent 2.0 and later; please use instead. */ #include #endif /* _EVUTIL_H_ */ lldpd-0.7.7/libevent/libevent.pc.in0000644000076400001440000000047512074262762014134 00000000000000#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-0.7.7/libevent/iocp-internal.h0000644000076400001440000001676512074262762014321 00000000000000/* * 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 _EVENT_IOCP_INTERNAL_H #define _EVENT_IOCP_INTERNAL_H #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; }; 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. */ 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. */ 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. */ 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. */ int evbuffer_launch_write(struct evbuffer *buf, ev_ssize_t n, struct event_overlapped *ol); /** XXX document */ void evbuffer_commit_read(struct evbuffer *, ev_ssize_t); 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. */ 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. */ 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. */ int event_iocp_shutdown(struct event_iocp_port *port, long waitMsec); /* FIXME document. */ 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. */ struct event_iocp_port *event_base_get_iocp(struct event_base *base); /* FIXME document. */ int event_base_start_iocp(struct event_base *base, int n_cpus); void event_base_stop_iocp(struct event_base *base); /* FIXME document. */ 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-0.7.7/libevent/include/0000755000076400001440000000000012237716102013061 500000000000000lldpd-0.7.7/libevent/include/Makefile.in0000644000076400001440000004751512237715703015070 00000000000000# Makefile.in generated by automake 1.14 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # include/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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@ subdir = include DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(am__nobase_include_HEADERS_DIST) $(am__noinst_HEADERS_DIST) 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/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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__nobase_include_HEADERS_DIST = event2/buffer.h \ event2/buffer_compat.h event2/bufferevent.h \ event2/bufferevent_compat.h event2/bufferevent_ssl.h \ event2/bufferevent_struct.h event2/dns.h event2/dns_compat.h \ event2/dns_struct.h event2/event.h event2/event_compat.h \ event2/event_struct.h event2/http.h event2/http_compat.h \ event2/http_struct.h event2/keyvalq_struct.h event2/listener.h \ event2/rpc.h event2/rpc_compat.h event2/rpc_struct.h \ event2/tag.h event2/tag_compat.h event2/thread.h event2/util.h 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)$(includedir)" "$(DESTDIR)$(includedir)" am__noinst_HEADERS_DIST = event2/buffer.h event2/buffer_compat.h \ event2/bufferevent.h event2/bufferevent_compat.h \ event2/bufferevent_ssl.h event2/bufferevent_struct.h \ event2/dns.h event2/dns_compat.h event2/dns_struct.h \ event2/event.h event2/event_compat.h event2/event_struct.h \ event2/http.h event2/http_compat.h event2/http_struct.h \ event2/keyvalq_struct.h event2/listener.h event2/rpc.h \ event2/rpc_compat.h event2/rpc_struct.h event2/tag.h \ event2/tag_compat.h event2/thread.h event2/util.h HEADERS = $(nobase_include_HEADERS) $(nobase_nodist_include_HEADERS) \ $(nodist_noinst_HEADERS) $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # 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)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 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@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ 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@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ 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@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ 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@ 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@ AUTOMAKE_OPTIONS = foreign EVENT2_EXPORT = \ event2/buffer.h \ event2/buffer_compat.h \ event2/bufferevent.h \ event2/bufferevent_compat.h \ event2/bufferevent_ssl.h \ event2/bufferevent_struct.h \ event2/dns.h \ event2/dns_compat.h \ event2/dns_struct.h \ event2/event.h \ event2/event_compat.h \ event2/event_struct.h \ event2/http.h \ event2/http_compat.h \ event2/http_struct.h \ event2/keyvalq_struct.h \ event2/listener.h \ event2/rpc.h \ event2/rpc_compat.h \ event2/rpc_struct.h \ event2/tag.h \ event2/tag_compat.h \ event2/thread.h \ event2/util.h EXTRA_SRC = $(EVENT2_EXPORT) @INSTALL_LIBEVENT_TRUE@nobase_include_HEADERS = $(EVENT2_EXPORT) @INSTALL_LIBEVENT_TRUE@nobase_nodist_include_HEADERS = ./event2/event-config.h @INSTALL_LIBEVENT_FALSE@noinst_HEADERS = $(EVENT2_EXPORT) @INSTALL_LIBEVENT_FALSE@nodist_noinst_HEADERS = ./event2/event-config.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign include/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_includeHEADERS: $(nobase_include_HEADERS) @$(NORMAL_INSTALL) @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \ echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \ done uninstall-nobase_includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) install-nobase_nodist_includeHEADERS: $(nobase_nodist_include_HEADERS) @$(NORMAL_INSTALL) @list='$(nobase_nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \ echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \ done uninstall-nobase_nodist_includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nobase_nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(includedir)'; $(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" 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 distdir: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(HEADERS) installdirs: for dir in "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: 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: clean-generic: 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) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nobase_includeHEADERS \ install-nobase_nodist_includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nobase_includeHEADERS \ uninstall-nobase_nodist_includeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-nobase_includeHEADERS \ install-nobase_nodist_includeHEADERS install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-nobase_includeHEADERS \ uninstall-nobase_nodist_includeHEADERS # 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-0.7.7/libevent/include/event2/0000755000076400001440000000000012237716102014264 500000000000000lldpd-0.7.7/libevent/include/event2/buffer_compat.h0000644000076400001440000001075212074262762017205 00000000000000/* * 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_ #define _EVENT2_BUFFER_COMPAT_H_ /** @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, EOL_STYLE_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 */ 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 */ void 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. */ 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-0.7.7/libevent/include/event2/listener.h0000644000076400001440000001352012074262762016212 00000000000000/* * 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_ #define _EVENT2_LISTENER_H_ #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) /** 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. */ 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. */ 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. */ void evconnlistener_free(struct evconnlistener *lev); /** Re-enable an evconnlistener that has been disabled. */ int evconnlistener_enable(struct evconnlistener *lev); /** Stop listening for connections on an evconnlistener. */ int evconnlistener_disable(struct evconnlistener *lev); /** Return an evconnlistener's associated event_base. */ struct event_base *evconnlistener_get_base(struct evconnlistener *lev); /** Return the socket that an evconnlistner is listening on. */ evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev); /** Change the callback on the listener to cb and its user_data to arg. */ void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb, void *arg); /** Set an evconnlistener's error callback. */ void evconnlistener_set_error_cb(struct evconnlistener *lev, evconnlistener_errorcb errorcb); #ifdef __cplusplus } #endif #endif lldpd-0.7.7/libevent/include/event2/bufferevent_struct.h0000644000076400001440000001001712074262762020302 00000000000000/* * 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_ #define _EVENT2_BUFFEREVENT_STRUCT_H_ /** @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_ */ lldpd-0.7.7/libevent/include/event2/keyvalq_struct.h0000644000076400001440000000504712074262762017452 00000000000000/* * 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_KEYVALQ_STRUCT_H_ #define _EVENT2_EVENT_KEYVALQ_STRUCT_H_ #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-0.7.7/libevent/include/event2/event_compat.h0000644000076400001440000001634312074262762017057 00000000000000/* * 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_ #define _EVENT2_EVENT_COMPAT_H_ /** @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. */ #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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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. */ 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_ */ lldpd-0.7.7/libevent/include/event2/tag_compat.h0000644000076400001440000000410512074262762016502 00000000000000/* * 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_ #define _EVENT2_TAG_COMPAT_H_ /** @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_ */ lldpd-0.7.7/libevent/include/event2/bufferevent_compat.h0000644000076400001440000001054012074262762020242 00000000000000/* * 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_ #define _EVENT2_BUFFEREVENT_COMPAT_H_ #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() */ 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 */ 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-0.7.7/libevent/include/event2/buffer.h0000644000076400001440000007402112155052147015633 00000000000000/* * 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_ #define _EVENT2_BUFFER_H_ /** @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. */ #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 these values except with evbuffer_ptr_set. */ struct evbuffer_ptr { ev_ssize_t pos; /* Do not alter the values of fields. */ 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 */ struct evbuffer *evbuffer_new(void); /** Deallocate storage for an evbuffer. @param buf pointer to the evbuffer to be freed */ 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. */ 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. */ void evbuffer_lock(struct evbuffer *buf); /** Release the lock on an evbuffer. Has no effect if locking was not enabled with evbuffer_enable_locking. */ 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. */ 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. */ 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 */ 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. */ 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 */ 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() */ 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() */ 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. */ 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. */ 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. */ ev_ssize_t evbuffer_copyout(struct evbuffer *buf, 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 */ 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 }; /** * 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 */ 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() */ int evbuffer_add_buffer(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 */ 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. @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 @return 0 if successful, or -1 if an error occurred */ int evbuffer_add_file(struct evbuffer *outbuf, int fd, 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() */ 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. */ 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. */ 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() */ 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() */ 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 @return the number of bytes read, or -1 if an error occurred @see evbuffer_write() */ 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. */ 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. */ 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. If evbuffer_ptr is not initialized. This function can only be called with EVBUFFER_PTR_SET. @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 */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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 */ 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 */ 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 */ 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. */ 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. */ 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. */ int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base); #ifdef __cplusplus } #endif #endif /* _EVENT2_BUFFER_H_ */ lldpd-0.7.7/libevent/include/event2/dns_struct.h0000644000076400001440000000501412074262762016554 00000000000000/* * 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_ #define _EVENT2_DNS_STRUCT_H_ /** @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_ */ lldpd-0.7.7/libevent/include/event2/bufferevent_ssl.h0000644000076400001440000000737012074262762017567 00000000000000/* * 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_ #define _EVENT2_BUFFEREVENT_SSL_H_ /** @file event2/bufferevent_ssl.h OpenSSL support for bufferevents. */ #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 */ 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. */ 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); /** Return the underlying openssl SSL * object for an SSL bufferevent. */ struct ssl_st * bufferevent_openssl_get_ssl(struct bufferevent *bufev); /** Tells a bufferevent to begin SSL renegotiation. */ int bufferevent_ssl_renegotiate(struct bufferevent *bev); /** Return the most recent OpenSSL error reported on an SSL bufferevent. */ unsigned long bufferevent_get_openssl_error(struct bufferevent *bev); #endif #ifdef __cplusplus } #endif #endif /* _EVENT2_BUFFEREVENT_SSL_H_ */ lldpd-0.7.7/libevent/include/event2/util.h0000644000076400001440000005237712074262762015357 00000000000000/* * 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_ #define _EVENT2_UTIL_H_ /** @file event2/util.h Common convenience functions for cross-platform portability and related socket manipulations. */ #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 #if !defined(_GNU_SOURCE) #define _GNU_SOURCE #endif #include #endif #ifdef WIN32 #include #else #include #endif /* 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 #ifdef WIN32 #define ev_off_t ev_int64_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. @{ */ #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) /** @} */ /** @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 /** 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() */ 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 */ 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 */ int evutil_make_listen_socket_reuseable(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 */ 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, -1 on failure */ int evutil_closesocket(evutil_socket_t sock); #define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s) #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. */ int evutil_socket_geterror(evutil_socket_t sock); /** Convert a socket error to a string. */ const char *evutil_socket_error_to_string(int errcode); #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) ... /**@}*/ #else #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)) #endif /** * @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_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. */ 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; 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. */ 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. */ 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. */ const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len); /** Replacement for inet_pton for platforms which lack it. */ 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. */ 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. */ 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. */ 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. */ 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. @{ */ #ifdef EAI_ADDRFAMILY #define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY #else #define EVUTIL_EAI_ADDRFAMILY -901 #endif #ifdef EAI_AGAIN #define EVUTIL_EAI_AGAIN EAI_AGAIN #else #define EVUTIL_EAI_AGAIN -902 #endif #ifdef EAI_BADFLAGS #define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS #else #define EVUTIL_EAI_BADFLAGS -903 #endif #ifdef EAI_FAIL #define EVUTIL_EAI_FAIL EAI_FAIL #else #define EVUTIL_EAI_FAIL -904 #endif #ifdef EAI_FAMILY #define EVUTIL_EAI_FAMILY EAI_FAMILY #else #define EVUTIL_EAI_FAMILY -905 #endif #ifdef EAI_MEMORY #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(EAI_NONAME) || EAI_NODATA != EAI_NONAME) #define EVUTIL_EAI_NODATA EAI_NODATA #else #define EVUTIL_EAI_NODATA -907 #endif #ifdef EAI_NONAME #define EVUTIL_EAI_NONAME EAI_NONAME #else #define EVUTIL_EAI_NONAME -908 #endif #ifdef EAI_SERVICE #define EVUTIL_EAI_SERVICE EAI_SERVICE #else #define EVUTIL_EAI_SERVICE -909 #endif #ifdef EAI_SOCKTYPE #define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE #else #define EVUTIL_EAI_SOCKTYPE -910 #endif #ifdef EAI_SYSTEM #define EVUTIL_EAI_SYSTEM EAI_SYSTEM #else #define EVUTIL_EAI_SYSTEM -911 #endif #define EVUTIL_EAI_CANCEL -90001 #ifdef AI_PASSIVE #define EVUTIL_AI_PASSIVE AI_PASSIVE #else #define EVUTIL_AI_PASSIVE 0x1000 #endif #ifdef AI_CANONNAME #define EVUTIL_AI_CANONNAME AI_CANONNAME #else #define EVUTIL_AI_CANONNAME 0x2000 #endif #ifdef AI_NUMERICHOST #define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST #else #define EVUTIL_AI_NUMERICHOST 0x4000 #endif #ifdef AI_NUMERICSERV #define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV #else #define EVUTIL_AI_NUMERICSERV 0x8000 #endif #ifdef AI_V4MAPPED #define EVUTIL_AI_V4MAPPED AI_V4MAPPED #else #define EVUTIL_AI_V4MAPPED 0x10000 #endif #ifdef AI_ALL #define EVUTIL_AI_ALL AI_ALL #else #define EVUTIL_AI_ALL 0x20000 #endif #ifdef AI_ADDRCONFIG #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. */ 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. */ void evutil_freeaddrinfo(struct evutil_addrinfo *ai); const char *evutil_gai_strerror(int err); /** Generate n bytes of secure pseudorandom data, and store them in buf. * * By default, Libevent uses an ARC4-based random number generator, seeded * using the platform's entropy source (/dev/urandom on Unix-like systems; * CryptGenRandom on Windows). */ 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. */ int evutil_secure_rng_init(void); /** 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 */ void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); #ifdef __cplusplus } #endif #endif /* _EVUTIL_H_ */ lldpd-0.7.7/libevent/include/event2/event.h0000644000076400001440000013010512074262762015505 00000000000000/* * 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_ #define _EVENT2_EVENT_H_ /** @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_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 inclurde 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 Dispaching evets. 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() function returns an event struct to use as a timer. To activate the timer, call evtimer_add(). Timers can be deactivated by calling evtimer_del(). @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. */ #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 * 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 * wrhere you set up configation 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() */ 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() */ 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() */ 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() */ int event_reinit(struct event_base *base); /** Event dispatching loop This loop will run the event base until either there are no more added events, 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 no events were registered. @see event_base_loop() */ 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.) */ 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. */ const char **event_get_supported_methods(void); /** 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 */ 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. */ 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. */ 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 }; /** 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. */ 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 settnig 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 }; /** 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 */ 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() */ 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() **/ 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. */ int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus); /** 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() */ 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. @param eb an event_base to be freed */ void event_base_free(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. */ 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. */ void event_set_fatal_callback(event_fatal_cb cb); /** 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. */ 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 /**@}*/ /** 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 added events, or until something calls event_base_loopbreak() or evenet_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 no events were registered. @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE, EVLOOP_NONBLOCK */ 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() */ 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_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() */ int event_base_loopbreak(struct event_base *); /** Checks if the event loop was told to exit by event_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() */ int event_base_got_exit(struct event_base *); /** Checks if the event loop was told to abort immediately by event_loopbreak(). This function will return true for an event_base at every point after event_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() */ 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 /**@}*/ /** @name evtimer_* macros Aliases for working with one-shot timer events */ /**@{*/ #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) /**@}*/ /** 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 *); /** Allocate and asssign 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 triggerd. When the event becomes active, the event loop will run the provided callbuck 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(). @see event_free(), event_add(), event_del(), event_assign() */ 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() */ 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, first make it non-pending and non-active. */ void event_free(struct event *); /** Schedule a one-time event The function event_base_once() is similar to event_set(). 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. This may be fixed in a later version of Libevent. @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 succees immediately. @return 0 if successful, or -1 if an error occurred */ 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 ev event when the event specified in event_assign()/event_new() occurs, or when the time specified in timeout has elapesed. If atimeout 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, or clears the old timeout if the timeout argument is NULL. @param ev an event struct initialized via event_set() @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() */ int event_add(struct event *ev, const struct timeval *timeout); /** 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() */ int event_del(struct event *); /** 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. **/ 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. */ int event_pending(const struct event *ev, short events, struct timeval *tv); /** 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 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 */ 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. */ evutil_socket_t event_get_fd(const struct event *ev); /** Get the event_base associated with an event. */ struct event_base *event_get_base(const struct event *ev); /** Return the events (EV_READ, EV_WRITE, etc) assigned to an event. */ short event_get_events(const struct event *ev); /** Return the callback assigned to an event. */ event_callback_fn event_get_callback(const struct event *ev); /** Return the callback argument assigned to an event. */ void *event_get_callback_arg(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. */ 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. */ 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 */ 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 */ 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() */ int event_base_priority_init(struct event_base *, int); /** 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() */ 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.) */ 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 funtions 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. **/ 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 void event_base_dump_events(struct event_base *, FILE *); /** 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 inaccuate if your callbacks take a long time to execute. Returns 0 on success, negative on failure. */ int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv); #ifdef __cplusplus } #endif #endif /* _EVENT2_EVENT_H_ */ lldpd-0.7.7/libevent/include/event2/http.h0000644000076400001440000007722012074262762015353 00000000000000/* * 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_ #define _EVENT2_HTTP_H_ /* For int types. */ #include #ifdef __cplusplus extern "C" { #endif /* In case we haven't included the right headers yet. */ struct evbuffer; struct event_base; /** @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; /** * 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 * @see evhttp_free() */ 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() */ 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() */ 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() */ 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() */ 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. */ struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener); /** * Return the listener used to implement a bound socket. */ struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound); /** * 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() */ 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() */ 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() */ void evhttp_free(struct evhttp* http); /** XXX Document. */ void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size); /** XXX Document. */ void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size); /** 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 */ 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 */ 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 */ 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 */ void evhttp_set_gencb(struct evhttp *http, void (*cb)(struct evhttp_request *, 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() */ 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() */ 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() */ 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() */ 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 */ void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs); /* 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. */ 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 */ 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 */ 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. */ void evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf); /** Complete a chunked reply, freeing the request as appropriate. @param req a request object */ 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 }; /** * 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. */ 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. */ void evhttp_request_set_chunked_cb(struct evhttp_request *, void (*cb)(struct evhttp_request *, void *)); /** Frees the request object and removes associated events. */ void evhttp_request_free(struct evhttp_request *req); struct evdns_base; /** * 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 */ struct evhttp_connection *evhttp_connection_base_new( struct event_base *base, struct evdns_base *dnsbase, const char *address, unsigned short port); /** * Return the bufferevent that an evhttp_connection is using. */ struct bufferevent *evhttp_connection_get_bufferevent( struct evhttp_connection *evcon); /** 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. */ void evhttp_request_own(struct evhttp_request *req); /** Returns 1 if the request is owned by the user */ 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(). */ struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req); /** * Returns the underlying event_base for this connection */ struct event_base *evhttp_connection_get_base(struct evhttp_connection *req); void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, ev_ssize_t new_max_headers_size); void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, ev_ssize_t new_max_body_size); /** Frees an http connection */ void evhttp_connection_free(struct evhttp_connection *evcon); /** sets the ip address from which http connections are made */ void evhttp_connection_set_local_address(struct evhttp_connection *evcon, const char *address); /** sets the local port from which http connections are made */ void evhttp_connection_set_local_port(struct evhttp_connection *evcon, ev_uint16_t port); /** Sets the timeout for events related to this connection */ void evhttp_connection_set_timeout(struct evhttp_connection *evcon, int timeout_in_secs); /** Sets the retry limit for this connection - -1 repeats indefinitely */ void evhttp_connection_set_retries(struct evhttp_connection *evcon, int retry_max); /** Set a callback for connection close. */ 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. */ void evhttp_connection_get_peer(struct evhttp_connection *evcon, char **address, ev_uint16_t *port); /** 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() */ 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. */ 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 */ const char *evhttp_request_get_uri(const struct evhttp_request *req); /** Returns the request URI (parsed) */ const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req); /** Returns the request command */ enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req); int evhttp_request_get_response_code(const struct evhttp_request *req); /** Returns the input headers */ struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req); /** Returns the output headers */ struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req); /** Returns the input buffer */ struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req); /** Returns the output buffer */ 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. */ 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 count not be found. @see evhttp_add_header(), evhttp_remove_header() */ 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() */ 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() */ 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 */ 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 */ 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. */ 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_get_decoded_uri, 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_get_decoded_uri instead. @param uri an encoded URI @return a newly allocated unencoded URI or NULL on failure */ 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 sapce. @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 */ 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 */ 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 */ 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 */ char *evhttp_htmlescape(const char *html); /** * Return a new empty evhttp_uri with no fields set. */ struct evhttp_uri *evhttp_uri_new(void); /** * Changes the flags set on a given URI. See EVHTTP_URI_* for * a list of flags. **/ 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. */ 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. */ 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 "". */ 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. */ 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 */ 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 */ 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 */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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() */ 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) */ 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() */ 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() */ char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit); #ifdef __cplusplus } #endif #endif /* _EVENT2_HTTP_H_ */ lldpd-0.7.7/libevent/include/event2/rpc_compat.h0000644000076400001440000000442712074262762016522 00000000000000/* * 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_ #define _EVENT2_RPC_COMPAT_H_ /** @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_ */ lldpd-0.7.7/libevent/include/event2/thread.h0000644000076400001440000002236212074262762015640 00000000000000/* * 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_ #define _EVENT2_THREAD_H_ /** @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(). */ #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. */ 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. */ 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. */ 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. */ 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. */ 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. **/ 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. @return 0 on success, -1 on failure. */ int evthread_make_base_notifiable(struct event_base *base); #ifdef __cplusplus } #endif #endif /* _EVENT2_THREAD_H_ */ lldpd-0.7.7/libevent/include/event2/http_struct.h0000644000076400001440000001010612074262762016745 00000000000000/* * 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_ #define _EVENT2_HTTP_STRUCT_H_ /** @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 *); }; #ifdef __cplusplus } #endif #endif /* _EVENT2_HTTP_STRUCT_H_ */ lldpd-0.7.7/libevent/include/event2/rpc_struct.h0000644000076400001440000000621312074262762016556 00000000000000/* * 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_ #define _EVENT2_RPC_STRUCT_H_ #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! */ /** * 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 __cplusplus } #endif #endif /* _EVENT2_RPC_STRUCT_H_ */ lldpd-0.7.7/libevent/include/event2/dns.h0000644000076400001440000006011112074262762015147 00000000000000/* * 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_ #define _EVENT2_DNS_H_ #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 #define DNS_OPTION_SEARCH 1 #define DNS_OPTION_NAMESERVERS 2 #define DNS_OPTION_MISC 4 #define DNS_OPTION_HOSTSFILE 8 #define DNS_OPTIONS_ALL 15 /* 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; /** 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 initialize_nameservers 1 if resolve.conf processing should occur @return evdns_base object if successful, or NULL if an error occurred. @see evdns_base_free() */ 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() */ void evdns_base_free(struct evdns_base *base, int fail_requests); /** Convert a DNS error code to a string. @param err the DNS error code @return a string containing an explanation of the error code */ 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() */ 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() */ 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() */ 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() */ 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() */ int evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string); /** Add a nameserver by sockaddr. **/ 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() */ 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() */ 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() */ 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() */ 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 */ 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. 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 */ 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_OPTIONS_HOSTSFILE|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() */ 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. Return 0 on success, negative on failure. */ int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname); /** 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() */ #ifdef WIN32 int evdns_base_config_windows_nameservers(struct evdns_base *); #define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED #endif /** Clear the list of search domains. */ 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 */ 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 */ 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 */ 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. */ 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. */ 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. */ 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. */ 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 */ void evdns_server_request_set_flags(struct evdns_server_request *req, int flags); /* Functions to add an answer to an in-progress DNS reply. */ 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); int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); 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); 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. */ int evdns_server_request_respond(struct evdns_server_request *req, int err); /** Free a DNS request without sending back a reply. */ int evdns_server_request_drop(struct evdns_server_request *req); struct sockaddr; /** Get the address that made a DNS request. */ 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. */ 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. */ void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req); #ifdef __cplusplus } #endif #endif /* !_EVENT2_DNS_H_ */ lldpd-0.7.7/libevent/include/event2/event_struct.h0000644000076400001440000000771712074262762017125 00000000000000/* * 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_ #define _EVENT2_EVENT_STRUCT_H_ /** @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_INIT 0x80 /* EVLIST_X_ Private space: 0x1000-0xf000 */ #define EVLIST_ALL (0xf000 | 0x9f) /* 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 struct event_base; struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) ev_next; /* 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 { TAILQ_ENTRY(event) ev_io_next; struct timeval ev_timeout; } ev_io; /* used by signal events */ struct { TAILQ_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 */ short ev_flags; ev_uint8_t ev_pri; /* smaller numbers are higher priority */ ev_uint8_t ev_closure; struct timeval ev_timeout; /* allows us to adopt for different types of events */ void (*ev_callback)(evutil_socket_t, short, void *arg); void *ev_arg; }; TAILQ_HEAD (event_list, event); #ifdef _EVENT_DEFINED_TQENTRY #undef TAILQ_ENTRY #endif #ifdef _EVENT_DEFINED_TQHEAD #undef TAILQ_HEAD #endif #ifdef __cplusplus } #endif #endif /* _EVENT2_EVENT_STRUCT_H_ */ lldpd-0.7.7/libevent/include/event2/bufferevent.h0000644000076400001440000006770012074262762016711 00000000000000/* * 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_ #define _EVENT2_BUFFEREVENT_H_ /** @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 and call the read callback. When writing is enabled, the bufferevent will try to write data onto its file descriptor when writing is enabled, 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().
*/ #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. @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() */ 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. */ int bufferevent_socket_connect(struct bufferevent *, 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. */ 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() */ 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() */ int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); /** Return the event_base used by a bufferevent */ 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 */ int bufferevent_priority_set(struct bufferevent *bufev, int pri); /** Deallocate the storage associated with a bufferevent structure. @param bufev the bufferevent structure to be freed. */ 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() */ void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg); /** 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 */ 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. */ 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. */ 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() */ 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() */ 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. */ 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. */ 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 */ 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 */ 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() */ 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() */ 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 */ 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 banwidth, 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 */ 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. 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 */ void bufferevent_setwatermark(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. */ void bufferevent_lock(struct bufferevent *bufev); /** Release the lock on a bufferevent. Has no effect if locking was not enabled with BEV_OPT_THREADSAFE. */ void bufferevent_unlock(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 */ int bufferevent_flush(struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode mode); /** @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. */ 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. */ 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. */ 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. */ 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. */ 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 sucess, -1 on failure. */ 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. */ 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. */ 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 faulre. */ 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. */ 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. */ 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). */ int bufferevent_remove_from_rate_limit_group(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. @{ */ ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev); ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev); /*@}*/ ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev); ev_ssize_t bufferevent_get_max_to_write(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. @{ */ ev_ssize_t bufferevent_rate_limit_group_get_read_limit( struct bufferevent_rate_limit_group *); 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. @{ */ int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr); 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. @{ */ int bufferevent_rate_limit_group_decrement_read( struct bufferevent_rate_limit_group *, ev_ssize_t); 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. */ 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(). */ void bufferevent_rate_limit_group_reset_totals( struct bufferevent_rate_limit_group *grp); #ifdef __cplusplus } #endif #endif /* _EVENT2_BUFFEREVENT_H_ */ lldpd-0.7.7/libevent/include/event2/http_compat.h0000644000076400001440000000607112074262762016712 00000000000000/* * 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_ #define _EVENT2_HTTP_COMPAT_H_ /** @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 an struct evhttp object */ struct evhttp *evhttp_start(const char *address, unsigned short 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 */ struct evhttp_connection *evhttp_connection_new( const char *address, unsigned short 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? */ 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_ */ lldpd-0.7.7/libevent/include/event2/dns_compat.h0000644000076400001440000002754312074262762016526 00000000000000/* * 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_ #define _EVENT2_DNS_COMPAT_H_ /** @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 /** 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() */ 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. */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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() */ 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 */ 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() */ 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(). */ 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 */ 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 */ 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(). */ 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 int evdns_config_windows_nameservers(void); #define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED #endif #ifdef __cplusplus } #endif #endif /* _EVENT2_EVENT_COMPAT_H_ */ lldpd-0.7.7/libevent/include/event2/tag.h0000644000076400001440000001052612074262762015143 00000000000000/* * 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_ #define _EVENT2_TAG_H_ /** @file event2/tag.h Helper functions for reading and writing tagged data onto buffers. */ #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. */ 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. */ int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag); void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, ev_uint32_t len); 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 */ void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number); void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number); void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer); void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint64_t integer); void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string); void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv); int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst); int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); int evtag_consume(struct evbuffer *evbuf); int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint32_t *pinteger); int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint64_t *pinteger); int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, size_t len); int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring); int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv); #ifdef __cplusplus } #endif #endif /* _EVENT2_TAG_H_ */ lldpd-0.7.7/libevent/include/event2/rpc.h0000644000076400001440000005077012074262762015161 00000000000000/* * 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_ #define _EVENT2_RPC_H_ #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_ /** 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_ */ /** 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; \ }; \ 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 */ 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 */ void evrpc_request_done(struct evrpc_req_generic *req); /** accessors for request and reply */ void *evrpc_get_request(struct evrpc_req_generic *req); 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 * @see evrpc_free() */ 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 */ 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, NULL, \ (void (*)(void *))request##_free, \ (int (*)(void *, struct evbuffer *))request##_unmarshal, \ (void *(*)(void *))reply##_new, 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() */ 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) 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() */ 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 * @see evrpc_pool_free() */ 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() */ 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. */ 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. */ 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. */ 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() */ 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() */ 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 */ 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 */ 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 */ 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 */ 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() */ 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() */ 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 */ struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx); void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx, struct evrpc_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); #ifdef __cplusplus } #endif #endif /* _EVENT2_RPC_H_ */ lldpd-0.7.7/libevent/include/Makefile.am0000644000076400001440000000226112074262762015045 00000000000000# include/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. AUTOMAKE_OPTIONS = foreign EVENT2_EXPORT = \ event2/buffer.h \ event2/buffer_compat.h \ event2/bufferevent.h \ event2/bufferevent_compat.h \ event2/bufferevent_ssl.h \ event2/bufferevent_struct.h \ event2/dns.h \ event2/dns_compat.h \ event2/dns_struct.h \ event2/event.h \ event2/event_compat.h \ event2/event_struct.h \ event2/http.h \ event2/http_compat.h \ event2/http_struct.h \ event2/keyvalq_struct.h \ event2/listener.h \ event2/rpc.h \ event2/rpc_compat.h \ event2/rpc_struct.h \ event2/tag.h \ event2/tag_compat.h \ event2/thread.h \ event2/util.h EXTRA_SRC = $(EVENT2_EXPORT) ## Without the nobase_ prefixing, Automake would strip "event2/" from ## the source header filename to derive the installed header filename. ## With nobase_ the installed path is $(includedir)/event2/ev*.h. if INSTALL_LIBEVENT nobase_include_HEADERS = $(EVENT2_EXPORT) nobase_nodist_include_HEADERS = ./event2/event-config.h else noinst_HEADERS = $(EVENT2_EXPORT) nodist_noinst_HEADERS = ./event2/event-config.h endif lldpd-0.7.7/libevent/event-internal.h0000644000076400001440000003065412074262762014501 00000000000000/* * 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_ #define _EVENT_INTERNAL_H_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.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 /* Possible values for ev_closure in struct event. */ #define EV_CLOSURE_NONE 0 #define EV_CLOSURE_SIGNAL 1 #define EV_CLOSURE_PERSIST 2 /** 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 #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 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 handelr code. */ struct evsig_info sig; /** Number of virtual events */ int virtual_event_count; /** Number of total events added to this event_base */ int event_count; /** Number of total events active in this event_base */ int event_count_active; /** 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; /* Active event management. */ /** An array of nactivequeues queues for active events (ones that * have triggered, and whose callbacks need to be called). Low * priority numbers are more important, and stall higher ones. */ struct event_list *activequeues; /** The length of the activequeues array */ int nactivequeues; /* 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; /** List of defered_cb that are active. We run these after the active * events. */ struct deferred_cb_queue defer_queue; /** 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; /** All events that have been enabled (added) in this event_base */ struct event_list eventqueue; /** Stored timeval; used to detect when time is running backwards. */ struct timeval event_tv; /** 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; #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) /** 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; #endif #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; /** The event whose callback is executing right now */ struct event *current_event; /** 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 #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; /* 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); }; 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; enum event_method_feature require_features; enum event_base_config_flag flags; }; /* Internal use only: Functions that might be missing from */ #if defined(_EVENT_HAVE_SYS_QUEUE_H) && !defined(_EVENT_HAVE_TAILQFOREACH) #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 #endif /* TAILQ_FOREACH */ #define N_ACTIVE_CALLBACKS(base) \ ((base)->event_count_active + (base)->defer_queue.active_count) int _evsig_set_handler(struct event_base *base, int evsignal, void (*fn)(int)); int _evsig_restore_handler(struct event_base *base, int evsignal); void event_active_nolock(struct event *ev, int res, short count); /* FIXME document. */ 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. */ void event_base_assert_ok(struct event_base *base); #ifdef __cplusplus } #endif #endif /* _EVENT_INTERNAL_H_ */ lldpd-0.7.7/libevent/minheap-internal.h0000644000076400001440000001321112074262762014767 00000000000000/* * 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 _MIN_HEAP_H_ #define _MIN_HEAP_H_ #include "event2/event-config.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_elem_greater(struct event *a, struct event *b); 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_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_down_(min_heap_t* s, unsigned hole_index, struct event* e); int min_heap_elem_greater(struct event *a, struct event *b) { return 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 (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_(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_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 (!(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_(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 /* _MIN_HEAP_H_ */ lldpd-0.7.7/libevent/epoll.c0000644000076400001440000003142712074262762012653 00000000000000/* * 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 #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 #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" struct epollop { struct epoll_event *events; int nevents; int epfd; }; 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, 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, 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; struct epollop *epollop; /* Initialize the kernel queue. (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; 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": "???"; } 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; if (1) { /* The logic here is a little tricky. If 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=the remaining events. What fun! */ /* TODO: Turn this into a switch or a table lookup. */ if ((ch->read_change & EV_CHANGE_ADD) || (ch->write_change & EV_CHANGE_ADD)) { /* If we are adding anything at all, we'll want to do * either an ADD or a MOD. */ events = 0; op = EPOLL_CTL_ADD; if (ch->read_change & EV_CHANGE_ADD) { events |= EPOLLIN; } else if (ch->read_change & EV_CHANGE_DEL) { ; } else if (ch->old_events & EV_READ) { events |= EPOLLIN; } if (ch->write_change & EV_CHANGE_ADD) { events |= EPOLLOUT; } else if (ch->write_change & EV_CHANGE_DEL) { ; } else if (ch->old_events & EV_WRITE) { events |= EPOLLOUT; } if ((ch->read_change|ch->write_change) & EV_ET) events |= EPOLLET; if (ch->old_events) { /* If MOD fails, we retry as an ADD, and if * ADD fails we will retry as a MOD. So the * only hard part here is to guess which one * will work. As a heuristic, we'll try * MOD first if we think there were old * events and ADD if we think there were none. * * We can be wrong about the MOD if the file * has in fact been closed and re-opened. * * We can be wrong about the ADD if the * the fd has been re-created with a dup() * of the same file that it was before. */ op = EPOLL_CTL_MOD; } } else if ((ch->read_change & EV_CHANGE_DEL) || (ch->write_change & EV_CHANGE_DEL)) { /* If we're deleting anything, we'll want to do a MOD * or a DEL. */ op = EPOLL_CTL_DEL; if (ch->read_change & EV_CHANGE_DEL) { if (ch->write_change & EV_CHANGE_DEL) { events = EPOLLIN|EPOLLOUT; } else if (ch->old_events & EV_WRITE) { events = EPOLLOUT; op = EPOLL_CTL_MOD; } else { events = EPOLLIN; } } else if (ch->write_change & EV_CHANGE_DEL) { if (ch->old_events & EV_READ) { events = EPOLLIN; op = EPOLL_CTL_MOD; } else { events = EPOLLOUT; } } } if (!events) return 0; memset(&epev, 0, sizeof(epev)); epev.data.fd = ch->fd; epev.events = events; if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == -1) { if (op == EPOLL_CTL_MOD && 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)); } } else if (op == EPOLL_CTL_ADD && 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)); } } else if (op == EPOLL_CTL_DEL && (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))); } else { event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s)", epoll_op_to_string(op), (int)epev.events, ch->fd, ch->old_events, ch->read_change, change_to_string(ch->read_change), ch->write_change, change_to_string(ch->write_change)); return -1; } } else { event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]", epoll_op_to_string(op), (int)epev.events, (int)ch->fd, ch->old_events, ch->read_change, ch->write_change)); } } return 0; } 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 = 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); 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 = 0; if (events & EV_WRITE) ch.write_change = EV_CHANGE_DEL; if (events & EV_READ) ch.read_change = EV_CHANGE_DEL; 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; 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; if (what & (EPOLLHUP|EPOLLERR)) { ev = EV_READ | EV_WRITE; } else { if (what & EPOLLIN) ev |= EV_READ; if (what & EPOLLOUT) ev |= EV_WRITE; } 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); memset(epollop, 0, sizeof(struct epollop)); mm_free(epollop); } lldpd-0.7.7/libevent/util-internal.h0000644000076400001440000002452112074262762014331 00000000000000/* * 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_UTIL_INTERNAL_H #define _EVENT_UTIL_INTERNAL_H #include "event2/event-config.h" #include /* For EVUTIL_ASSERT */ #include "log-internal.h" #include #include #ifdef _EVENT_HAVE_SYS_SOCKET_H #include #endif #include "event2/util.h" #include "ipv6-internal.h" #ifdef __cplusplus extern "C" { #endif /* If we need magic to say "inline", get it for free internally. */ #ifdef _EVENT_inline #define inline _EVENT_inline #endif #ifdef _EVENT___func__ #define __func__ _EVENT___func__ #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 /* True iff e is an error that means a read/write operation can be retried. */ #define EVUTIL_ERR_RW_RETRIABLE(e) \ ((e) == EINTR || (e) == EAGAIN) /* 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 || (e) == EAGAIN || (e) == ECONNABORTED) /* True iff e is an error that means the connection was refused */ #define EVUTIL_ERR_CONNECT_REFUSED(e) \ ((e) == ECONNREFUSED) #else #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 #ifdef _EVENT_socklen_t #define socklen_t _EVENT_socklen_t #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 #endif #ifdef SHUT_BOTH #define EVUTIL_SHUT_BOTH SHUT_BOTH #else #define EVUTIL_SHUT_BOTH 2 #endif /* 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. */ int EVUTIL_ISALPHA(char c); int EVUTIL_ISALNUM(char c); int EVUTIL_ISSPACE(char c); int EVUTIL_ISDIGIT(char c); int EVUTIL_ISXDIGIT(char c); int EVUTIL_ISPRINT(char c); int EVUTIL_ISLOWER(char c); int EVUTIL_ISUPPER(char c); char EVUTIL_TOUPPER(char c); char EVUTIL_TOLOWER(char c); /** 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); int evutil_read_file(const char *filename, char **content_out, size_t *len_out, int is_binary); int evutil_socket_connect(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen); int evutil_socket_finished_connecting(evutil_socket_t fd); 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); long _evutil_weakrand(void); /* 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 /* 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); void evutil_set_evdns_getaddrinfo_fn(evdns_getaddrinfo_fn fn); struct evutil_addrinfo *evutil_new_addrinfo(struct sockaddr *sa, ev_socklen_t socklen, const struct evutil_addrinfo *hints); struct evutil_addrinfo *evutil_addrinfo_append(struct evutil_addrinfo *first, struct evutil_addrinfo *append); void evutil_adjust_hints_for_addrconfig(struct evutil_addrinfo *hints); int evutil_getaddrinfo_common(const char *nodename, const char *servname, struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum); int 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); /** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or * ::1). */ 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. */ const char *evutil_format_sockaddr_port(const struct sockaddr *sa, char *out, size_t outlen); long evutil_tv_to_msec(const struct timeval *tv); int evutil_hex_char_to_int(char c); #ifdef WIN32 HANDLE 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__) #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 #ifdef __cplusplus } #endif #endif lldpd-0.7.7/libevent/arc4random.c0000644000076400001440000003065712074262762013576 00000000000000/* 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 #ifdef WIN32 #include #include #else #include #include #include #include #ifdef _EVENT_HAVE_SYS_SYSCTL_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 int arc4_seeded_ok; 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)); memset(buf, 0, sizeof(buf)); arc4_seeded_ok = 1; return 0; } #endif #if defined(_EVENT_HAVE_SYS_SYSCTL_H) && defined(_EVENT_HAVE_SYSCTL) #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID #define TRY_SEED_SYSCTL_LINUX static int arc4_seed_sysctl_linux(void) { /* Based on code by William Ahern, this function tries to use the * RANDOM_UUID sysctl to get entropy from the kernel. This can work * even if /dev/urandom is inaccessible for some reason (e.g., we're * running in a chroot). */ int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; 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 != sysctl(mib, 3, &buf[len], &n, NULL, 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-0.7.7/libevent/Makefile.in0000644000076400001440000015047112237715703013441 00000000000000# Makefile.in generated by automake 1.14 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 @SELECT_BACKEND_TRUE@am__append_5 = select.c @POLL_BACKEND_TRUE@am__append_6 = poll.c @DEVPOLL_BACKEND_TRUE@am__append_7 = devpoll.c @KQUEUE_BACKEND_TRUE@am__append_8 = kqueue.c @EPOLL_BACKEND_TRUE@am__append_9 = epoll.c @EVPORT_BACKEND_TRUE@am__append_10 = evport.c @SIGNAL_SUPPORT_TRUE@am__append_11 = signal.c @INSTALL_LIBEVENT_FALSE@am__append_12 = $(EVENT1_HDRS) subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in $(srcdir)/libevent.pc.in \ $(srcdir)/libevent_openssl.pc.in \ $(srcdir)/libevent_pthreads.pc.in epoll_sub.c \ $(am__dist_bin_SCRIPTS_DIST) $(top_srcdir)/../depcomp \ $(am__include_HEADERS_DIST) $(am__noinst_HEADERS_DIST) \ ChangeLog README $(top_srcdir)/../compile \ $(top_srcdir)/../config.guess $(top_srcdir)/../config.sub \ $(top_srcdir)/../install-sh $(top_srcdir)/../ltmain.sh \ $(top_srcdir)/../missing 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/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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = libevent.pc libevent_openssl.pc \ libevent_pthreads.pc CONFIG_CLEAN_VPATH_FILES = 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)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = libevent_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1) am__libevent_la_SOURCES_DIST = event.c evthread.c buffer.c \ bufferevent.c bufferevent_sock.c bufferevent_filter.c \ bufferevent_pair.c listener.c bufferevent_ratelim.c evmap.c \ log.c evutil.c evutil_rand.c strlcpy.c select.c poll.c \ devpoll.c kqueue.c epoll.c evport.c signal.c win32select.c \ evthread_win32.c buffer_iocp.c event_iocp.c \ bufferevent_async.c event_tagging.c http.c evdns.c evrpc.c @SELECT_BACKEND_TRUE@am__objects_1 = select.lo @POLL_BACKEND_TRUE@am__objects_2 = poll.lo @DEVPOLL_BACKEND_TRUE@am__objects_3 = devpoll.lo @KQUEUE_BACKEND_TRUE@am__objects_4 = kqueue.lo @EPOLL_BACKEND_TRUE@am__objects_5 = epoll.lo @EVPORT_BACKEND_TRUE@am__objects_6 = evport.lo @SIGNAL_SUPPORT_TRUE@am__objects_7 = signal.lo @BUILD_WIN32_FALSE@am__objects_8 = $(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) @BUILD_WIN32_TRUE@am__objects_8 = win32select.lo evthread_win32.lo \ @BUILD_WIN32_TRUE@ buffer_iocp.lo event_iocp.lo \ @BUILD_WIN32_TRUE@ bufferevent_async.lo $(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) am__objects_9 = event.lo evthread.lo buffer.lo bufferevent.lo \ bufferevent_sock.lo bufferevent_filter.lo bufferevent_pair.lo \ listener.lo bufferevent_ratelim.lo evmap.lo log.lo evutil.lo \ evutil_rand.lo strlcpy.lo $(am__objects_8) am__objects_10 = event_tagging.lo http.lo evdns.lo evrpc.lo am_libevent_la_OBJECTS = $(am__objects_9) $(am__objects_10) 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__libevent_core_la_SOURCES_DIST = event.c evthread.c buffer.c \ bufferevent.c bufferevent_sock.c bufferevent_filter.c \ bufferevent_pair.c listener.c bufferevent_ratelim.c evmap.c \ log.c evutil.c evutil_rand.c strlcpy.c select.c poll.c \ devpoll.c kqueue.c epoll.c evport.c signal.c win32select.c \ evthread_win32.c buffer_iocp.c event_iocp.c \ bufferevent_async.c am_libevent_core_la_OBJECTS = $(am__objects_9) 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_10) 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 = 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__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)/../depcomp am__depfiles_maybe = depfiles 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) 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) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(pkgconfig_DATA) am__include_HEADERS_DIST = event.h evhttp.h evdns.h evrpc.h evutil.h am__noinst_HEADERS_DIST = util-internal.h mm-internal.h \ ipv6-internal.h evrpc-internal.h strlcpy-internal.h \ evbuffer-internal.h bufferevent-internal.h http-internal.h \ event-internal.h evthread-internal.h ht-internal.h \ defer-internal.h minheap-internal.h log-internal.h \ evsignal-internal.h evmap-internal.h changelist-internal.h \ iocp-internal.h ratelim-internal.h \ WIN32-Code/event2/event-config.h WIN32-Code/tree.h \ compat/sys/queue.h event.h evhttp.h evdns.h evrpc.h evutil.h HEADERS = $(include_HEADERS) $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.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)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) 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) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip 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@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ 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@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ 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@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ 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@ 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.7' means that we need automake 1.7 or later (and we do). AUTOMAKE_OPTIONS = foreign 1.7 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.0 # 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 = 6:9:1 # 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 # 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 $(am__append_2) $(am__append_4) # These sources are conditionally added by configure.in or conditionally # included from other files. PLATFORM_DEPENDENT_SRC = \ epoll_sub.c \ arc4random.c EXTRA_DIST = \ LICENSE \ autogen.sh \ event_rpcgen.py \ libevent.pc.in \ make-event-config.sed \ Doxyfile \ whatsnew-2.0.txt \ Makefile.nmake test/Makefile.nmake \ $(PLATFORM_DEPENDENT_SRC) 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) SUBDIRS = . include sample test @BUILD_WIN32_FALSE@SYS_LIBS = @BUILD_WIN32_TRUE@SYS_LIBS = -lws2_32 -lshell32 -ladvapi32 @BUILD_WIN32_FALSE@SYS_SRC = $(am__append_5) $(am__append_6) \ @BUILD_WIN32_FALSE@ $(am__append_7) $(am__append_8) \ @BUILD_WIN32_FALSE@ $(am__append_9) $(am__append_10) \ @BUILD_WIN32_FALSE@ $(am__append_11) @BUILD_WIN32_TRUE@SYS_SRC = win32select.c evthread_win32.c \ @BUILD_WIN32_TRUE@ buffer_iocp.c event_iocp.c \ @BUILD_WIN32_TRUE@ bufferevent_async.c $(am__append_5) \ @BUILD_WIN32_TRUE@ $(am__append_6) $(am__append_7) \ @BUILD_WIN32_TRUE@ $(am__append_8) $(am__append_9) \ @BUILD_WIN32_TRUE@ $(am__append_10) $(am__append_11) @BUILD_WIN32_FALSE@SYS_INCLUDES = @BUILD_WIN32_TRUE@SYS_INCLUDES = -IWIN32-Code BUILT_SOURCES = include/event2/event-config.h CORE_SRC = event.c evthread.c buffer.c \ bufferevent.c bufferevent_sock.c bufferevent_filter.c \ bufferevent_pair.c listener.c bufferevent_ratelim.c \ evmap.c log.c evutil.c evutil_rand.c strlcpy.c $(SYS_SRC) EXTRA_SRC = event_tagging.c http.c evdns.c evrpc.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 GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC) libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) libevent_la_LDFLAGS = $(GENERIC_LDFLAGS) libevent_core_la_SOURCES = $(CORE_SRC) libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_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 = $(EXTRA_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) noinst_HEADERS = util-internal.h mm-internal.h ipv6-internal.h \ evrpc-internal.h strlcpy-internal.h evbuffer-internal.h \ bufferevent-internal.h http-internal.h event-internal.h \ evthread-internal.h ht-internal.h defer-internal.h \ minheap-internal.h log-internal.h evsignal-internal.h \ evmap-internal.h changelist-internal.h iocp-internal.h \ ratelim-internal.h WIN32-Code/event2/event-config.h \ WIN32-Code/tree.h compat/sys/queue.h $(am__append_12) EVENT1_HDRS = event.h evhttp.h evdns.h evrpc.h evutil.h @INSTALL_LIBEVENT_TRUE@include_HEADERS = $(EVENT1_HDRS) AM_CPPFLAGS = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES) DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.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 .PRECIOUS: 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__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(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 $@ distclean-hdr: -rm -f config.h stamp-h1 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 $@ 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) 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) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/epoll_sub.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer_iocp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_async.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_openssl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_pair.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_ratelim.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bufferevent_sock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devpoll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epoll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evdns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_iocp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_tagging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evport.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evrpc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread_pthread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evthread_win32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evutil_rand.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kqueue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/poll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32select.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt 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) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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-recursive 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 distdir: $(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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || 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) | GZIP=$(GZIP_ENV) gzip -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-tarZ: distdir @echo WARNING: "Support for shar distribution archives 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 distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(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 \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(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 check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(DATA) $(HEADERS) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: clean-generic: 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) -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) clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-includeHEADERS install-pkgconfigDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-dist_binSCRIPTS install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-pkgconfigDATA .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ 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-dist_binSCRIPTS install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-includeHEADERS install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-pkgconfigDATA install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-pkgconfigDATA include/event2/event-config.h: config.h make-event-config.sed test -d include/event2 || $(MKDIR_P) include/event2 $(SED) -f $(srcdir)/make-event-config.sed < config.h > $@T mv -f $@T $@ verify: check doxygen: FORCE doxygen $(srcdir)/Doxyfile FORCE: # 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-0.7.7/libevent/changelist-internal.h0000644000076400001440000001072212074262762015473 00000000000000/* * 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_H_ #define _CHANGELIST_H_ /* 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; }; /* 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-0.7.7/libevent/configure.ac0000644000076400001440000005304612155052147013655 00000000000000dnl configure.in for libevent dnl 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_PREREQ(2.59) AC_INIT(event.c) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE(libevent,2.0.21-stable-dev) AC_CONFIG_HEADERS(config.h) AC_DEFINE(NUMERIC_VERSION, 0x02001501, [Numeric representation of the version]) dnl Initialize prefix. if test "$prefix" = "NONE"; then prefix="/usr/local" fi 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. AC_PROG_CC 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 is only available in Autoconf >= 2.59b; workaround for older # versions ifdef([AC_PROG_SED], [AC_PROG_SED], [ AC_CHECK_PROGS(SED, [gsed 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. case "$host_os" in darwin*) CFLAGS="$CFLAGS -Wno-deprecated-declarations" ;; esac AC_ARG_ENABLE(gcc-warnings, AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings with GCC)) 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([function-sections], AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]), [], [enable_function_sections=no]) AC_PROG_LIBTOOL dnl Uncomment "AC_DISABLE_SHARED" to make shared librraries 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_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]) AC_SEARCH_LIBS([clock_gettime], [rt]) 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 version of GCC) AC_MSG_CHECKING(for WIN32) AC_TRY_COMPILE(, [ #ifndef WIN32 die horribly #endif ], bwin32=true; AC_MSG_RESULT(yes), bwin32=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_TRY_COMPILE(, [ #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_CHECK_HEADERS([openssl/bio.h]) if test "$enable_openssl" = "yes"; then save_LIBS="$LIBS" LIBS="" OPENSSL_LIBS="" have_openssl=no AC_SEARCH_LIBS([SSL_new], [ssl], [have_openssl=yes OPENSSL_LIBS="$LIBS -lcrypto $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD" AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl])], [have_openssl=no], [-lcrypto $EV_LIB_GDI $EV_LIB_WS32 $OPENSSL_LIBADD]) LIBS="$save_LIBS" AC_SUBST(OPENSSL_LIBS) fi dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h sys/wait.h netdb.h]) AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS(sys/sysctl.h, [], [], [ #ifdef HAVE_SYS_PARAM_H #include #endif ]) 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_RANDOM, RANDOM_UUID, KERN_ARND], [], [], [[#include #include ]] ) fi AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue) AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue) AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue) if test x$bwin32 = xtrue; then AC_SEARCH_LIBS([getservbyname],[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([gettimeofday vasprintf fcntl clock_gettime strtok_r strsep]) AC_CHECK_FUNCS([getnameinfo strlcpy inet_ntop inet_pton signal sigaction strtoll inet_aton pipe eventfd sendfile mmap splice arc4random arc4random_buf issetugid geteuid getegid getprotobynumber setenv unsetenv putenv sysctl]) AC_CHECK_FUNCS([umask]) 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 AC_CHECK_FUNCS([getservbyname]) # 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_TRY_COMPILE([ #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_TRY_COMPILE([ #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 AC_CHECK_SIZEOF(long) AC_MSG_CHECKING(for F_SETFD in fcntl.h) AC_EGREP_CPP(yes, [ #define _GNU_SOURCE #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_TRY_RUN( #include #include #include #include #include #include int main(int argc, char **argv) { int kq; int n; int fd[[2]]; struct kevent ev; struct timespec ts; char buf[[8000]]; if (pipe(fd) == -1) exit(1); if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1) exit(1); while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf)) ; if ((kq = kqueue()) == -1) exit(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) exit(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) exit(1); exit(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_TRY_RUN( #include #include #include #include #include #include int epoll_create(int size) { return (syscall(__NR_epoll_create, size)); } int main(int argc, char **argv) { int epfd; epfd = epoll_create(256); exit (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_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , , [#define _GNU_SOURCE #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_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_MSG_CHECKING([for socklen_t]) AC_TRY_COMPILE([ #include #include ], [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])] ) AC_MSG_CHECKING([whether our compiler supports __func__]) AC_TRY_COMPILE([], [ const char *cp = __func__; ], AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) AC_MSG_CHECKING([whether our compiler supports __FUNCTION__]) AC_TRY_COMPILE([], [ const char *cp = __FUNCTION__; ], AC_MSG_RESULT([yes]) AC_DEFINE(__func__, __FUNCTION__, [Define to appropriate substitue if compiler doesnt have __func__]), AC_MSG_RESULT([no]) AC_DEFINE(__func__, __FILE__, [Define to appropriate substitue if compiler doesnt have __func__]))) # 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(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 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 = xyes && 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) CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum -Werror" 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" 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"]) AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc] ) AC_OUTPUT(Makefile include/Makefile test/Makefile sample/Makefile) lldpd-0.7.7/libevent/strlcpy-internal.h0000644000076400001440000000050012074262762015043 00000000000000#ifndef _STRLCPY_INTERNAL_H_ #define _STRLCPY_INTERNAL_H_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.h" #ifndef _EVENT_HAVE_STRLCPY #include size_t _event_strlcpy(char *dst, const char *src, size_t siz); #define strlcpy _event_strlcpy #endif #ifdef __cplusplus } #endif #endif lldpd-0.7.7/libevent/ipv6-internal.h0000644000076400001440000000465512074262762014246 00000000000000/* * 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 _EVENT_IPV6_INTERNAL_H #define _EVENT_IPV6_INTERNAL_H #include #ifdef _EVENT_HAVE_SYS_SOCKET_H #include #endif #include "event2/event-config.h" #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-0.7.7/libevent/WIN32-Code/0000755000076400001440000000000012237716101013107 500000000000000lldpd-0.7.7/libevent/WIN32-Code/tree.h0000644000076400001440000013035412074262762014155 00000000000000/* $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_ */ /* $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-0.7.7/libevent/WIN32-Code/event2/0000755000076400001440000000000012237716101014312 500000000000000lldpd-0.7.7/libevent/WIN32-Code/event2/event-config.h0000644000076400001440000002562612155052147017004 00000000000000/* 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_aton' function. */ /* #undef _EVENT_HAVE_INET_ATON */ /* 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_DEVPOLL_H */ /* 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 0x02001501 /* 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 /* Define to 1 if you have the ANSI C header files. */ #define _EVENT_STDC_HEADERS 1 /* 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.0.21-stable-dev" /* Define to appropriate substitue if compiler doesnt have __func__ */ #define _EVENT___func__ __FUNCTION__ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef _EVENT_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 _EVENT___cplusplus #define _EVENT_inline __inline #endif /* Define to `int' if does not define. */ /* #undef _EVENT_pid_t */ /* 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-0.7.7/libevent/ratelim-internal.h0000644000076400001440000000775012074262762015016 00000000000000/* * 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_ #define _RATELIM_INTERNAL_H_ #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-0.7.7/libevent/evutil_rand.c0000644000076400001440000001063012074262762014045 00000000000000/* * 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 #include "util-internal.h" #include "evthread-internal.h" #ifdef _EVENT_HAVE_ARC4RANDOM #include #include int evutil_secure_rng_init(void) { /* call arc4random() now to force it to self-initialize */ (void) arc4random(); return 0; } int evutil_secure_rng_global_setup_locks_(const int enable_locks) { return 0; } static void ev_arc4random_buf(void *buf, size_t n) { #if defined(_EVENT_HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) return arc4random_buf(buf, n); #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.) */ if (arc4random_buf != NULL) { return arc4random_buf(buf, n); } #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 int evutil_secure_rng_init(void) { int val; _ARC4_LOCK(); if (!arc4_seeded_ok) arc4_stir(); val = arc4_seeded_ok ? 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); } 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); } lldpd-0.7.7/libevent/evmap-internal.h0000644000076400001440000000755212074262762014471 00000000000000/* * 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_H_ #define _EVMAP_H_ /** @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); void *evmap_io_get_fdinfo(struct event_io_map *ctx, evutil_socket_t fd); void evmap_check_integrity(struct event_base *base); #endif /* _EVMAP_H_ */ lldpd-0.7.7/libevent/evthread.c0000644000076400001440000002746212074262762013346 00000000000000/* * 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" #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 /* 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; } int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) { struct evthread_lock_callbacks *target = _evthread_lock_debugging_enabled ? &_original_lock_fns : &_evthread_lock_fns; 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_lock_debugging_enabled ? &_original_cond_fns : &_evthread_cond_fns; 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; } struct debug_lock { 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->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); if (_original_lock_fns.free) { _original_lock_fns.free(lock->lock, lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); } lock->lock = NULL; lock->count = -100; mm_free(lock); } static void evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) { ++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) { 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) { EVUTIL_ASSERT(lock->held_by == _evthread_id_fn()); 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); 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; } void evthread_enable_lock_debuging(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_; EVUTIL_ASSERT(enable_locks && _evthread_lock_debugging_enabled); EVUTIL_ASSERT(lock->locktype == locktype); EVUTIL_ASSERT(lock->lock == NULL); 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) { 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) { 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-0.7.7/libevent/m4/0000755000076400001440000000000012237716100011754 500000000000000lldpd-0.7.7/libevent/m4/ltoptions.m40000644000076400001440000003007312237715654014211 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 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 7 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_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_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=default]) test -z "$pic_mode" && 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-0.7.7/libevent/m4/ltsugar.m40000644000076400001440000001042412237715654013635 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 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-0.7.7/libevent/m4/ltversion.m40000644000076400001440000000126212237715654014201 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 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 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) lldpd-0.7.7/libevent/m4/lt~obsolete.m40000644000076400001440000001375612237715655014542 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 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-0.7.7/libevent/m4/libtool.m40000644000076400001440000106000712237715654013623 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 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) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # 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 # 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 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.58])dnl We use AC_INCLUDES_DEFAULT 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_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _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 _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which 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 "X${COLLECT_NAMES+set}" != Xset; 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\\"\\\`\\\\\\"" ;; *) 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\\"\\\`\\\\\\"" ;; *) 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 $lt_write_fail = 0 && 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 "$silent" = yes && 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 which 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 # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _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 "X${COLLECT_NAMES+set}" != Xset; 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) _LT_PROG_REPLACE_SHELLFNS 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' TIMESTAMP='$TIMESTAMP' 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 $_lt_result -eq 0; 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 cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru 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 $_lt_result -eq 0 && $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[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; 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 "$lt_cv_ld_force_load" = "no"; 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 "$lt_cv_ld_force_load" = "yes"; 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*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; 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 "$lt_cv_apple_cc_single_mod" != "yes"; 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 "${lt_cv_aix_libpath+set}" = 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 which will find a shell with a builtin # printf (which 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], [ --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 "$GCC" = yes; 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 in which 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 "x$enable_libtool_lock" != xno && 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 which ABI we are using. 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 which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; 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* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. 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 ;; ppc64-*linux*|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" ;; ppc*-*linux*|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 x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. 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*) 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=cru} _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 "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; 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 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" # 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 x"[$]$2" = xyes; 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 x"[$]$2" = xyes; 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; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # 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 $i != 17 # 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 "$cross_compiling" = yes; 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 -fvisbility=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 "x$enable_dlopen" != xyes; 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 ]) ;; *) 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 "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && 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 "x$lt_cv_dlopen_self" = xyes; 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 "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; 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 "$hard_links" = no; 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 in which 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 "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # 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 "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; 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 "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; 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_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 AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; 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` 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" else 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 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 "$host_cpu" = ia64; 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 # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # 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}' else # 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' fi 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%'\''`; test $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} $libname${shared_ext}' 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=yes 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 "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; 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 "$lt_cv_prog_gnu_ld" = yes; 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 ;; # 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 # Append ld.so.conf contents 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*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac 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 if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; 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 "$with_gnu_ld" = yes; 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=freebsd-elf 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 "$with_gnu_ld" = yes; 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 "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _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], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which 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 which 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 "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; 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 "$with_gnu_ld" = yes; 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 /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*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 ;; 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 case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) 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 "$lt_cv_path_NM" != "no"; 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 /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) 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 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 "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # 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 "$GCC" = yes; 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 "$host_cpu" = ia64; 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 # 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 -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$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 -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/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 # and D for any global 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};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print 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 if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && 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 con'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* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$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 "$pipe_works" = yes; 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_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_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 "$GXX" = yes; 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 "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; 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']) ;; 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 "$host_cpu" = ia64; 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 "$host_cpu" != ia64; 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 "$GCC" = yes; 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 "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; 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']) ;; 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 "$host_cpu" = ia64; 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 ;; 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']) ;; 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' ;; # 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' ;; 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 which 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 AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". 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) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) 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 "$with_gnu_ld" = yes; 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 "$lt_use_gnu_ld_interface" = yes; 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 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 "$host_cpu" != ia64; 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 (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; 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 ;; 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 "$host_os" = linux-dietlibc; 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 "$tmp_diet" = no 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' ;; 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 "x$supports_anon_versioning" = xyes; 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 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 "x$supports_anon_versioning" = xyes; 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 can not *** 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no; 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 "$GCC" = yes && 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 "$host_cpu" = ia64; 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 AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". 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) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; 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,' if test "$GCC" = yes; 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 "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; 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 "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi 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_use_runtimelinking" = yes; 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 "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; 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 "$with_gnu_ld" = yes; 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 # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' 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~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $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 "$GCC" = yes; 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 $output_objdir/$soname = $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 $output_objdir/$soname = $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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes; 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 "$lt_cv_irix_exported_symbol" = yes; 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 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 ;; 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*) 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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _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' ;; esac 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 _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "x$host_vendor" = xsequent; 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 "$GCC" = yes; 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 can NOT 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 "$GCC" = yes; 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 x$host_vendor = xsni; 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no && 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 "$enable_shared" = yes && test "$GCC" = yes; 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 which 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; 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 "$_lt_caught_CXX_error" != yes; 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 "$GXX" = yes; 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 "$GXX" = yes; 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 "$with_gnu_ld" = yes; 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 "$host_cpu" = ia64; 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 # need to do runtime linking. 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 ;; 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,' if test "$GXX" = yes; 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 "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; 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 "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi 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_use_runtimelinking" = yes; 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 "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; 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 "$with_gnu_ld" = yes; 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 # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' 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~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $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 (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; 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) ;; 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 $output_objdir/$soname = $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 "$GXX" = yes; 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 $output_objdir/$soname = $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 $with_gnu_ld = no; 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 "$GXX" = yes; then if test $with_gnu_ld = no; 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 "$GXX" = yes; then if test "$with_gnu_ld" = no; 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 "x$supports_anon_versioning" = xyes; 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 ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) 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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 $LDFLAGS $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 -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 $LDFLAGS $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 -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 can NOT 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no && 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 "$_lt_caught_CXX_error" != yes 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 ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; 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 $p = "-L" || test $p = "-R"; 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 "$pre_test_object_deps_done" = no; 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 "$pre_test_object_deps_done" = no; 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)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; 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 "X$F77" = "Xno"; 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 "$_lt_disable_F77" != yes; 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "$_lt_disable_F77" != yes 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 "X$FC" = "Xno"; 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 "$_lt_disable_FC" != yes; 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "$_lt_disable_FC" != yes 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 "x${GCJFLAGS+set}" = xset || 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 $lt_ac_count -gt 10 && 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], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) 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_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which 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-0.7.7/libevent/m4/acx_pthread.m40000644000076400001440000002526012074262762014436 00000000000000##### 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-0.7.7/libevent/m4/ac_backport_259_ssizet.m40000644000076400001440000000015012155052146016404 00000000000000AN_IDENTIFIER([ssize_t], [AC_TYPE_SSIZE_T]) AC_DEFUN([AC_TYPE_SSIZE_T], [AC_CHECK_TYPE(ssize_t, int)]) lldpd-0.7.7/libevent/evrpc.h0000644000076400001440000000366212074262762012664 00000000000000/* * 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 _EVRPC_H_ #define _EVRPC_H_ /** @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 /* _EVRPC_H_ */ lldpd-0.7.7/libevent/evthread_pthread.c0000644000076400001440000001144512074262762015047 00000000000000/* * 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" /* With glibc we need to define this to get PTHREAD_MUTEX_RECURSIVE. */ #define _GNU_SOURCE #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-0.7.7/libevent/log-internal.h0000644000076400001440000000475212074262762014141 00000000000000/* * 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_H_ #define _LOG_H_ #include "event2/util.h" #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) void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN; void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2); void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN; void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(2,3); void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN; void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2); void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2); void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2); #ifdef USE_DEBUG #define event_debug(x) _event_debugx x #else #define event_debug(x) do {;} while (0) #endif #undef EV_CHECK_FMT #endif lldpd-0.7.7/libevent/evmap.c0000644000076400001440000005170312074262762012647 00000000000000/* * 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" #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 "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_list events; ev_uint16_t nread; ev_uint16_t nwrite; }; /* An entry for an evmap_signal list: notes all the events that want to know when a signal triggers. */ struct evmap_signal { struct event_list 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; while (nentries <= slot) nentries <<= 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) { TAILQ_INIT(&entry->events); entry->nread = 0; entry->nwrite = 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, 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; if (nread) old |= EV_READ; if (nwrite) old |= EV_WRITE; 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 (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff)) { event_warnx("Too many events reading or writing on fd %d", (int)fd); return -1; } if (EVENT_DEBUG_MODE_IS_ON() && (old_ev = TAILQ_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; TAILQ_INSERT_TAIL(&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, 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; if (nread) old |= EV_READ; if (nwrite) old |= EV_WRITE; 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 (res) { void *extra = ((char*)ctx) + sizeof(struct evmap_io); if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) return (-1); retval = 1; } ctx->nread = nread; ctx->nwrite = nwrite; TAILQ_REMOVE(&ctx->events, 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 EVUTIL_ASSERT(fd < io->nentries); #endif GET_IO_SLOT(ctx, io, fd, evmap_io); EVUTIL_ASSERT(ctx); TAILQ_FOREACH(ev, &ctx->events, ev_io_next) { if (ev->ev_events & events) event_active_nolock(ev, ev->ev_events & events, 1); } } /* code specific to signals */ static void evmap_signal_init(struct evmap_signal *entry) { TAILQ_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 >= 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 (TAILQ_EMPTY(&ctx->events)) { if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } TAILQ_INSERT_TAIL(&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 >= map->nentries) return (-1); GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); if (TAILQ_FIRST(&ctx->events) == TAILQ_LAST(&ctx->events, event_list)) { if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } TAILQ_REMOVE(&ctx->events, ev, ev_signal_next); 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; EVUTIL_ASSERT(sig < map->nentries); GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); TAILQ_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; } /** 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; } #ifdef DEBUG_CHANGELIST /** Make sure that the changelist is consistent with the evmap structures. */ static void event_changelist_check(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); } for (i = 0; i < base->io.nentries; ++i) { struct evmap_io *io = base->io.entries[i]; struct event_changelist_fdinfo *f; if (!io) continue; f = (void*) ( ((char*)io) + sizeof(struct evmap_io) ); if (f->idxplus1) { struct event_change *c = &changelist->changes[f->idxplus1 - 1]; EVUTIL_ASSERT(c->fd == i); } } } #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; 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 = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); } if (events & EV_WRITE) { change->write_change = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); } 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; event_changelist_check(base); change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); event_changelist_check(base); if (!change) return -1; /* A delete removes any previous 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. As well as checking the current operation we should also check the original set of events to make sure were not ignoring the case where the add operation is present on an event that was already set. 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 & EV_CHANGE_ADD)) change->read_change = 0; else change->read_change = EV_CHANGE_DEL; } if (events & EV_WRITE) { if (!(change->old_events & EV_WRITE) && (change->write_change & EV_CHANGE_ADD)) change->write_change = 0; else change->write_change = EV_CHANGE_DEL; } event_changelist_check(base); return (0); } void evmap_check_integrity(struct event_base *base) { #define EVLIST_X_SIGFOUND 0x1000 #define EVLIST_X_IOFOUND 0x2000 evutil_socket_t i; struct event *ev; struct event_io_map *io = &base->io; struct event_signal_map *sigmap = &base->sigmap; #ifdef EVMAP_USE_HT struct event_map_entry **mapent; #endif int nsignals, ntimers, nio; nsignals = ntimers = nio = 0; TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED); EVUTIL_ASSERT(ev->ev_flags & EVLIST_INIT); ev->ev_flags &= ~(EVLIST_X_SIGFOUND|EVLIST_X_IOFOUND); } #ifdef EVMAP_USE_HT HT_FOREACH(mapent, event_io_map, io) { struct evmap_io *ctx = &(*mapent)->ent.evmap_io; i = (*mapent)->fd; #else for (i = 0; i < io->nentries; ++i) { struct evmap_io *ctx = io->entries[i]; if (!ctx) continue; #endif TAILQ_FOREACH(ev, &ctx->events, ev_io_next) { EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_IOFOUND)); EVUTIL_ASSERT(ev->ev_fd == i); ev->ev_flags |= EVLIST_X_IOFOUND; nio++; } } for (i = 0; i < sigmap->nentries; ++i) { struct evmap_signal *ctx = sigmap->entries[i]; if (!ctx) continue; TAILQ_FOREACH(ev, &ctx->events, ev_signal_next) { EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_SIGFOUND)); EVUTIL_ASSERT(ev->ev_fd == i); ev->ev_flags |= EVLIST_X_SIGFOUND; nsignals++; } } TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { if (ev->ev_events & (EV_READ|EV_WRITE)) { EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_IOFOUND); --nio; } if (ev->ev_events & EV_SIGNAL) { EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_SIGFOUND); --nsignals; } } EVUTIL_ASSERT(nio == 0); EVUTIL_ASSERT(nsignals == 0); /* There is no "EVUTIL_ASSERT(ntimers == 0)": eventqueue is only for * pending signals and io events. */ } lldpd-0.7.7/libevent/http.c0000644000076400001440000033123512155052147012511 00000000000000/* * 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" #ifdef _EVENT_HAVE_SYS_PARAM_H #include #endif #ifdef _EVENT_HAVE_SYS_TYPES_H #include #endif #ifdef _EVENT_HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_IOCCOM_H #include #endif #ifndef WIN32 #include #include #include #include #else #include #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 #include #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/bufferevent_compat.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 bind_socket_ai(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 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_decode_uri_internal(const char *uri, size_t length, char *ret, int decode_plus); 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_HEAD); } /** Helper: adds the event 'ev' with the timeout 'timeout', or with * default_timeout if timeout is -1. */ static int evhttp_add_event(struct event *ev, int timeout, int default_timeout) { if (timeout != 0) { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = timeout != -1 ? timeout : default_timeout; return event_add(ev, &tv); } else { return event_add(ev, NULL); } } /** 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; bufferevent_enable(evcon->bufev, EV_WRITE); /* Disable the read callback: we don't actually care about data; * we only care about close detection. (We don't disable reading, * since we *do* want to learn about any close events.) */ bufferevent_setcb(evcon->bufev, NULL, /*read*/ evhttp_write_cb, evhttp_error_cb, evcon); } 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 */ method = evhttp_method(req->type); 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); } } /* 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]; #ifndef WIN32 struct tm cur; #endif struct tm *cur_p; time_t t = time(NULL); #ifdef WIN32 cur_p = gmtime(&t); #else gmtime_r(&t, &cur); cur_p = &cur; #endif if (strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 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) { evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=ISO-8859-1"); } } /* 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"); } } /** 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 (evbuffer_get_length(req->output_buffer) > 0) { /* * For a request, we add the POST data, for a reply, this * is the regular data. */ /* XXX We might want to support waiting (a limited amount of time) for a continue status line from the server before sending POST/PUT message bodies. */ 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_connection_error error) { switch (error) { case EVCON_HTTP_TIMEOUT: case EVCON_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 EVCON_HTTP_INVALID_HEADER: case EVCON_HTTP_BUFFER_ERROR: case EVCON_HTTP_REQUEST_CANCEL: 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); } /* 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_connection_error error) { struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); void (*cb)(struct evhttp_request *, void *); void *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; } /* when the request was canceled, the callback is not executed */ if (error != EVCON_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 */ TAILQ_REMOVE(&evcon->requests, req, next); evhttp_request_free(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); /* inform the user */ 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; if (con_outgoing) { /* idle or close the connection */ int need_close; TAILQ_REMOVE(&evcon->requests, req, next); req->evcon = NULL; evcon->state = EVCON_IDLE; need_close = evhttp_is_connection_close(req->flags, req->input_headers)|| evhttp_is_connection_close(req->flags, req->output_headers); /* 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 { /* * 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. * unless the callback specifically requested to own the request. */ if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) { evhttp_request_free(req); } } /* * 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, EVCON_HTTP_INVALID_HEADER); break; case ALL_DATA_READ: bufferevent_disable(evcon->bufev, EV_READ); evhttp_connection_done(evcon); break; case MORE_DATA_EXPECTED: case REQUEST_CANCELED: /* ??? */ default: bufferevent_enable(evcon->bufev, EV_READ); break; } } 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:/*separate error for this? XXX */ /* corrupted data */ evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); return; case REQUEST_CANCELED: /* request canceled */ evhttp_request_free(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, EVCON_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 */ event_debug(("Request body is too long")); evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 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(req); return; } } if (req->ntoread == 0) { bufferevent_disable(evcon->bufev, EV_READ); /* Completed content length */ evhttp_connection_done(evcon); return; } /* Read more! */ bufferevent_enable(evcon->bufev, EV_READ); } #define get_deferred_queue(evcon) \ (event_base_get_deferred_cb_queue((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 deferred_cb *cb, void *data) { struct evhttp_connection *evcon = data; evhttp_read_cb(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); EVUTIL_ASSERT(req != NULL); EVUTIL_ASSERT(evcon->state == EVCON_WRITING); /* 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; /* 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) { TAILQ_REMOVE(&evcon->requests, req, next); evhttp_request_free(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); } if (evcon->bufev != NULL) bufferevent_free(evcon->bufev); event_deferred_cb_cancel(get_deferred_queue(evcon), &evcon->read_more_deferred_cb); if (evcon->fd != -1) { shutdown(evcon->fd, EVUTIL_SHUT_WR); 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_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; /* 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; /* 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) { /* 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; } /* we need to clean up any buffered data */ tmp = bufferevent_get_output(evcon->bufev); evbuffer_drain(tmp, evbuffer_get_length(tmp)); tmp = bufferevent_get_input(evcon->bufev); evbuffer_drain(tmp, evbuffer_get_length(tmp)); 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; if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); /* XXXX handle failure from evhttp_add_event */ evhttp_add_event(&evcon->retry_ev, MIN(3600, 2 << evcon->retry_cnt), HTTP_CONNECT_TIMEOUT); evcon->retry_cnt++; return; } evhttp_connection_reset(evcon); /* * 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(request); } } 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); 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); return; } if (what & BEV_EVENT_TIMEOUT) { evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { evhttp_connection_fail(evcon, EVCON_HTTP_EOF); } else { evhttp_connection_fail(evcon, EVCON_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 (!(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; } /* 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 (evcon->timeout == -1) bufferevent_settimeout(evcon->bufev, HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); else { struct timeval tv; tv.tv_sec = evcon->timeout; tv.tv_usec = 0; bufferevent_set_timeouts(evcon->bufev, &tv, &tv); } /* 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 = 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) { char *method; char *uri; char *version; const char *hostname; const char *scheme; /* Parse the request line */ method = strsep(&line, " "); if (line == NULL) return (-1); uri = strsep(&line, " "); if (line == NULL) return (-1); version = strsep(&line, " "); if (line != NULL) return (-1); /* First line */ if (strcmp(method, "GET") == 0) { req->type = EVHTTP_REQ_GET; } else if (strcmp(method, "POST") == 0) { req->type = EVHTTP_REQ_POST; } else if (strcmp(method, "HEAD") == 0) { req->type = EVHTTP_REQ_HEAD; } else if (strcmp(method, "PUT") == 0) { req->type = EVHTTP_REQ_PUT; } else if (strcmp(method, "DELETE") == 0) { req->type = EVHTTP_REQ_DELETE; } else if (strcmp(method, "OPTIONS") == 0) { req->type = EVHTTP_REQ_OPTIONS; } else if (strcmp(method, "TRACE") == 0) { req->type = EVHTTP_REQ_TRACE; } else if (strcmp(method, "PATCH") == 0) { req->type = EVHTTP_REQ_PATCH; } else { req->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. */ } 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 ((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 line_length; /* XXX try */ line = evbuffer_readln(buffer, &line_length, 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 && line_length > req->evcon->max_headers_size) { mm_free(line); return (DATA_TOO_LONG); } req->headers_size = line_length; switch (req->kind) { case EVHTTP_REQUEST: if (evhttp_parse_request_line(req, line) == -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, const 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); line_len = strlen(line); newval = mm_realloc(header->value, old_len + line_len + 1); if (newval == NULL) return (-1); memcpy(newval + old_len, 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 line_length; while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF)) != NULL) { char *skey, *svalue; req->headers_size += line_length; 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, " "); 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) { /* Bad combination, we don't know when it will end */ event_warnx("%s: we got no content length, but the " "server wants to keep the connection open: %s.", __func__, connection); return (-1); } 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: return 1; case EVHTTP_REQ_TRACE: return 0; /* XXX May any of the below methods have a body? */ case EVHTTP_REQ_GET: case EVHTTP_REQ_HEAD: case EVHTTP_REQ_DELETE: case EVHTTP_REQ_OPTIONS: case EVHTTP_REQ_CONNECT: return 0; 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, EVCON_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? */ if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) { const char *expect; expect = evhttp_find_header(req->input_headers, "Expect"); if (expect) { if (!evutil_ascii_strcasecmp(expect, "100-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_send_error(req, HTTP_ENTITYTOOLARGE, NULL); return; } } if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) evhttp_send_continue(evcon, req); } else { evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL); return; } } } 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, EVCON_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, EVCON_HTTP_INVALID_HEADER); return; } else if (res == MORE_DATA_EXPECTED) { /* Need more header lines */ return; } /* Disable reading for now */ bufferevent_disable(evcon->bufev, EV_READ); /* 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) { evhttp_start_read(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, EVCON_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, unsigned short port) { return (evhttp_connection_base_new(NULL, NULL, address, port)); } struct evhttp_connection * evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, const char *address, unsigned short 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; evcon->timeout = -1; evcon->retry_cnt = evcon->retry_max = 0; if ((evcon->address = mm_strdup(address)) == NULL) { event_warn("%s: strdup failed", __func__); goto error; } if ((evcon->bufev = bufferevent_new(-1, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon)) == NULL) { event_warn("%s: bufferevent_new failed", __func__); goto error; } evcon->state = EVCON_DISCONNECTED; TAILQ_INIT(&evcon->requests); if (base != NULL) { evcon->base = base; bufferevent_base_set(base, evcon->bufev); } event_deferred_cb_init(&evcon->read_more_deferred_cb, evhttp_deferred_read_cb, evcon); evcon->dns_base = dnsbase; 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; } 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) { evcon->timeout = timeout_in_secs; if (evcon->timeout == -1) bufferevent_settimeout(evcon->bufev, HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); else bufferevent_settimeout(evcon->bufev, evcon->timeout, evcon->timeout); } 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; } int evhttp_connection_connect(struct evhttp_connection *evcon) { int old_state = evcon->state; if (evcon->state == EVCON_CONNECTING) return (0); evhttp_connection_reset(evcon); EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); evcon->flags |= EVHTTP_CON_OUTGOING; 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); } /* Set up a callback for successful connection setup */ bufferevent_setfd(evcon->bufev, evcon->fd); bufferevent_setcb(evcon->bufev, NULL /* evhttp_read_cb */, NULL /* evhttp_write_cb */, evhttp_connection_cb, evcon); bufferevent_settimeout(evcon->bufev, 0, evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT); /* make sure that we get a write callback */ bufferevent_enable(evcon->bufev, EV_WRITE); evcon->state = EVCON_CONNECTING; if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, AF_UNSPEC, evcon->address, evcon->port) < 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(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); /* 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 r * 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, EVCON_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(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) { /* Set up an event to read the headers */ 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); } } 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); need_close = (REQ_VERSION_BEFORE(req, 1, 1) && !evhttp_is_connection_keepalive(req->input_headers))|| evhttp_is_connection_close(req->flags, req->input_headers) || evhttp_is_connection_close(req->flags, req->output_headers); 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 (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(struct evhttp_request *req, struct evbuffer *databuf) { 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, 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; if (buf == NULL) return (NULL); if (len >= 0) end = uri+len; else end = uri+strlen(uri); 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)); 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'. */ static 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 (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; 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)); evhttp_add_header_internal(headers, key, decoded_value); mm_free(decoded_value); } 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; if (req->type == 0 || req->uri == NULL) { evhttp_send_error(req, HTTP_BADREQUEST, 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; if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) return (NULL); if (listen(fd, 128) == -1) { event_sock_warn(fd, "%s: listen", __func__); evutil_closesocket(fd); 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); } 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); } http->timeout = -1; evhttp_set_max_headers_size(http, EV_SIZE_MAX); evhttp_set_max_body_size(http, EV_SIZE_MAX); 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, unsigned short 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) { http->timeout = timeout_in_secs; } 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_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; } /* * 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; } /* * 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; } /** 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; 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 */ evcon = evhttp_connection_base_new( http->base, NULL, 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; evcon->flags |= EVHTTP_CON_INCOMING; evcon->state = EVCON_READING_FIRSTLINE; evcon->fd = fd; bufferevent_setfd(evcon->bufev, fd); return (evcon); } 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 (http->timeout != -1) evhttp_connection_set_timeout(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 */ /* todo: rename this function */ static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *ai, int reuse) { evutil_socket_t fd; int on = 1, r; int serrno; /* Create listen socket */ fd = socket(ai ? ai->ai_family : AF_INET, SOCK_STREAM, 0); if (fd == -1) { event_sock_warn(-1, "socket"); return (-1); } if (evutil_make_socket_nonblocking(fd) < 0) goto out; if (evutil_make_socket_closeonexec(fd) < 0) goto out; 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 bind_socket_ai(NULL, 0); aitop = make_addrinfo(address, port); if (aitop == NULL) return (-1); fd = bind_socket_ai(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 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; } 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-0.7.7/libevent/evdns.h0000644000076400001440000000366612074262762012670 00000000000000/* * 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 _EVDNS_H_ #define _EVDNS_H_ /** @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 /* _EVDNS_H_ */ lldpd-0.7.7/libevent/defer-internal.h0000644000076400001440000000716212074262762014443 00000000000000/* * 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_ #define _DEFER_INTERNAL_H_ #ifdef __cplusplus extern "C" { #endif #include "event2/event-config.h" #include struct deferred_cb; typedef void (*deferred_cb_fn)(struct deferred_cb *, void *); /** A deferred_cb is a callback that can be scheduled to run as part of * an event_base's event_loop, rather than running immediately. */ struct deferred_cb { /** Links to the adjacent active (pending) deferred_cb objects. */ TAILQ_ENTRY (deferred_cb) cb_next; /** True iff this deferred_cb is pending in an event_base. */ unsigned queued : 1; /** The function to execute when the callback runs. */ deferred_cb_fn cb; /** The function's second argument. */ void *arg; }; /** A deferred_cb_queue is a list of deferred_cb that we can add to and run. */ struct deferred_cb_queue { /** Lock used to protect the queue. */ void *lock; /** How many entries are in the queue? */ int active_count; /** Function called when adding to the queue from another thread. */ void (*notify_fn)(struct deferred_cb_queue *, void *); void *notify_arg; /** Deferred callback management: a list of deferred callbacks to * run active the active events. */ TAILQ_HEAD (deferred_cb_list, deferred_cb) deferred_cb_list; }; /** Initialize an empty, non-pending deferred_cb. @param deferred The deferred_cb structure to initialize. @param cb The function to run when the deferred_cb executes. @param arg The function's second argument. */ void event_deferred_cb_init(struct deferred_cb *, deferred_cb_fn, void *); /** Cancel a deferred_cb if it is currently scheduled in an event_base. */ void event_deferred_cb_cancel(struct deferred_cb_queue *, struct deferred_cb *); /** Activate a deferred_cb if it is not currently scheduled in an event_base. */ void event_deferred_cb_schedule(struct deferred_cb_queue *, struct deferred_cb *); #define LOCK_DEFERRED_QUEUE(q) \ EVLOCK_LOCK((q)->lock, 0) #define UNLOCK_DEFERRED_QUEUE(q) \ EVLOCK_UNLOCK((q)->lock, 0) #ifdef __cplusplus } #endif void event_deferred_cb_queue_init(struct deferred_cb_queue *); struct deferred_cb_queue *event_base_get_deferred_cb_queue(struct event_base *); #endif /* _EVENT_INTERNAL_H_ */ lldpd-0.7.7/libevent/config.h.in0000644000076400001440000002713512237715701013415 00000000000000/* 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 `arc4random' function. */ #undef HAVE_ARC4RANDOM /* 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 to 1 if you have the declaration of `KERN_RANDOM', and to 0 if you don't. */ #undef HAVE_DECL_KERN_RANDOM /* Define to 1 if you have the declaration of `RANDOM_UUID', and to 0 if you don't. */ #undef HAVE_DECL_RANDOM_UUID /* 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_ctl' function. */ #undef HAVE_EPOLL_CTL /* 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 `getnameinfo' function. */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the `getprotobynumber' function. */ #undef HAVE_GETPROTOBYNUMBER /* 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 `inet_aton' function. */ #undef HAVE_INET_ATON /* 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 if the system has zlib */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* 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 if the system has openssl */ #undef HAVE_OPENSSL /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_BIO_H /* Define to 1 if you have the `pipe' function. */ #undef HAVE_PIPE /* 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 `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_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 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 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_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_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_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 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 `vasprintf' function. */ #undef HAVE_VASPRINTF /* 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 the sub-directory in which 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 `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 `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Version number of package */ #undef VERSION /* Define to appropriate substitue if compiler doesnt have __func__ */ #undef __func__ /* 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 to `int' if does not define. */ #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-0.7.7/libevent/bufferevent_sock.c0000644000076400001440000004262012155052147015061 00000000000000/* * 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 #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 _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_adj_timeouts(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, be_socket_destruct, be_socket_adj_timeouts, be_socket_flush, be_socket_ctrl, }; #define be_socket_add(ev, t) \ _bufferevent_add_event((ev), (t)) 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 = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 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 (be_socket_add(&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 = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 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; /* 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 */ if (evbuffer_get_length(input) >= bufev->wm_read.low) _bufferevent_run_readcb(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); _bufferevent_run_eventcb(bufev, what); 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 = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 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); goto done; } else { connected = 1; #ifdef WIN32 if (BEV_IS_ASYNC(bufev)) { event_del(&bufev->ev_write); bufferevent_async_set_connected(bufev); _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); goto done; } #endif _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); 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) && evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { _bufferevent_run_writecb(bufev); } 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); 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, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, 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, struct sockaddr *sa, int socklen) { struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bev, struct bufferevent_private, bev); evutil_socket_t fd; int r = 0; int result=-1; int ownfd = 0; _bufferevent_incref_and_lock(bev); if (!bufev_p) goto done; fd = bufferevent_getfd(bev); if (fd < 0) { if (!sa) goto done; fd = socket(sa->sa_family, SOCK_STREAM, 0); if (fd < 0) goto done; if (evutil_make_socket_nonblocking(fd)<0) goto done; 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, 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; event_active(&bev->ev_write, EV_WRITE, 1); } else { /* The connect failed already. How very BSD of it. */ bufev_p->connection_refused = 1; bufev_p->connecting = 1; result = 0; event_active(&bev->ev_write, EV_WRITE, 1); } goto done; freesock: _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); if (ownfd) evutil_closesocket(fd); /* do something about the error? */ 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 = EVUTIL_UPCAST(bev, struct bufferevent_private, bev); int r; BEV_LOCK(bev); bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP); bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP); if (result != 0) { bev_p->dns_error = result; _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR); _bufferevent_decref_and_unlock(bev); if (ai) evutil_freeaddrinfo(ai); return; } /* XXX use the other addrinfos? */ /* XXX use this return value */ r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); (void)r; _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; int err; struct bufferevent_private *bev_p = EVUTIL_UPCAST(bev, struct bufferevent_private, bev); if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) return -1; if (port < 1 || port > 65535) return -1; BEV_LOCK(bev); bev_p->dns_error = 0; BEV_UNLOCK(bev); evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_protocol = IPPROTO_TCP; hint.ai_socktype = SOCK_STREAM; bufferevent_suspend_write(bev, BEV_SUSPEND_LOOKUP); bufferevent_suspend_read(bev, BEV_SUSPEND_LOOKUP); bufferevent_incref(bev); err = evutil_getaddrinfo_async(evdns_base, hostname, portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev); if (err == 0) { return 0; } else { bufferevent_unsuspend_write(bev, BEV_SUSPEND_LOOKUP); bufferevent_unsuspend_read(bev, BEV_SUSPEND_LOOKUP); return -1; } } int bufferevent_socket_get_dns_error(struct bufferevent *bev) { int rv; struct bufferevent_private *bev_p = EVUTIL_UPCAST(bev, struct bufferevent_private, 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) { if (be_socket_add(&bufev->ev_read,&bufev->timeout_read) == -1) return -1; } if (event & EV_WRITE) { if (be_socket_add(&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 = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 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 = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); evutil_socket_t fd; EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); fd = event_get_fd(&bufev->ev_read); event_del(&bufev->ev_read); event_del(&bufev->ev_write); if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0) EVUTIL_CLOSESOCKET(fd); } static int be_socket_adj_timeouts(struct bufferevent *bufev) { int r = 0; if (event_pending(&bufev->ev_read, EV_READ, NULL)) if (be_socket_add(&bufev->ev_read, &bufev->timeout_read) < 0) r = -1; if (event_pending(&bufev->ev_write, EV_WRITE, NULL)) { if (be_socket_add(&bufev->ev_write, &bufev->timeout_write) < 0) r = -1; } return r; } 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) { BEV_LOCK(bufev); EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); event_del(&bufev->ev_read); event_del(&bufev->ev_write); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); if (fd >= 0) bufferevent_enable(bufev, bufev->enabled); BEV_UNLOCK(bufev); } /* XXXX Should non-socket bufferevents support this? */ int bufferevent_priority_set(struct bufferevent *bufev, int priority) { int r = -1; BEV_LOCK(bufev); if (bufev->be_ops != &bufferevent_ops_socket) goto done; if (event_priority_set(&bufev->ev_read, priority) == -1) goto done; if (event_priority_set(&bufev->ev_write, priority) == -1) goto done; 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 (bufev->be_ops != &bufferevent_ops_socket) 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-0.7.7/libevent/evsignal-internal.h0000644000076400001440000000476012074262762015167 00000000000000/* * 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_H_ #define _EVSIGNAL_H_ #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); #endif /* _EVSIGNAL_H_ */ lldpd-0.7.7/libevent/sample/0000755000076400001440000000000012237716102012717 500000000000000lldpd-0.7.7/libevent/sample/Makefile.in0000644000076400001440000004702612237715703014723 00000000000000# Makefile.in generated by automake 1.14 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # sample/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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@ noinst_PROGRAMS = event-test$(EXEEXT) time-test$(EXEEXT) \ signal-test$(EXEEXT) dns-example$(EXEEXT) hello-world$(EXEEXT) \ http-server$(EXEEXT) $(am__EXEEXT_1) @OPENSSL_TRUE@am__append_1 = le-proxy subdir = sample DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am 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/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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @OPENSSL_TRUE@am__EXEEXT_1 = le-proxy$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) am_dns_example_OBJECTS = dns-example.$(OBJEXT) dns_example_OBJECTS = $(am_dns_example_OBJECTS) dns_example_LDADD = $(LDADD) am__DEPENDENCIES_1 = dns_example_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la 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 = am_event_test_OBJECTS = event-test.$(OBJEXT) event_test_OBJECTS = $(am_event_test_OBJECTS) event_test_LDADD = $(LDADD) event_test_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am_hello_world_OBJECTS = hello-world.$(OBJEXT) hello_world_OBJECTS = $(am_hello_world_OBJECTS) hello_world_LDADD = $(LDADD) hello_world_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am_http_server_OBJECTS = http-server.$(OBJEXT) http_server_OBJECTS = $(am_http_server_OBJECTS) http_server_LDADD = $(LDADD) http_server_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am__le_proxy_SOURCES_DIST = le-proxy.c @OPENSSL_TRUE@am_le_proxy_OBJECTS = le-proxy.$(OBJEXT) le_proxy_OBJECTS = $(am_le_proxy_OBJECTS) am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) ../libevent.la @OPENSSL_TRUE@le_proxy_DEPENDENCIES = $(am__DEPENDENCIES_2) \ @OPENSSL_TRUE@ ../libevent_openssl.la $(am__DEPENDENCIES_1) am_signal_test_OBJECTS = signal-test.$(OBJEXT) signal_test_OBJECTS = $(am_signal_test_OBJECTS) signal_test_LDADD = $(LDADD) signal_test_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am_time_test_OBJECTS = time-test.$(OBJEXT) time_test_OBJECTS = $(am_time_test_OBJECTS) time_test_LDADD = $(LDADD) time_test_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la 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@ -I$(top_builddir) depcomp = am__depfiles_maybe = 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 = $(dns_example_SOURCES) $(event_test_SOURCES) \ $(hello_world_SOURCES) $(http_server_SOURCES) \ $(le_proxy_SOURCES) $(signal_test_SOURCES) \ $(time_test_SOURCES) DIST_SOURCES = $(dns_example_SOURCES) $(event_test_SOURCES) \ $(hello_world_SOURCES) $(http_server_SOURCES) \ $(am__le_proxy_SOURCES_DIST) $(signal_test_SOURCES) \ $(time_test_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # 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)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 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@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ 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@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ 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@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ 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@ 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@ AUTOMAKE_OPTIONS = foreign no-dependencies LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include event_test_SOURCES = event-test.c time_test_SOURCES = time-test.c signal_test_SOURCES = signal-test.c dns_example_SOURCES = dns-example.c hello_world_SOURCES = hello-world.c http_server_SOURCES = http-server.c @OPENSSL_TRUE@le_proxy_SOURCES = le-proxy.c @OPENSSL_TRUE@le_proxy_LDADD = $(LDADD) ../libevent_openssl.la -lssl -lcrypto ${OPENSSL_LIBADD} DISTCLEANFILES = *~ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sample/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign sample/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): 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 dns-example$(EXEEXT): $(dns_example_OBJECTS) $(dns_example_DEPENDENCIES) $(EXTRA_dns_example_DEPENDENCIES) @rm -f dns-example$(EXEEXT) $(AM_V_CCLD)$(LINK) $(dns_example_OBJECTS) $(dns_example_LDADD) $(LIBS) event-test$(EXEEXT): $(event_test_OBJECTS) $(event_test_DEPENDENCIES) $(EXTRA_event_test_DEPENDENCIES) @rm -f event-test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(event_test_OBJECTS) $(event_test_LDADD) $(LIBS) hello-world$(EXEEXT): $(hello_world_OBJECTS) $(hello_world_DEPENDENCIES) $(EXTRA_hello_world_DEPENDENCIES) @rm -f hello-world$(EXEEXT) $(AM_V_CCLD)$(LINK) $(hello_world_OBJECTS) $(hello_world_LDADD) $(LIBS) http-server$(EXEEXT): $(http_server_OBJECTS) $(http_server_DEPENDENCIES) $(EXTRA_http_server_DEPENDENCIES) @rm -f http-server$(EXEEXT) $(AM_V_CCLD)$(LINK) $(http_server_OBJECTS) $(http_server_LDADD) $(LIBS) le-proxy$(EXEEXT): $(le_proxy_OBJECTS) $(le_proxy_DEPENDENCIES) $(EXTRA_le_proxy_DEPENDENCIES) @rm -f le-proxy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(le_proxy_OBJECTS) $(le_proxy_LDADD) $(LIBS) signal-test$(EXEEXT): $(signal_test_OBJECTS) $(signal_test_DEPENDENCIES) $(EXTRA_signal_test_DEPENDENCIES) @rm -f signal-test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(signal_test_OBJECTS) $(signal_test_LDADD) $(LIBS) time-test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) $(EXTRA_time_test_DEPENDENCIES) @rm -f time-test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c -o $@ $< .c.obj: $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs 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" 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 distdir: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: 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: clean-generic: 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) -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." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 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: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ 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 \ tags tags-am uninstall uninstall-am verify: # 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-0.7.7/libevent/sample/le-proxy.c0000644000076400001440000001533012074262762014573 00000000000000/* 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. */ #include #include #include #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #include #include #include #include #include #include #include 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); } 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; 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; SSL_library_init(); ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); r = RAND_poll(); if (r == 0) { fprintf(stderr, "RAND_poll() failed.\n"); return 1; } ssl_ctx = SSL_CTX_new(SSLv23_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); event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); return 0; } lldpd-0.7.7/libevent/sample/event-test.c0000644000076400001440000000553012074262762015113 00000000000000/* * 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 event-test event-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 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 /* Reschedule this event */ event_add(ev, NULL); 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 == -1) { perror("read"); return; } else if (len == 0) { fprintf(stderr, "Connection closed\n"); return; } buf[len] = '\0'; #endif fprintf(stdout, "Read: %s\n", buf); } int main(int argc, char **argv) { struct event evfifo; #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 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); } /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */ #ifdef __linux socket = open(fifo, O_RDWR | O_NONBLOCK, 0); #else socket = open(fifo, O_RDONLY | O_NONBLOCK, 0); #endif if (socket == -1) { perror("open"); exit(1); } fprintf(stderr, "Write data to %s\n", fifo); #endif /* Initalize the event library */ event_init(); /* Initalize one event */ #ifdef WIN32 event_set(&evfifo, (evutil_socket_t)socket, EV_READ, fifo_read, &evfifo); #else event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo); #endif /* Add it to the active events, without a timeout */ event_add(&evfifo, NULL); event_dispatch(); #ifdef WIN32 CloseHandle(socket); #endif return (0); } lldpd-0.7.7/libevent/sample/time-test.c0000644000076400001440000000416512074262762014733 00000000000000/* * 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; } /* Initalize the event library */ base = event_base_new(); /* Initalize 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); event_base_dispatch(base); return (0); } lldpd-0.7.7/libevent/sample/dns-example.c0000644000076400001440000001443712074262762015240 00000000000000/* 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 WIN32 #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; 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); } } } 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) { int idx; int reverse = 0, servertest = 0, use_getaddrinfo = 0; struct event_base *event_base = NULL; struct evdns_base *evdns_base = NULL; const char *resolv_conf = NULL; if (c<2) { fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] hostname\n", v[0]); fprintf(stderr, "syntax: %s [-servertest]\n", v[0]); return 1; } idx = 1; while (idx < c && v[idx][0] == '-') { if (!strcmp(v[idx], "-x")) reverse = 1; else if (!strcmp(v[idx], "-v")) verbose = 1; else if (!strcmp(v[idx], "-g")) use_getaddrinfo = 1; else if (!strcmp(v[idx], "-servertest")) servertest = 1; else if (!strcmp(v[idx], "-c")) { if (idx + 1 < c) resolv_conf = v[++idx]; else fprintf(stderr, "-c needs an argument\n"); } else fprintf(stderr, "Unknown option %s\n", v[idx]); ++idx; } #ifdef WIN32 { WSADATA WSAData; WSAStartup(0x101, &WSAData); } #endif event_base = event_base_new(); evdns_base = evdns_base_new(event_base, 0); evdns_set_log_fn(logfn); if (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 (idx < c) { int res; #ifdef WIN32 if (resolv_conf == NULL) res = evdns_base_config_windows_nameservers(evdns_base); else #endif res = evdns_base_resolv_conf_parse(evdns_base, DNS_OPTION_NAMESERVERS, resolv_conf ? resolv_conf : "/etc/resolv.conf"); if (res < 0) { fprintf(stderr, "Couldn't configure nameservers"); return 1; } } printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME); for (; idx < c; ++idx) { if (reverse) { struct in_addr addr; if (evutil_inet_pton(AF_INET, v[idx], &addr)!=1) { fprintf(stderr, "Skipping non-IP %s\n", v[idx]); continue; } fprintf(stderr, "resolving %s...\n",v[idx]); evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[idx]); } else if (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[idx]); evdns_getaddrinfo(evdns_base, v[idx], NULL, &hints, gai_callback, v[idx]); } else { fprintf(stderr, "resolving (fwd) %s...\n",v[idx]); evdns_base_resolve_ipv4(evdns_base, v[idx], 0, main_callback, v[idx]); } } fflush(stdout); event_base_dispatch(event_base); return 0; } lldpd-0.7.7/libevent/sample/hello-world.c0000644000076400001440000000664512074262762015255 00000000000000/* This exmple 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; #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; } memset(&sin, 0, sizeof(sin)); 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-0.7.7/libevent/sample/signal-test.c0000644000076400001440000000240612074262762015246 00000000000000/* * 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 #ifdef _EVENT___func__ #define __func__ _EVENT___func__ #endif int called = 0; static void signal_cb(evutil_socket_t fd, short event, void *arg) { struct event *signal = arg; printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal)); if (called >= 2) event_del(signal); called++; } int main(int argc, char **argv) { struct event signal_int; struct event_base* base; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); (void) WSAStartup(wVersionRequested, &wsaData); #endif /* Initalize the event library */ base = event_base_new(); /* Initalize one event */ event_assign(&signal_int, base, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb, &signal_int); event_add(&signal_int, NULL); event_base_dispatch(base); event_base_free(base); return (0); } lldpd-0.7.7/libevent/sample/http-server.c0000644000076400001440000002357212155052147015300 00000000000000/* 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! */ #include #include #include #include #include #ifdef WIN32 #include #include #include #include #include #ifndef S_ISDIR #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) #endif #else #include #include #include #include #include #include #endif #include #include #include #include #include #ifdef _EVENT_HAVE_NETINET_IN_H #include # ifdef _XOPEN_SOURCE_EXTENDED # include # endif #endif /* Compatibility for possible missing IPv6 declarations */ #include "../util-internal.h" #ifdef WIN32 #define stat _stat #define fstat _fstat #define open _open #define close _close #define O_RDONLY _O_RDONLY #endif 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/postsript" }, { NULL, NULL }, }; /* 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; const char *docroot = 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(docroot)+2; if (!(whole_path = malloc(len))) { perror("malloc"); goto err; } evutil_snprintf(whole_path, len, "%s/%s", 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" " %s\n" " \n" " \n" " \n" "

%s

\n" "
    \n", decoded_path, /* XXX html-escape this. */ uri_root, 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 CloseHandle(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 syntax(void) { fprintf(stdout, "Syntax: http-server \n"); } int main(int argc, char **argv) { struct event_base *base; struct evhttp *http; struct evhttp_bound_socket *handle; unsigned short port = 0; #ifdef WIN32 WSADATA WSAData; WSAStartup(0x101, &WSAData); #else if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return (1); #endif if (argc < 2) { syntax(); return 1; } base = event_base_new(); if (!base) { fprintf(stderr, "Couldn't create an event_base: exiting\n"); return 1; } /* Create a new evhttp object to handle requests. */ http = evhttp_new(base); if (!http) { fprintf(stderr, "couldn't create evhttp. Exiting.\n"); return 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, argv[1]); /* Now we tell the evhttp what port to listen on */ handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port); if (!handle) { fprintf(stderr, "couldn't bind to port %d. Exiting.\n", (int)port); return 1; } { /* Extract and display the address we're listening on. */ 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; } 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; } } event_base_dispatch(base); return 0; } lldpd-0.7.7/libevent/sample/Makefile.am0000644000076400001440000000150112074262762014677 00000000000000# sample/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. AUTOMAKE_OPTIONS = foreign no-dependencies LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include noinst_PROGRAMS = event-test time-test signal-test dns-example hello-world http-server event_test_SOURCES = event-test.c time_test_SOURCES = time-test.c signal_test_SOURCES = signal-test.c dns_example_SOURCES = dns-example.c hello_world_SOURCES = hello-world.c http_server_SOURCES = http-server.c if OPENSSL noinst_PROGRAMS += le-proxy le_proxy_SOURCES = le-proxy.c le_proxy_LDADD = $(LDADD) ../libevent_openssl.la -lssl -lcrypto ${OPENSSL_LIBADD} endif verify: DISTCLEANFILES = *~ lldpd-0.7.7/libevent/bufferevent_filter.c0000644000076400001440000003531012074262762015413 00000000000000/* * 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 #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_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_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 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_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->be_ops != &bufferevent_ops_filter) return NULL; bev_f = (void*)( ((char*)bev) - evutil_offsetof(struct bufferevent_filtered, bev.bev)); EVUTIL_ASSERT(bev_f->bev.bev.be_ops == &bufferevent_ops_filter); 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->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_destruct(struct bufferevent *bev) { struct bufferevent_filtered *bevf = upcast(bev); EVUTIL_ASSERT(bevf); if (bevf->free_context) bevf->free_context(bevf->context); 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); } } _bufferevent_del_generic_timeout_cbs(bev); } 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_set_flags(bufev->output, bevf->outbuf_cb, 0); 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 && evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { /* call the write callback.*/ _bufferevent_run_writecb(bufev); 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); } } /* Called when the underlying socket has read. */ static void be_filter_readcb(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); int processed_any = 0; _bufferevent_incref_and_lock(bufev); 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 && evbuffer_get_length(bufev->input) >= bufev->wm_read.low) _bufferevent_run_readcb(bufev); _bufferevent_decref_and_unlock(bufev); } /* 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); int processed_any = 0; _bufferevent_incref_and_lock(bev); be_filter_process_output(bevf, BEV_NORMAL, &processed_any); _bufferevent_decref_and_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); _bufferevent_incref_and_lock(bev); /* All we can really to is tell our own eventcb. */ _bufferevent_run_eventcb(bev, what); _bufferevent_decref_and_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_GET_FD: case BEV_CTRL_SET_FD: case BEV_CTRL_CANCEL_ALL: default: return -1; } } lldpd-0.7.7/libevent/event_tagging.c0000644000076400001440000003375312074262762014365 00000000000000/* * 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" #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 #else #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. */ 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 tag); 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); while (count++ < len) { ev_uint8_t lower = *data++; number |= (lower & 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; \ \ 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; \ \ 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-0.7.7/libevent/event_rpcgen.py0000755000076400001440000015424012074262762014427 00000000000000#!/usr/bin/env python2 # # Copyright (c) 2005-2007 Niels Provos # Copyright (c) 2007-2012 Niels Provos and Nick Mathewson # All rights reserved. # # Generates marshaling code based on libevent. # TODO: # 1) use optparse to allow the strategy shell to parse options, and # to allow the instantiated factory (for the specific output language) # to parse remaining options # 2) move the globals into a class that manages execution (including the # progress outputs that space stderr at the moment) # 3) emit other languages import sys import re _NAME = "event_rpcgen.py" _VERSION = "0.1" # Globals line_count = 0 white = re.compile(r'\s+') cppcomment = re.compile(r'\/\/.*$') nonident = re.compile(r'[^a-zA-Z0-9_]') structref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$') structdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$') headerdirect = [] cppdirect = [] def TranslateList(mylist, mydict): return map(lambda x: x % mydict, mylist) # Exception class for parse errors class RpcGenError(Exception): def __init__(self, why): self.why = why def __str__(self): return str(self.why) # Holds everything that makes a struct class Struct: def __init__(self, name): self._name = name self._entries = [] self._tags = {} print >>sys.stderr, ' Created struct: %s' % name def AddEntry(self, entry): if self._tags.has_key(entry.Tag()): 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() print >>sys.stderr, ' 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() def PrintIndented(self, file, ident, code): """Takes an array, add indentation to each entry and prints it.""" for entry in code: print >>file, '%s%s' % (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, file): """Prints the tag definitions for a structure.""" print >>file, '/* Tag definition for %s */' % self._name print >>file, 'enum %s_ {' % self._name.lower() for entry in self._entries: print >>file, ' %s=%d,' % (self.EntryTagName(entry), entry.Tag()) print >>file, ' %s_MAX_TAGS' % (self._name.upper()) print >>file, '};\n' def PrintForwardDeclaration(self, file): print >>file, 'struct %s;' % self._name def PrintDeclaration(self, file): print >>file, '/* Structure declaration for %s */' % self._name print >>file, 'struct %s_access_ {' % 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(file, ' ', dcl) print >>file, '};\n' print >>file, 'struct %s {' % self._name print >>file, ' struct %s_access_ *base;\n' % self._name for entry in self._entries: dcl = entry.Declaration() self.PrintIndented(file, ' ', dcl) print >>file, '' for entry in self._entries: print >>file, ' ev_uint8_t %s_set;' % entry.Name() print >>file, '};\n' print >>file, \ """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 *);""" % { 'name' : self._name } # Write a setting function of every variable for entry in self._entries: self.PrintIndented(file, '', entry.AssignDeclaration( entry.AssignFuncName())) self.PrintIndented(file, '', entry.GetDeclaration( entry.GetFuncName())) if entry.Array(): self.PrintIndented(file, '', entry.AddDeclaration( entry.AddFuncName())) print >>file, '/* --- %s done --- */\n' % self._name def PrintCode(self, file): print >>file, ('/*\n' ' * Implementation of %s\n' ' */\n') % self._name print >>file, \ 'static struct %(name)s_access_ __%(name)s_base = {' % \ { 'name' : self._name } for entry in self._entries: self.PrintIndented(file, ' ', entry.CodeBase()) print >>file, '};\n' # Creation print >>file, ( 'struct %(name)s *\n' '%(name)s_new(void)\n' '{\n' ' return %(name)s_new_with_arg(NULL);\n' '}\n' '\n' 'struct %(name)s *\n' '%(name)s_new_with_arg(void *unused)\n' '{\n' ' struct %(name)s *tmp;\n' ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n' ' event_warn("%%s: malloc", __func__);\n' ' return (NULL);\n' ' }\n' ' tmp->base = &__%(name)s_base;\n') % { 'name' : self._name } for entry in self._entries: self.PrintIndented(file, ' ', entry.CodeInitialize('tmp')) print >>file, ' tmp->%s_set = 0;\n' % entry.Name() print >>file, ( ' return (tmp);\n' '}\n') # Adding for entry in self._entries: if entry.Array(): self.PrintIndented(file, '', entry.CodeAdd()) print >>file, '' # Assigning for entry in self._entries: self.PrintIndented(file, '', entry.CodeAssign()) print >>file, '' # Getting for entry in self._entries: self.PrintIndented(file, '', entry.CodeGet()) print >>file, '' # Clearing print >>file, ( 'void\n' '%(name)s_clear(struct %(name)s *tmp)\n' '{' ) % { 'name' : self._name } for entry in self._entries: self.PrintIndented(file, ' ', entry.CodeClear('tmp')) print >>file, '}\n' # Freeing print >>file, ( 'void\n' '%(name)s_free(struct %(name)s *tmp)\n' '{' ) % { 'name' : self._name } for entry in self._entries: self.PrintIndented(file, ' ', entry.CodeFree('tmp')) print >>file, (' free(tmp);\n' '}\n') # Marshaling print >>file, ('void\n' '%(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 += ' ' print >>file, ' if (tmp->%s_set) {' % entry.Name() self.PrintIndented( file, indent, entry.CodeMarshal('evbuf', self.EntryTagName(entry), entry.GetVarName('tmp'), entry.GetVarLen('tmp'))) if entry.Optional(): print >>file, ' }' print >>file, '}\n' # Unmarshaling print >>file, ('int\n' '%(name)s_unmarshal(struct %(name)s *tmp, ' ' struct evbuffer *evbuf)\n' '{\n' ' ev_uint32_t tag;\n' ' while (evbuffer_get_length(evbuf) > 0) {\n' ' if (evtag_peek(evbuf, &tag) == -1)\n' ' return (-1);\n' ' switch (tag) {\n' ) % { 'name' : self._name } for entry in self._entries: print >>file, ' case %s:\n' % self.EntryTagName(entry) if not entry.Array(): print >>file, ( ' if (tmp->%s_set)\n' ' return (-1);' ) % (entry.Name()) self.PrintIndented( file, ' ', entry.CodeUnmarshal('evbuf', self.EntryTagName(entry), entry.GetVarName('tmp'), entry.GetVarLen('tmp'))) print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() + ' break;\n' ) print >>file, ( ' default:\n' ' return -1;\n' ' }\n' ' }\n' ) # Check if it was decoded completely print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n' ' return (-1);' ) % { 'name' : self._name } # Successfully decoded print >>file, ( ' return (0);\n' '}\n') # Checking if a structure has all the required data print >>file, ( 'int\n' '%(name)s_complete(struct %(name)s *msg)\n' '{' ) % { '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( file, ' ', code) self.PrintIndented( file, ' ', entry.CodeComplete('msg', entry.GetVarName('msg'))) print >>file, ( ' return (0);\n' '}\n' ) # Complete message unmarshaling print >>file, ( 'int\n' 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' 'ev_uint32_t need_tag, struct %(name)s *msg)\n' '{\n' ' ev_uint32_t tag;\n' ' int res = -1;\n' '\n' ' struct evbuffer *tmp = evbuffer_new();\n' '\n' ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1' ' || tag != need_tag)\n' ' goto error;\n' '\n' ' if (%(name)s_unmarshal(msg, tmp) == -1)\n' ' goto error;\n' '\n' ' res = 0;\n' '\n' ' error:\n' ' evbuffer_free(tmp);\n' ' return (res);\n' '}\n' ) % { 'name' : self._name } # Complete message marshaling print >>file, ( 'void\n' 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' 'const struct %(name)s *msg)\n' '{\n' ' struct evbuffer *_buf = evbuffer_new();\n' ' assert(_buf != NULL);\n' ' %(name)s_marshal(_buf, msg);\n' ' evtag_marshal_buffer(evbuf, tag, _buf);\n ' ' evbuffer_free(_buf);\n' '}\n' ) % { 'name' : self._name } class Entry: def __init__(self, type, name, tag): self._type = type self._name = name self._tag = int(tag) self._ctype = type self._optional = 0 self._can_be_array = 0 self._array = 0 self._line_count = -1 self._struct = None self._refname = None self._optpointer = True self._optaddarg = True def GetInitializer(self): assert 0, "Entry does not provide 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, yes=1): self._array = yes def MakeOptional(self): self._optional = 1 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 = {}): 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 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 = '\n'.join(code) 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 def CodeComplete(self, structname, var_name): return [] def CodeFree(self, 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, type, name, tag, length): # Init base class Entry.__init__(self, type, name, tag) self._length = length self._ctype = 'ev_uint8_t' def GetInitializer(self): return "NULL" def GetVarLen(self, var): return '(%s)' % self._length def CodeArrayAdd(self, 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 })) def CodeMarshal(self, 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())) Entry.Verify(self) class EntryInt(Entry): def __init__(self, type, name, tag, bits=32): # Init base class Entry.__init__(self, type, name, tag) self._can_be_array = 1 if bits == 32: self._ctype = 'ev_uint32_t' self._marshal_type = 'int' if bits == 64: self._ctype = 'ev_uint64_t' self._marshal_type = 'int64' def GetInitializer(self): return "0" def CodeArrayFree(self, var): return [] def CodeArrayAssign(self, varname, srcvar): return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname, 'srcvar' : srcvar } ] def CodeArrayAdd(self, 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, type, name, tag): # Init base class Entry.__init__(self, type, name, tag) self._can_be_array = 1 self._ctype = 'char *' def GetInitializer(self): return "NULL" def CodeArrayFree(self, varname): code = [ 'if (%(var)s != NULL) free(%(var)s);' ] return TranslateList(code, { 'var' : varname }) def CodeArrayAssign(self, 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 }) def CodeArrayAdd(self, 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) def CodeMakeInitalize(self, varname): return '%(varname)s = NULL;' % { 'varname' : varname } def CodeAssign(self): name = self._name 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') def CodeMarshal(self, 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, type, name, tag, refname): # Init base class Entry.__init__(self, type, name, tag) self._optpointer = False self._can_be_array = 1 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): name = self._name 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, type, name, tag): # Init base class Entry.__init__(self, type, name, tag) self._ctype = 'ev_uint8_t *' def GetInitializer(self): return "NULL" def GetVarLen(self, var): return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var }) def CodeArrayAdd(self, 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') def CodeMarshal(self, 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): def __init__(self, entry): # Init base class Entry.__init__(self, 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_name): return var_name 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.split('\n') 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);\n', ' {' ] code = TranslateList(code, self.GetTranslation()) codearrayassign = self._entry.CodeArrayAssign( 'msg->%(name)s_data[off]' % self.GetTranslation(), 'value') code += map(lambda x: ' ' + x, 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 += map(lambda x: ' ' + x, 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 += map(lambda x: ' ' + x, 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 += map(lambda x: ' ' + x, 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): global white global cppcomment line = cppcomment.sub('', line) line = line.strip() line = white.sub(' ', line) return line def ProcessOneEntry(factory, newstruct, entry): optional = 0 array = 0 entry_type = '' name = '' tag = '' tag_set = None separator = '' fixed_length = '' tokens = entry.split(' ') while tokens: token = tokens[0] tokens = tokens[1:] if not entry_type: if not optional and token == 'optional': optional = 1 continue if not array and token == 'array': array = 1 continue if not entry_type: entry_type = token continue if not name: res = re.match(r'^([^\[\]]+)(\[.*\])?$', token) if not res: raise RpcGenError( 'Cannot parse name: \"%s\" ' 'around line %d' % (entry, line_count)) name = res.group(1) fixed_length = res.group(2) if fixed_length: fixed_length = fixed_length[1:-1] continue if not separator: separator = token if separator != '=': raise RpcGenError('Expected "=" after name \"%s\" got %s' % (name, token)) continue if not tag_set: tag_set = 1 if not re.match(r'^(0x)?[0-9]+$', token): raise RpcGenError('Expected tag number: \"%s\"' % entry) tag = int(token, 0) continue raise RpcGenError('Cannot parse \"%s\"' % entry) if not tag_set: raise RpcGenError('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 = structref.match(entry_type) if res: # References another struct defined in our file newentry = factory.EntryStruct(entry_type, name, tag, res.group(1)) 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 newname = newentry.Name()+ '_array' # Now borgify the new entry. 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 def GetNextStruct(file): global line_count global cppdirect got_struct = 0 processed_lines = [] have_c_comment = 0 data = '' while 1: line = file.readline() if not line: break line_count += 1 line = line[:-1] if not have_c_comment and re.search(r'/\*', line): if re.search(r'/\*.*?\*/', line): line = re.sub(r'/\*.*?\*/', '', line) else: line = re.sub(r'/\*.*$', '', line) have_c_comment = 1 if have_c_comment: if not re.search(r'\*/', line): continue have_c_comment = 0 line = re.sub(r'^.*\*/', '', line) line = NormalizeLine(line) if not line: continue if not got_struct: if re.match(r'#include ["<].*[>"]', line): cppdirect.append(line) continue if re.match(r'^#(if( |def)|endif)', line): cppdirect.append(line) continue if re.match(r'^#define', line): headerdirect.append(line) continue if not structdef.match(line): raise RpcGenError('Missing struct on line %d: %s' % (line_count, line)) else: got_struct = 1 data += line continue # We are inside the struct tokens = line.split('}') if len(tokens) == 1: data += ' ' + line continue if len(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, file): """ Parses the input file and returns C code and corresponding header file. """ entities = [] while 1: # Just gets the whole struct nicely formatted data = GetNextStruct(file) if not data: break entities.extend(ProcessStruct(factory, data)) return entities class CCodeGenerator: def __init__(self): pass def GuardName(self, 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 '_' + nonident.sub('_', name).upper() + '_' def HeaderPreamble(self, name): guard = self.GuardName(name) pre = ( '/*\n' ' * Automatically generated from %s\n' ' */\n\n' '#ifndef %s\n' '#define %s\n\n' ) % ( name, guard, guard) for statement in headerdirect: pre += '%s\n' % statement if headerdirect: pre += '\n' pre += ( '#include /* for ev_uint*_t */\n' '#include \n' ) return pre def HeaderPostamble(self, name): guard = self.GuardName(name) return '#endif /* %s */' % guard def BodyPreamble(self, name, header_file): global _NAME global _VERSION slash = header_file.rfind('/') if slash != -1: header_file = header_file[slash+1:] pre = ( '/*\n' ' * Automatically generated from %s\n' ' * by %s/%s. DO NOT EDIT THIS FILE.\n' ' */\n\n' ) % (name, _NAME, _VERSION) pre += ( '#include \n' '#include \n' '#include \n' '#include \n' '#include \n' '#include \n' '#include \n\n' '#ifdef _EVENT___func__\n' '#define __func__ _EVENT___func__\n' '#endif\n\n' ) for statement in cppdirect: 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 def HeaderFilename(self, filename): return '.'.join(filename.split('.')[:-1]) + '.h' def CodeFilename(self, filename): return '.'.join(filename.split('.')[:-1]) + '.gen.c' def Struct(self, name): return StructCCode(name) def EntryBytes(self, entry_type, name, tag, fixed_length): return EntryBytes(entry_type, name, tag, fixed_length) def EntryVarBytes(self, entry_type, name, tag): return EntryVarBytes(entry_type, name, tag) def EntryInt(self, entry_type, name, tag, bits=32): return EntryInt(entry_type, name, tag, bits) def EntryString(self, entry_type, name, tag): return EntryString(entry_type, name, tag) def EntryStruct(self, entry_type, name, tag, struct_name): return EntryStruct(entry_type, name, tag, struct_name) def EntryArray(self, entry): return EntryArray(entry) class Usage(RpcGenError): def __init__(self, argv0): RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]" % argv0) class CommandLine: def __init__(self, argv): """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] """ self.filename = None self.header_file = None self.impl_file = None self.factory = CCodeGenerator() if len(argv) < 2 or len(argv) > 4: raise Usage(argv[0]) self.filename = argv[1].replace('\\', '/') if len(argv) == 3: self.impl_file = argv[2].replace('\\', '/') if len(argv) == 4: self.header_file = argv[2].replace('\\', '/') self.impl_file = argv[3].replace('\\', '/') if not self.filename: raise Usage(argv[0]) if not self.impl_file: self.impl_file = self.factory.CodeFilename(self.filename) if not self.header_file: self.header_file = self.factory.HeaderFilename(self.impl_file) if not self.impl_file.endswith('.c'): raise RpcGenError("can only generate C implementation files") if not self.header_file.endswith('.h'): raise RpcGenError("can only generate C header files") def run(self): filename = self.filename header_file = self.header_file impl_file = self.impl_file factory = self.factory print >>sys.stderr, 'Reading \"%s\"' % filename fp = open(filename, 'r') entities = Parse(factory, fp) fp.close() print >>sys.stderr, '... creating "%s"' % header_file header_fp = open(header_file, 'w') print >>header_fp, factory.HeaderPreamble(filename) # Create forward declarations: allows other structs to reference # each other for entry in entities: entry.PrintForwardDeclaration(header_fp) print >>header_fp, '' for entry in entities: entry.PrintTags(header_fp) entry.PrintDeclaration(header_fp) print >>header_fp, factory.HeaderPostamble(filename) header_fp.close() print >>sys.stderr, '... creating "%s"' % impl_file impl_fp = open(impl_file, 'w') print >>impl_fp, factory.BodyPreamble(filename, header_file) for entry in entities: entry.PrintCode(impl_fp) impl_fp.close() if __name__ == '__main__': try: CommandLine(sys.argv).run() sys.exit(0) except RpcGenError, e: print >>sys.stderr, e sys.exit(1) except EnvironmentError, e: if e.filename and e.strerror: print >>sys.stderr, "%s: %s" % (e.filename, e.strerror) sys.exit(1) elif e.strerror: print >> sys.stderr, e.strerror sys.exit(1) else: raise lldpd-0.7.7/libevent/evdns.c0000644000076400001440000037145412155052147012660 00000000000000/* 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 #include "event2/event-config.h" #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 #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 "event2/bufferevent.h" #include "event2/bufferevent_struct.h" #include "bufferevent-internal.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 0 #define EVDNS_LOG_WARN 1 #define EVDNS_LOG_MSG 2 #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; }; /* 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 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 }; 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 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 void default_evdns_log_fn(int warning, const char *buf) { if (warning == EVDNS_LOG_WARN) event_warnx("[evdns] %s", buf); else if (warning == EVDNS_LOG_MSG) event_msgx("[evdns] %s", buf); else event_debug(("[evdns] %s", buf)); } 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 warn, const char *fmt, ...) EVDNS_LOG_CHECK; static void _evdns_log(int warn, const char *fmt, ...) { va_list args; char buf[512]; if (!evdns_log_fn) return; va_start(args,fmt); evutil_vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (evdns_log_fn) { if (warn == EVDNS_LOG_MSG) warn = EVDNS_LOG_WARN; evdns_log_fn(warn, buf); } else { default_evdns_log_fn(warn, buf); } } #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))); } } /* 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 */ req->ns = 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--; } else { base->global_requests_waiting--; } /* it was initialized during request_new / evtimer_assign */ event_debug_unassign(&req->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 */ req->ns = 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. */ 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; /* move a request from the waiting queue to the inflight queue */ EVUTIL_ASSERT(base->req_waiting_head); req = base->req_waiting_head; evdns_request_remove(req, &base->req_waiting_head); base->global_requests_waiting--; base->global_requests_inflight++; req->ns = nameserver_pick(base); 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 deferred_cb 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 deferred_cb *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, reply_run_callback, req->user_pointer); event_deferred_cb_schedule( event_base_get_deferred_cb_queue(req->base->event_base), &d->deferred); } /* 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 & 0x020f || !reply || !reply->have_answer) { /* there was an error */ if (flags & 0x0200) { error = DNS_ERR_TRUNCATED; } else if (flags & 0x000f) { u16 error_code = (flags & 0x000f) - 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))); break; 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; if (j >= length) return -1; 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; 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 & 0x8000)) return -1; /* must be an answer */ if ((flags & 0x020f) && (flags & 0x020f) != 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) #define TEST_NAME \ do { 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; \ } \ } while (0) reply.type = req->request_type; /* skip over each question in the reply */ for (i = 0; i < questions; ++i) { /* the question looks like * */ TEST_NAME; 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 & 0x8000) return -1; /* Must not be an answer. */ flags &= 0x0110; /* 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 & 0x7800) { 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) { 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; } } /* 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 |= (0x8000 | 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); req->ns->timedout++; if (req->ns->timedout > req->base->global_max_nameserver_timeout) { req->ns->timedout = 0; nameserver_failed(req->ns, "request timed out."); } if (req->tx_count >= req->base->global_max_retransmits) { /* 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); } else { /* retransmit it */ struct nameserver *new_ns; log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d", arg, req->tx_count); (void) evtimer_del(&req->timeout_event); new_ns = nameserver_pick(base); if (new_ns) req->ns = new_ns; evdns_request_transmit(req); } 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); 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. */ retcode = 1; /* fall through: we'll set a timeout, which will time out, * and make us retransmit the request anyway. */ 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 = socket(address->sa_family, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } evutil_make_socket_closeonexec(ns->socket); evutil_make_socket_nonblocking(ns->socket); 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; } } 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 (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; } /* 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++; 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); const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1; struct search_domain *dom; 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) { /* 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 (flags & DNS_OPTION_NAMESERVERS) 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 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 (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 (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 (!(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 (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)); } 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); path_out = mm_malloc(len_out+1); 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; log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); if (flags & DNS_OPTION_HOSTSFILE) { char *fname = evdns_get_default_hosts_filename(); evdns_base_load_hosts(base, fname); if (fname) mm_free(fname); } 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 && (flags & DNS_OPTION_NAMESERVERS)) { /* 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); if (load_nameservers_with_getnetworkparams(base) == 0) { EVDNS_UNLOCK(base); return 0; } r = load_nameservers_from_registry(base); fname = evdns_get_default_hosts_filename(); evdns_base_load_hosts(base, fname); if (fname) mm_free(fname); 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 initialize_nameservers) { 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); 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); if (initialize_nameservers) { int r; #ifdef WIN32 r = evdns_base_config_windows_nameservers(base); #else r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf"); #endif if (r == -1) { evdns_base_free_and_unlock(base, 0); return NULL; } } 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); 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. */ 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); } } 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); } base->global_requests_inflight = base->global_requests_waiting = 0; for (server = base->server_head; server; server = server_next) { server_next = server->next; 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_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; } 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); 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 */ 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; 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.) */ 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->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->current_req->put_cname_in_ptr = &data->cname_result; } evtimer_assign(&data->timeout, dns_base->event_base, evdns_getaddrinfo_timeout_cb, data); if (data->ipv4_request.r || data->ipv6_request.r) { 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-0.7.7/libevent/test/0000755000076400001440000000000012237716103012416 500000000000000lldpd-0.7.7/libevent/test/regress_dns.c0000644000076400001440000014765112074262762015044 00000000000000/* * 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. */ #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_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 "log-internal.h" #include "regress.h" #include "regress_testutils.h" #include "../util-internal.h" 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, 1/* init name servers */); 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); /* 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; 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; } if (--n_replies_left == 0) event_base_loopexit(exit_base, NULL); } static struct regress_dns_server_table search_table[] = { { "host.a.example.com", "err", "3", 0 }, { "host.b.example.com", "err", "3", 0 }, { "host.c.example.com", "A", "11.22.33.44", 0 }, { "host2.a.example.com", "err", "3", 0 }, { "host2.b.example.com", "A", "200.100.0.100", 0 }, { "host2.c.example.com", "err", "3", 0 }, { "hostn.a.example.com", "errsoa", "0", 0 }, { "hostn.b.example.com", "errsoa", "3", 0 }, { "hostn.c.example.com", "err", "0", 0 }, { "host", "err", "3", 0 }, { "host2", "err", "3", 0 }, { "*", "err", "3", 0 }, { NULL, NULL, NULL, 0 } }; static void dns_search_test(void *arg) { 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]; tt_assert(regress_dnsserver(base, &portnum, search_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 = sizeof(r)/sizeof(r[0]); 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 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); } 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(void *arg) { 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, 0); tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); tt_assert(! evdns_base_set_option(dns, "timeout", "0.3")); tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10")); tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.5")); 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:", "3")); tt_assert(! evdns_base_set_option(dns, "attempts:", "4")); 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 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 }, { NULL, NULL, NULL, 0 } }; static struct regress_dns_server_table reissue_table[] = { { "foof.example.com", "A", "240.15.240.15", 0 }, { NULL, NULL, NULL, 0 } }; static void dns_reissue_test(void *arg) { 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, 0); 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); } #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; ev_uint16_t portnum = 0; char buf[64]; struct generic_dns_callback_result r[20]; int i; tt_assert(regress_dnsserver(base, &portnum, reissue_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)); 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); regress_clean_dnsserver(); } /* === 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;inquestions;++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)); 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) evdns_server_request_respond(req, 0); else 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_BLATHER(("Got a bufferevent event %d", what)); got->what = what; if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) { int r; if ((r = bufferevent_socket_get_dns_error(bev))) { 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)); if (total_n_accepted >= 3 && total_connected_or_failed >= 5) event_base_loopexit(be_connect_hostname_base, NULL); } } else { TT_FAIL(("Two events on one bufferevent. %d,%d", got->what, (int)what)); } } static void test_bufferevent_connect_hostname(void *arg) { struct basic_test_data *data = arg; struct evconnlistener *listener = NULL; struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL; struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0}, be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0}; int expect_err5; 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]; 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); /* 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. */ be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb, &be1_outcome); bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb, &be2_outcome); bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb, &be3_outcome); bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb, &be4_outcome); bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb, &be5_outcome); /* Launch an async resolve that will fail. */ tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET, "nosuchplace.example.com", listener_port)); /* Connect to the IP without resolving. */ tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET, "127.0.0.1", listener_port)); /* Launch an async resolve that will succeed. */ tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET, "nobodaddy.example.com", listener_port)); /* 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(be4, NULL, AF_INET, "localhost", listener_port)); /* Use the blocking resolver with a nonexistent hostname. */ tt_assert(!bufferevent_socket_connect_hostname(be5, 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_err5 = evutil_getaddrinfo( "nonesuch.nowhere.example.com", "80", &hints, &ai); } event_base_dispatch(data->base); tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR); tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME); tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED); tt_int_op(be2_outcome.dnserr, ==, 0); tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED); tt_int_op(be3_outcome.dnserr, ==, 0); tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED); tt_int_op(be4_outcome.dnserr, ==, 0); if (expect_err5) { tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR); tt_int_op(be5_outcome.dnserr, ==, expect_err5); } 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); if (be1) bufferevent_free(be1); if (be2) bufferevent_free(be2); if (be3) bufferevent_free(be3); if (be4) bufferevent_free(be4); if (be5) bufferevent_free(be5); } 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]; int 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 = evdns_base_new(data->base, 0); tt_assert(dns_base); /* for localhost */ evdns_base_load_hosts(dns_base, NULL); memset(a_out, 0, sizeof(a_out)); memset(&local_outcome, 0, sizeof(local_outcome)); 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<10;++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 pending = 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 (--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); ++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; 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 /* FIXME: that's `1' because of event_debug_map_HT_GROW */ tt_int_op(allocated_chunks, ==, 1); #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 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; int 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); end: if (dns_base) evdns_base_free(dns_base, 1); if (server) evdns_close_server_port(server); if (fd >= 0) evutil_closesocket(fd); } #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), DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS), DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS), { "resolve_reverse", dns_resolve_reverse, TT_FORK, NULL, NULL }, { "search", dns_search_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, &basic_setup, NULL }, { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE, &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 }, { "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 }, #endif END_OF_TESTCASES }; lldpd-0.7.7/libevent/test/regress_util.c0000644000076400001440000006767712074262762015246 00000000000000/* * 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. */ #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 "../util-internal.h" #include "../log-internal.h" #include "../strlcpy-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 = (in6.s6_addr[j*4 ] << 24) | (in6.s6_addr[j*4+1] << 16) | (in6.s6_addr[j*4+2] << 8) | (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 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 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; 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() % 4; int endpoint = 32 - (_evutil_weakrand() % 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; } /* 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); } #ifdef WIN32 static void test_evutil_loadsyslib(void *arg) { HANDLE h=NULL; h = evutil_load_windows_system_library(TEXT("kernel32.dll")); tt_assert(h); end: if (h) CloseHandle(h); } #endif struct testcase_t util_testcases[] = { { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL }, { "ipv6_parse", regress_ipv6_parse, 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 }, { "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 }, { "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL }, #ifdef WIN32 { "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL }, #endif END_OF_TESTCASES, }; lldpd-0.7.7/libevent/test/regress.gen.c0000644000076400001440000006604412074263235014740 00000000000000/* * Automatically generated from ../../../libevent/test/regress.rpc * by event_rpcgen.py/0.1. DO NOT EDIT THIS FILE. */ #include #include #include #include #include #include #include #ifdef _EVENT___func__ #define __func__ _EVENT___func__ #endif #include "regress.gen.h" void event_warn(const char *fmt, ...); void event_warnx(const char *fmt, ...); /* * Implementation of msg */ static struct msg_access_ __msg_base = { msg_from_name_assign, msg_from_name_get, msg_to_name_assign, msg_to_name_get, msg_attack_assign, msg_attack_get, msg_run_assign, msg_run_get, msg_run_add, }; struct msg * msg_new(void) { return msg_new_with_arg(NULL); } struct msg * msg_new_with_arg(void *unused) { struct msg *tmp; if ((tmp = malloc(sizeof(struct msg))) == NULL) { event_warn("%s: malloc", __func__); return (NULL); } tmp->base = &__msg_base; tmp->from_name_data = NULL; tmp->from_name_set = 0; tmp->to_name_data = NULL; tmp->to_name_set = 0; tmp->attack_data = NULL; tmp->attack_set = 0; tmp->run_data = NULL; tmp->run_length = 0; tmp->run_num_allocated = 0; tmp->run_set = 0; return (tmp); } static int msg_run_expand_to_hold_more(struct msg *msg) { int tobe_allocated = msg->run_num_allocated; struct run** new_data = NULL; tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; new_data = (struct run**) realloc(msg->run_data, tobe_allocated * sizeof(struct run*)); if (new_data == NULL) return -1; msg->run_data = new_data; msg->run_num_allocated = tobe_allocated; return 0;} struct run* msg_run_add(struct msg *msg) { if (++msg->run_length >= msg->run_num_allocated) { if (msg_run_expand_to_hold_more(msg)<0) goto error; } msg->run_data[msg->run_length - 1] = run_new(); if (msg->run_data[msg->run_length - 1] == NULL) goto error; msg->run_set = 1; return (msg->run_data[msg->run_length - 1]); error: --msg->run_length; return (NULL); } int msg_from_name_assign(struct msg *msg, const char * value) { if (msg->from_name_data != NULL) free(msg->from_name_data); if ((msg->from_name_data = strdup(value)) == NULL) return (-1); msg->from_name_set = 1; return (0); } int msg_to_name_assign(struct msg *msg, const char * value) { if (msg->to_name_data != NULL) free(msg->to_name_data); if ((msg->to_name_data = strdup(value)) == NULL) return (-1); msg->to_name_set = 1; return (0); } int msg_attack_assign(struct msg *msg, const struct kill* value) { struct evbuffer *tmp = NULL; if (msg->attack_set) { kill_clear(msg->attack_data); msg->attack_set = 0; } else { msg->attack_data = kill_new(); if (msg->attack_data == NULL) { event_warn("%s: kill_new()", __func__); goto error; } } if ((tmp = evbuffer_new()) == NULL) { event_warn("%s: evbuffer_new()", __func__); goto error; } kill_marshal(tmp, value); if (kill_unmarshal(msg->attack_data, tmp) == -1) { event_warnx("%s: kill_unmarshal", __func__); goto error; } msg->attack_set = 1; evbuffer_free(tmp); return (0); error: if (tmp != NULL) evbuffer_free(tmp); if (msg->attack_data != NULL) { kill_free(msg->attack_data); msg->attack_data = NULL; } return (-1); } int msg_run_assign(struct msg *msg, int off, const struct run* value) { if (!msg->run_set || off < 0 || off >= msg->run_length) return (-1); { int had_error = 0; struct evbuffer *tmp = NULL; run_clear(msg->run_data[off]); if ((tmp = evbuffer_new()) == NULL) { event_warn("%s: evbuffer_new()", __func__); had_error = 1; goto done; } run_marshal(tmp, value); if (run_unmarshal(msg->run_data[off], tmp) == -1) { event_warnx("%s: run_unmarshal", __func__); had_error = 1; goto done; } done:if (tmp != NULL) evbuffer_free(tmp); if (had_error) { run_clear(msg->run_data[off]); return (-1); } } return (0); } int msg_from_name_get(struct msg *msg, char * *value) { if (msg->from_name_set != 1) return (-1); *value = msg->from_name_data; return (0); } int msg_to_name_get(struct msg *msg, char * *value) { if (msg->to_name_set != 1) return (-1); *value = msg->to_name_data; return (0); } int msg_attack_get(struct msg *msg, struct kill* *value) { if (msg->attack_set != 1) { msg->attack_data = kill_new(); if (msg->attack_data == NULL) return (-1); msg->attack_set = 1; } *value = msg->attack_data; return (0); } int msg_run_get(struct msg *msg, int offset, struct run* *value) { if (!msg->run_set || offset < 0 || offset >= msg->run_length) return (-1); *value = msg->run_data[offset]; return (0); } void msg_clear(struct msg *tmp) { if (tmp->from_name_set == 1) { free(tmp->from_name_data); tmp->from_name_data = NULL; tmp->from_name_set = 0; } if (tmp->to_name_set == 1) { free(tmp->to_name_data); tmp->to_name_data = NULL; tmp->to_name_set = 0; } if (tmp->attack_set == 1) { kill_free(tmp->attack_data); tmp->attack_data = NULL; tmp->attack_set = 0; } if (tmp->run_set == 1) { int i; for (i = 0; i < tmp->run_length; ++i) { run_free(tmp->run_data[i]); } free(tmp->run_data); tmp->run_data = NULL; tmp->run_set = 0; tmp->run_length = 0; tmp->run_num_allocated = 0; } } void msg_free(struct msg *tmp) { if (tmp->from_name_data != NULL) free (tmp->from_name_data); if (tmp->to_name_data != NULL) free (tmp->to_name_data); if (tmp->attack_data != NULL) kill_free(tmp->attack_data); if (tmp->run_set == 1) { int i; for (i = 0; i < tmp->run_length; ++i) { run_free(tmp->run_data[i]); } free(tmp->run_data); tmp->run_data = NULL; tmp->run_set = 0; tmp->run_length = 0; tmp->run_num_allocated = 0; } free(tmp->run_data); free(tmp); } void msg_marshal(struct evbuffer *evbuf, const struct msg *tmp){ evtag_marshal_string(evbuf, MSG_FROM_NAME, tmp->from_name_data); evtag_marshal_string(evbuf, MSG_TO_NAME, tmp->to_name_data); if (tmp->attack_set) { evtag_marshal_kill(evbuf, MSG_ATTACK, tmp->attack_data); } if (tmp->run_set) { { int i; for (i = 0; i < tmp->run_length; ++i) { evtag_marshal_run(evbuf, MSG_RUN, tmp->run_data[i]); } } } } int msg_unmarshal(struct msg *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { case MSG_FROM_NAME: if (tmp->from_name_set) return (-1); if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) { event_warnx("%s: failed to unmarshal from_name", __func__); return (-1); } tmp->from_name_set = 1; break; case MSG_TO_NAME: if (tmp->to_name_set) return (-1); if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) { event_warnx("%s: failed to unmarshal to_name", __func__); return (-1); } tmp->to_name_set = 1; break; case MSG_ATTACK: if (tmp->attack_set) return (-1); tmp->attack_data = kill_new(); if (tmp->attack_data == NULL) return (-1); if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) { event_warnx("%s: failed to unmarshal attack", __func__); return (-1); } tmp->attack_set = 1; break; case MSG_RUN: if (tmp->run_length >= tmp->run_num_allocated && msg_run_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } tmp->run_data[tmp->run_length] = run_new(); if (tmp->run_data[tmp->run_length] == NULL) return (-1); if (evtag_unmarshal_run(evbuf, MSG_RUN, tmp->run_data[tmp->run_length]) == -1) { event_warnx("%s: failed to unmarshal run", __func__); return (-1); } ++tmp->run_length; tmp->run_set = 1; break; default: return -1; } } if (msg_complete(tmp) == -1) return (-1); return (0); } int msg_complete(struct msg *msg) { if (!msg->from_name_set) return (-1); if (!msg->to_name_set) return (-1); if (msg->attack_set && kill_complete(msg->attack_data) == -1) return (-1); { int i; for (i = 0; i < msg->run_length; ++i) { if (msg->run_set && run_complete(msg->run_data[i]) == -1) return (-1); } } return (0); } int evtag_unmarshal_msg(struct evbuffer *evbuf, ev_uint32_t need_tag, struct msg *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 (msg_unmarshal(msg, tmp) == -1) goto error; res = 0; error: evbuffer_free(tmp); return (res); } void evtag_marshal_msg(struct evbuffer *evbuf, ev_uint32_t tag, const struct msg *msg) { struct evbuffer *_buf = evbuffer_new(); assert(_buf != NULL); msg_marshal(_buf, msg); evtag_marshal_buffer(evbuf, tag, _buf); evbuffer_free(_buf); } /* * Implementation of kill */ static struct kill_access_ __kill_base = { kill_weapon_assign, kill_weapon_get, kill_action_assign, kill_action_get, kill_how_often_assign, kill_how_often_get, kill_how_often_add, }; struct kill * kill_new(void) { return kill_new_with_arg(NULL); } struct kill * kill_new_with_arg(void *unused) { struct kill *tmp; if ((tmp = malloc(sizeof(struct kill))) == NULL) { event_warn("%s: malloc", __func__); return (NULL); } tmp->base = &__kill_base; tmp->weapon_data = NULL; tmp->weapon_set = 0; tmp->action_data = NULL; tmp->action_set = 0; tmp->how_often_data = NULL; tmp->how_often_length = 0; tmp->how_often_num_allocated = 0; tmp->how_often_set = 0; return (tmp); } static int kill_how_often_expand_to_hold_more(struct kill *msg) { int tobe_allocated = msg->how_often_num_allocated; ev_uint32_t* new_data = NULL; tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; new_data = (ev_uint32_t*) realloc(msg->how_often_data, tobe_allocated * sizeof(ev_uint32_t)); if (new_data == NULL) return -1; msg->how_often_data = new_data; msg->how_often_num_allocated = tobe_allocated; return 0;} ev_uint32_t * kill_how_often_add(struct kill *msg, const ev_uint32_t value) { if (++msg->how_often_length >= msg->how_often_num_allocated) { if (kill_how_often_expand_to_hold_more(msg)<0) goto error; } msg->how_often_data[msg->how_often_length - 1] = value; msg->how_often_set = 1; return &(msg->how_often_data[msg->how_often_length - 1]); error: --msg->how_often_length; return (NULL); } int kill_weapon_assign(struct kill *msg, const char * value) { if (msg->weapon_data != NULL) free(msg->weapon_data); if ((msg->weapon_data = strdup(value)) == NULL) return (-1); msg->weapon_set = 1; return (0); } int kill_action_assign(struct kill *msg, const char * value) { if (msg->action_data != NULL) free(msg->action_data); if ((msg->action_data = strdup(value)) == NULL) return (-1); msg->action_set = 1; return (0); } int kill_how_often_assign(struct kill *msg, int off, const ev_uint32_t value) { if (!msg->how_often_set || off < 0 || off >= msg->how_often_length) return (-1); { msg->how_often_data[off] = value; } return (0); } int kill_weapon_get(struct kill *msg, char * *value) { if (msg->weapon_set != 1) return (-1); *value = msg->weapon_data; return (0); } int kill_action_get(struct kill *msg, char * *value) { if (msg->action_set != 1) return (-1); *value = msg->action_data; return (0); } int kill_how_often_get(struct kill *msg, int offset, ev_uint32_t *value) { if (!msg->how_often_set || offset < 0 || offset >= msg->how_often_length) return (-1); *value = msg->how_often_data[offset]; return (0); } void kill_clear(struct kill *tmp) { if (tmp->weapon_set == 1) { free(tmp->weapon_data); tmp->weapon_data = NULL; tmp->weapon_set = 0; } if (tmp->action_set == 1) { free(tmp->action_data); tmp->action_data = NULL; tmp->action_set = 0; } if (tmp->how_often_set == 1) { free(tmp->how_often_data); tmp->how_often_data = NULL; tmp->how_often_set = 0; tmp->how_often_length = 0; tmp->how_often_num_allocated = 0; } } void kill_free(struct kill *tmp) { if (tmp->weapon_data != NULL) free (tmp->weapon_data); if (tmp->action_data != NULL) free (tmp->action_data); if (tmp->how_often_set == 1) { free(tmp->how_often_data); tmp->how_often_data = NULL; tmp->how_often_set = 0; tmp->how_often_length = 0; tmp->how_often_num_allocated = 0; } free(tmp->how_often_data); free(tmp); } void kill_marshal(struct evbuffer *evbuf, const struct kill *tmp){ evtag_marshal_string(evbuf, KILL_WEAPON, tmp->weapon_data); evtag_marshal_string(evbuf, KILL_ACTION, tmp->action_data); if (tmp->how_often_set) { { int i; for (i = 0; i < tmp->how_often_length; ++i) { evtag_marshal_int(evbuf, KILL_HOW_OFTEN, tmp->how_often_data[i]); } } } } int kill_unmarshal(struct kill *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { case KILL_WEAPON: if (tmp->weapon_set) return (-1); if (evtag_unmarshal_string(evbuf, KILL_WEAPON, &tmp->weapon_data) == -1) { event_warnx("%s: failed to unmarshal weapon", __func__); return (-1); } tmp->weapon_set = 1; break; case KILL_ACTION: if (tmp->action_set) return (-1); if (evtag_unmarshal_string(evbuf, KILL_ACTION, &tmp->action_data) == -1) { event_warnx("%s: failed to unmarshal action", __func__); return (-1); } tmp->action_set = 1; break; case KILL_HOW_OFTEN: if (tmp->how_often_length >= tmp->how_often_num_allocated && kill_how_often_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } if (evtag_unmarshal_int(evbuf, KILL_HOW_OFTEN, &tmp->how_often_data[tmp->how_often_length]) == -1) { event_warnx("%s: failed to unmarshal how_often", __func__); return (-1); } ++tmp->how_often_length; tmp->how_often_set = 1; break; default: return -1; } } if (kill_complete(tmp) == -1) return (-1); return (0); } int kill_complete(struct kill *msg) { if (!msg->weapon_set) return (-1); if (!msg->action_set) return (-1); return (0); } int evtag_unmarshal_kill(struct evbuffer *evbuf, ev_uint32_t need_tag, struct kill *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 (kill_unmarshal(msg, tmp) == -1) goto error; res = 0; error: evbuffer_free(tmp); return (res); } void evtag_marshal_kill(struct evbuffer *evbuf, ev_uint32_t tag, const struct kill *msg) { struct evbuffer *_buf = evbuffer_new(); assert(_buf != NULL); kill_marshal(_buf, msg); evtag_marshal_buffer(evbuf, tag, _buf); evbuffer_free(_buf); } /* * Implementation of run */ static struct run_access_ __run_base = { run_how_assign, run_how_get, run_some_bytes_assign, run_some_bytes_get, run_fixed_bytes_assign, run_fixed_bytes_get, run_notes_assign, run_notes_get, run_notes_add, run_large_number_assign, run_large_number_get, run_other_numbers_assign, run_other_numbers_get, run_other_numbers_add, }; struct run * run_new(void) { return run_new_with_arg(NULL); } struct run * run_new_with_arg(void *unused) { struct run *tmp; if ((tmp = malloc(sizeof(struct run))) == NULL) { event_warn("%s: malloc", __func__); return (NULL); } tmp->base = &__run_base; tmp->how_data = NULL; tmp->how_set = 0; tmp->some_bytes_data = NULL; tmp->some_bytes_length = 0; tmp->some_bytes_set = 0; memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data)); tmp->fixed_bytes_set = 0; tmp->notes_data = NULL; tmp->notes_length = 0; tmp->notes_num_allocated = 0; tmp->notes_set = 0; tmp->large_number_data = 0; tmp->large_number_set = 0; tmp->other_numbers_data = NULL; tmp->other_numbers_length = 0; tmp->other_numbers_num_allocated = 0; tmp->other_numbers_set = 0; return (tmp); } static int run_notes_expand_to_hold_more(struct run *msg) { int tobe_allocated = msg->notes_num_allocated; char ** new_data = NULL; tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; new_data = (char **) realloc(msg->notes_data, tobe_allocated * sizeof(char *)); if (new_data == NULL) return -1; msg->notes_data = new_data; msg->notes_num_allocated = tobe_allocated; return 0;} char * * run_notes_add(struct run *msg, const char * value) { if (++msg->notes_length >= msg->notes_num_allocated) { if (run_notes_expand_to_hold_more(msg)<0) goto error; } if (value != NULL) { msg->notes_data[msg->notes_length - 1] = strdup(value); if (msg->notes_data[msg->notes_length - 1] == NULL) { goto error; } } else { msg->notes_data[msg->notes_length - 1] = NULL; } msg->notes_set = 1; return &(msg->notes_data[msg->notes_length - 1]); error: --msg->notes_length; return (NULL); } static int run_other_numbers_expand_to_hold_more(struct run *msg) { int tobe_allocated = msg->other_numbers_num_allocated; ev_uint32_t* new_data = NULL; tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; new_data = (ev_uint32_t*) realloc(msg->other_numbers_data, tobe_allocated * sizeof(ev_uint32_t)); if (new_data == NULL) return -1; msg->other_numbers_data = new_data; msg->other_numbers_num_allocated = tobe_allocated; return 0;} ev_uint32_t * run_other_numbers_add(struct run *msg, const ev_uint32_t value) { if (++msg->other_numbers_length >= msg->other_numbers_num_allocated) { if (run_other_numbers_expand_to_hold_more(msg)<0) goto error; } msg->other_numbers_data[msg->other_numbers_length - 1] = value; msg->other_numbers_set = 1; return &(msg->other_numbers_data[msg->other_numbers_length - 1]); error: --msg->other_numbers_length; return (NULL); } int run_how_assign(struct run *msg, const char * value) { if (msg->how_data != NULL) free(msg->how_data); if ((msg->how_data = strdup(value)) == NULL) return (-1); msg->how_set = 1; return (0); } int run_some_bytes_assign(struct run *msg, const ev_uint8_t * value, ev_uint32_t len) { if (msg->some_bytes_data != NULL) free (msg->some_bytes_data); msg->some_bytes_data = malloc(len); if (msg->some_bytes_data == NULL) return (-1); msg->some_bytes_set = 1; msg->some_bytes_length = len; memcpy(msg->some_bytes_data, value, len); return (0); } int run_fixed_bytes_assign(struct run *msg, const ev_uint8_t *value) { msg->fixed_bytes_set = 1; memcpy(msg->fixed_bytes_data, value, 24); return (0); } int run_notes_assign(struct run *msg, int off, const char * value) { if (!msg->notes_set || off < 0 || off >= msg->notes_length) return (-1); { if (msg->notes_data[off] != NULL) free(msg->notes_data[off]); msg->notes_data[off] = strdup(value); if (msg->notes_data[off] == NULL) { event_warnx("%s: strdup", __func__); return (-1); } } return (0); } int run_large_number_assign(struct run *msg, const ev_uint64_t value) { msg->large_number_set = 1; msg->large_number_data = value; return (0); } int run_other_numbers_assign(struct run *msg, int off, const ev_uint32_t value) { if (!msg->other_numbers_set || off < 0 || off >= msg->other_numbers_length) return (-1); { msg->other_numbers_data[off] = value; } return (0); } int run_how_get(struct run *msg, char * *value) { if (msg->how_set != 1) return (-1); *value = msg->how_data; return (0); } int run_some_bytes_get(struct run *msg, ev_uint8_t * *value, ev_uint32_t *plen) { if (msg->some_bytes_set != 1) return (-1); *value = msg->some_bytes_data; *plen = msg->some_bytes_length; return (0); } int run_fixed_bytes_get(struct run *msg, ev_uint8_t **value) { if (msg->fixed_bytes_set != 1) return (-1); *value = msg->fixed_bytes_data; return (0); } int run_notes_get(struct run *msg, int offset, char * *value) { if (!msg->notes_set || offset < 0 || offset >= msg->notes_length) return (-1); *value = msg->notes_data[offset]; return (0); } int run_large_number_get(struct run *msg, ev_uint64_t *value) { if (msg->large_number_set != 1) return (-1); *value = msg->large_number_data; return (0); } int run_other_numbers_get(struct run *msg, int offset, ev_uint32_t *value) { if (!msg->other_numbers_set || offset < 0 || offset >= msg->other_numbers_length) return (-1); *value = msg->other_numbers_data[offset]; return (0); } void run_clear(struct run *tmp) { if (tmp->how_set == 1) { free(tmp->how_data); tmp->how_data = NULL; tmp->how_set = 0; } if (tmp->some_bytes_set == 1) { free (tmp->some_bytes_data); tmp->some_bytes_data = NULL; tmp->some_bytes_length = 0; tmp->some_bytes_set = 0; } tmp->fixed_bytes_set = 0; memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data)); if (tmp->notes_set == 1) { int i; for (i = 0; i < tmp->notes_length; ++i) { if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]); } free(tmp->notes_data); tmp->notes_data = NULL; tmp->notes_set = 0; tmp->notes_length = 0; tmp->notes_num_allocated = 0; } tmp->large_number_set = 0; if (tmp->other_numbers_set == 1) { free(tmp->other_numbers_data); tmp->other_numbers_data = NULL; tmp->other_numbers_set = 0; tmp->other_numbers_length = 0; tmp->other_numbers_num_allocated = 0; } } void run_free(struct run *tmp) { if (tmp->how_data != NULL) free (tmp->how_data); if (tmp->some_bytes_data != NULL) free(tmp->some_bytes_data); if (tmp->notes_set == 1) { int i; for (i = 0; i < tmp->notes_length; ++i) { if (tmp->notes_data[i] != NULL) free(tmp->notes_data[i]); } free(tmp->notes_data); tmp->notes_data = NULL; tmp->notes_set = 0; tmp->notes_length = 0; tmp->notes_num_allocated = 0; } free(tmp->notes_data); if (tmp->other_numbers_set == 1) { free(tmp->other_numbers_data); tmp->other_numbers_data = NULL; tmp->other_numbers_set = 0; tmp->other_numbers_length = 0; tmp->other_numbers_num_allocated = 0; } free(tmp->other_numbers_data); free(tmp); } void run_marshal(struct evbuffer *evbuf, const struct run *tmp){ evtag_marshal_string(evbuf, RUN_HOW, tmp->how_data); if (tmp->some_bytes_set) { evtag_marshal(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length); } evtag_marshal(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24)); if (tmp->notes_set) { { int i; for (i = 0; i < tmp->notes_length; ++i) { evtag_marshal_string(evbuf, RUN_NOTES, tmp->notes_data[i]); } } } if (tmp->large_number_set) { evtag_marshal_int64(evbuf, RUN_LARGE_NUMBER, tmp->large_number_data); } if (tmp->other_numbers_set) { { int i; for (i = 0; i < tmp->other_numbers_length; ++i) { evtag_marshal_int(evbuf, RUN_OTHER_NUMBERS, tmp->other_numbers_data[i]); } } } } int run_unmarshal(struct run *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { case RUN_HOW: if (tmp->how_set) return (-1); if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) { event_warnx("%s: failed to unmarshal how", __func__); return (-1); } tmp->how_set = 1; break; case RUN_SOME_BYTES: if (tmp->some_bytes_set) return (-1); if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1) return (-1); if (tmp->some_bytes_length > evbuffer_get_length(evbuf)) return (-1); if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL) return (-1); if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) { event_warnx("%s: failed to unmarshal some_bytes", __func__); return (-1); } tmp->some_bytes_set = 1; break; case RUN_FIXED_BYTES: if (tmp->fixed_bytes_set) return (-1); if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24)) == -1) { event_warnx("%s: failed to unmarshal fixed_bytes", __func__); return (-1); } tmp->fixed_bytes_set = 1; break; case RUN_NOTES: if (tmp->notes_length >= tmp->notes_num_allocated && run_notes_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } if (evtag_unmarshal_string(evbuf, RUN_NOTES, &tmp->notes_data[tmp->notes_length]) == -1) { event_warnx("%s: failed to unmarshal notes", __func__); return (-1); } ++tmp->notes_length; tmp->notes_set = 1; break; case RUN_LARGE_NUMBER: if (tmp->large_number_set) return (-1); if (evtag_unmarshal_int64(evbuf, RUN_LARGE_NUMBER, &tmp->large_number_data) == -1) { event_warnx("%s: failed to unmarshal large_number", __func__); return (-1); } tmp->large_number_set = 1; break; case RUN_OTHER_NUMBERS: if (tmp->other_numbers_length >= tmp->other_numbers_num_allocated && run_other_numbers_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } if (evtag_unmarshal_int(evbuf, RUN_OTHER_NUMBERS, &tmp->other_numbers_data[tmp->other_numbers_length]) == -1) { event_warnx("%s: failed to unmarshal other_numbers", __func__); return (-1); } ++tmp->other_numbers_length; tmp->other_numbers_set = 1; break; default: return -1; } } if (run_complete(tmp) == -1) return (-1); return (0); } int run_complete(struct run *msg) { if (!msg->how_set) return (-1); if (!msg->fixed_bytes_set) return (-1); return (0); } int evtag_unmarshal_run(struct evbuffer *evbuf, ev_uint32_t need_tag, struct run *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 (run_unmarshal(msg, tmp) == -1) goto error; res = 0; error: evbuffer_free(tmp); return (res); } void evtag_marshal_run(struct evbuffer *evbuf, ev_uint32_t tag, const struct run *msg) { struct evbuffer *_buf = evbuffer_new(); assert(_buf != NULL); run_marshal(_buf, msg); evtag_marshal_buffer(evbuf, tag, _buf); evbuffer_free(_buf); } lldpd-0.7.7/libevent/test/bench_http.c0000644000076400001440000001150512074262762014630 00000000000000/* * 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; unsigned short port = 8080; char *endptr = NULL; #ifdef WIN32 WSADATA WSAData; WSAStartup(0x101, &WSAData); #else if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return (1); #endif 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; evthread_use_windows_threads(); 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"); #ifdef _EVENT2_EVENT_H_ evhttp_set_cb(http, "/ref", http_ref_cb, NULL); fprintf(stderr, "/ref - basic content (reference)\n"); #endif 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); if (use_iocp) { struct timeval tv={99999999,0}; event_base_loopexit(base, &tv); } event_base_dispatch(base); /* NOTREACHED */ return (0); } lldpd-0.7.7/libevent/test/regress_thread.c0000644000076400001440000003127112074262762015515 00000000000000/* * 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 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/util.h" #include "event2/event.h" #include "event2/event_struct.h" #include "event2/thread.h" #include "evthread-internal.h" #include "event-internal.h" #include "defer-internal.h" #include "regress.h" #include "tinytest_macros.h" #ifdef _EVENT_HAVE_PTHREADS #define THREAD_T pthread_t #define THREAD_FN void * #define THREAD_RETURN() return (NULL) #define THREAD_START(threadvar, fn, arg) \ pthread_create(&(threadvar), NULL, fn, arg) #define THREAD_JOIN(th) pthread_join(th, NULL) #else #define THREAD_T HANDLE #define THREAD_FN unsigned __stdcall #define THREAD_RETURN() return (0) #define THREAD_START(threadvar, fn, arg) do { \ uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \ (threadvar) = (HANDLE) threadhandle; \ } while (0) #define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE) #endif 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 (abs(diff1) < abs(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, 50); } tt_int_op(n_broadcast + n_signal + n_timed_out, ==, NUM_THREADS); tt_int_op(n_signal, ==, 1); end: ; } #define CB_COUNT 128 #define QUEUE_THREAD_COUNT 8 #ifdef WIN32 #define SLEEP_MS(ms) Sleep(ms) #else #define SLEEP_MS(ms) usleep((ms) * 1000) #endif struct deferred_test_data { struct deferred_cb cbs[CB_COUNT]; struct deferred_cb_queue *queue; }; static time_t timer_start = 0; static time_t timer_end = 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 deferred_cb *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], 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) { timer_end = time(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 basic_test_data *data = arg; struct timeval tv_timer = {4, 0}; struct deferred_cb_queue *queue; time_t elapsed; int i; queue = event_base_get_deferred_cb_queue(data->base); tt_assert(queue); for (i = 0; i < QUEUE_THREAD_COUNT; ++i) deferred_data[i].queue = queue; timer_start = time(NULL); event_base_once(data->base, -1, EV_TIMEOUT, timer_callback, NULL, &tv_timer); event_base_once(data->base, -1, EV_TIMEOUT, start_threads_callback, NULL, NULL); event_base_dispatch(data->base); elapsed = timer_end - timer_start; TT_BLATHER(("callback count, %u", callback_count)); TT_BLATHER(("elapsed time, %u", (unsigned)elapsed)); /* XXX be more intelligent here. just make sure skew is * within 2 seconds for now. */ tt_assert(elapsed >= 4 && elapsed <= 6); end: for (i = 0; i < QUEUE_THREAD_COUNT; ++i) THREAD_JOIN(load_threads[i]); } #define TEST(name) \ { #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \ &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), TEST(deferred_cb_skew), END_OF_TESTCASES }; lldpd-0.7.7/libevent/test/Makefile.in0000644000076400001440000022765112237715703014425 00000000000000# Makefile.in generated by automake 1.14 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # test/Makefile.am for libevent # Copyright 2000-2007 Niels Provos # Copyright 2007-2012 Niels Provos and Nick Mathewson # # See LICENSE for copying information. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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@ noinst_PROGRAMS = test-init$(EXEEXT) test-eof$(EXEEXT) \ test-weof$(EXEEXT) test-time$(EXEEXT) bench$(EXEEXT) \ bench_cascade$(EXEEXT) bench_http$(EXEEXT) \ bench_httpclient$(EXEEXT) test-ratelim$(EXEEXT) \ test-changelist$(EXEEXT) $(am__EXEEXT_1) @BUILD_REGRESS_TRUE@am__append_1 = regress EXTRA_PROGRAMS = regress$(EXEEXT) @BUILD_REGRESS_TRUE@am__append_2 = regress.gen.c regress.gen.h @PTHREADS_TRUE@am__append_3 = ../libevent_pthreads.la @BUILD_WIN32_TRUE@am__append_4 = regress_iocp.c @OPENSSL_TRUE@am__append_5 = regress_ssl.c @OPENSSL_TRUE@am__append_6 = ../libevent_openssl.la -lssl -lcrypto ${OPENSSL_LIBADD} subdir = test DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/../depcomp $(noinst_HEADERS) \ $(top_srcdir)/../test-driver 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/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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @BUILD_REGRESS_TRUE@am__EXEEXT_1 = regress$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) am_bench_OBJECTS = bench.$(OBJEXT) bench_OBJECTS = $(am_bench_OBJECTS) am__DEPENDENCIES_1 = bench_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la 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 = am_bench_cascade_OBJECTS = bench_cascade.$(OBJEXT) bench_cascade_OBJECTS = $(am_bench_cascade_OBJECTS) bench_cascade_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am_bench_http_OBJECTS = bench_http.$(OBJEXT) bench_http_OBJECTS = $(am_bench_http_OBJECTS) bench_http_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la am_bench_httpclient_OBJECTS = bench_httpclient.$(OBJEXT) bench_httpclient_OBJECTS = $(am_bench_httpclient_OBJECTS) bench_httpclient_DEPENDENCIES = $(am__DEPENDENCIES_1) \ ../libevent_core.la am__regress_SOURCES_DIST = regress.c regress_buffer.c regress_http.c \ regress_dns.c regress_testutils.c regress_testutils.h \ regress_rpc.c regress.gen.c regress.gen.h regress_et.c \ regress_bufferevent.c regress_listener.c regress_util.c \ tinytest.c regress_main.c regress_minheap.c regress_thread.c \ regress_zlib.c regress_iocp.c regress_ssl.c @BUILD_WIN32_FALSE@@PTHREADS_TRUE@am__objects_1 = regress-regress_thread.$(OBJEXT) @BUILD_WIN32_TRUE@am__objects_1 = regress-regress_thread.$(OBJEXT) @ZLIB_REGRESS_TRUE@am__objects_2 = regress-regress_zlib.$(OBJEXT) @BUILD_WIN32_TRUE@am__objects_3 = regress-regress_iocp.$(OBJEXT) @OPENSSL_TRUE@am__objects_4 = regress-regress_ssl.$(OBJEXT) am_regress_OBJECTS = regress-regress.$(OBJEXT) \ regress-regress_buffer.$(OBJEXT) \ regress-regress_http.$(OBJEXT) regress-regress_dns.$(OBJEXT) \ regress-regress_testutils.$(OBJEXT) \ regress-regress_rpc.$(OBJEXT) regress-regress.gen.$(OBJEXT) \ regress-regress_et.$(OBJEXT) \ regress-regress_bufferevent.$(OBJEXT) \ regress-regress_listener.$(OBJEXT) \ regress-regress_util.$(OBJEXT) regress-tinytest.$(OBJEXT) \ regress-regress_main.$(OBJEXT) \ regress-regress_minheap.$(OBJEXT) $(am__objects_1) \ $(am__objects_2) $(am__objects_3) $(am__objects_4) regress_OBJECTS = $(am_regress_OBJECTS) am__DEPENDENCIES_2 = $(am__append_3) @OPENSSL_TRUE@am__DEPENDENCIES_3 = ../libevent_openssl.la \ @OPENSSL_TRUE@ $(am__DEPENDENCIES_1) regress_DEPENDENCIES = $(am__DEPENDENCIES_1) ../libevent.la \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_3) regress_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(regress_LDFLAGS) $(LDFLAGS) -o $@ am_test_changelist_OBJECTS = test-changelist.$(OBJEXT) test_changelist_OBJECTS = $(am_test_changelist_OBJECTS) test_changelist_DEPENDENCIES = ../libevent_core.la am_test_eof_OBJECTS = test-eof.$(OBJEXT) test_eof_OBJECTS = $(am_test_eof_OBJECTS) test_eof_DEPENDENCIES = ../libevent_core.la am_test_init_OBJECTS = test-init.$(OBJEXT) test_init_OBJECTS = $(am_test_init_OBJECTS) test_init_DEPENDENCIES = ../libevent_core.la am_test_ratelim_OBJECTS = test-ratelim.$(OBJEXT) test_ratelim_OBJECTS = $(am_test_ratelim_OBJECTS) test_ratelim_DEPENDENCIES = ../libevent_core.la am_test_time_OBJECTS = test-time.$(OBJEXT) test_time_OBJECTS = $(am_test_time_OBJECTS) test_time_DEPENDENCIES = ../libevent_core.la am_test_weof_OBJECTS = test-weof.$(OBJEXT) test_weof_OBJECTS = $(am_test_weof_OBJECTS) test_weof_DEPENDENCIES = ../libevent_core.la 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@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles 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 = $(bench_SOURCES) $(bench_cascade_SOURCES) \ $(bench_http_SOURCES) $(bench_httpclient_SOURCES) \ $(regress_SOURCES) $(test_changelist_SOURCES) \ $(test_eof_SOURCES) $(test_init_SOURCES) \ $(test_ratelim_SOURCES) $(test_time_SOURCES) \ $(test_weof_SOURCES) DIST_SOURCES = $(bench_SOURCES) $(bench_cascade_SOURCES) \ $(bench_http_SOURCES) $(bench_httpclient_SOURCES) \ $(am__regress_SOURCES_DIST) $(test_changelist_SOURCES) \ $(test_eof_SOURCES) $(test_init_SOURCES) \ $(test_ratelim_SOURCES) $(test_time_SOURCES) \ $(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 HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # 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)` ETAGS = etags CTAGS = ctags 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__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__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` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/../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)/../test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 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@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ 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@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ 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@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ $(am__append_3) 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@ 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@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat -I$(top_srcdir)/include -I../include -DTINYTEST_LOCAL EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c rpcgen_wrapper.sh test.sh noinst_HEADERS = tinytest.h tinytest_macros.h regress.h tinytest_local.h # We need to copy this file, since automake doesn't want us to use top_srcdir # in TESTS. TESTS = test-script.sh DISTCLEANFILES = test-script.sh *~ BUILT_SOURCES = $(am__append_2) test_init_SOURCES = test-init.c test_init_LDADD = ../libevent_core.la test_eof_SOURCES = test-eof.c test_eof_LDADD = ../libevent_core.la test_changelist_SOURCES = test-changelist.c test_changelist_LDADD = ../libevent_core.la test_weof_SOURCES = test-weof.c test_weof_LDADD = ../libevent_core.la test_time_SOURCES = test-time.c test_time_LDADD = ../libevent_core.la test_ratelim_SOURCES = test-ratelim.c test_ratelim_LDADD = ../libevent_core.la -lm regress_SOURCES = regress.c regress_buffer.c regress_http.c \ regress_dns.c regress_testutils.c regress_testutils.h \ regress_rpc.c regress.gen.c regress.gen.h regress_et.c \ regress_bufferevent.c regress_listener.c regress_util.c \ tinytest.c regress_main.c regress_minheap.c \ $(regress_thread_SOURCES) $(regress_zlib_SOURCES) \ $(am__append_4) $(am__append_5) @BUILD_WIN32_TRUE@regress_thread_SOURCES = regress_thread.c @PTHREADS_TRUE@regress_thread_SOURCES = regress_thread.c @ZLIB_REGRESS_TRUE@regress_zlib_SOURCES = regress_zlib.c regress_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la $(PTHREAD_LIBS) \ $(ZLIB_LIBS) $(am__append_6) regress_CPPFLAGS = $(AM_CPPFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) regress_LDFLAGS = $(PTHREAD_CFLAGS) bench_SOURCES = bench.c bench_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_cascade_SOURCES = bench_cascade.c bench_cascade_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_http_SOURCES = bench_http.c bench_http_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent.la bench_httpclient_SOURCES = bench_httpclient.c bench_httpclient_LDADD = $(LIBEVENT_GC_SECTIONS) ../libevent_core.la CLEANFILES = rpcgen-attempted all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign test/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): 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 bench$(EXEEXT): $(bench_OBJECTS) $(bench_DEPENDENCIES) $(EXTRA_bench_DEPENDENCIES) @rm -f bench$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bench_OBJECTS) $(bench_LDADD) $(LIBS) bench_cascade$(EXEEXT): $(bench_cascade_OBJECTS) $(bench_cascade_DEPENDENCIES) $(EXTRA_bench_cascade_DEPENDENCIES) @rm -f bench_cascade$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bench_cascade_OBJECTS) $(bench_cascade_LDADD) $(LIBS) bench_http$(EXEEXT): $(bench_http_OBJECTS) $(bench_http_DEPENDENCIES) $(EXTRA_bench_http_DEPENDENCIES) @rm -f bench_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bench_http_OBJECTS) $(bench_http_LDADD) $(LIBS) bench_httpclient$(EXEEXT): $(bench_httpclient_OBJECTS) $(bench_httpclient_DEPENDENCIES) $(EXTRA_bench_httpclient_DEPENDENCIES) @rm -f bench_httpclient$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bench_httpclient_OBJECTS) $(bench_httpclient_LDADD) $(LIBS) regress$(EXEEXT): $(regress_OBJECTS) $(regress_DEPENDENCIES) $(EXTRA_regress_DEPENDENCIES) @rm -f regress$(EXEEXT) $(AM_V_CCLD)$(regress_LINK) $(regress_OBJECTS) $(regress_LDADD) $(LIBS) test-changelist$(EXEEXT): $(test_changelist_OBJECTS) $(test_changelist_DEPENDENCIES) $(EXTRA_test_changelist_DEPENDENCIES) @rm -f test-changelist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_changelist_OBJECTS) $(test_changelist_LDADD) $(LIBS) test-eof$(EXEEXT): $(test_eof_OBJECTS) $(test_eof_DEPENDENCIES) $(EXTRA_test_eof_DEPENDENCIES) @rm -f test-eof$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS) test-init$(EXEEXT): $(test_init_OBJECTS) $(test_init_DEPENDENCIES) $(EXTRA_test_init_DEPENDENCIES) @rm -f test-init$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS) test-ratelim$(EXEEXT): $(test_ratelim_OBJECTS) $(test_ratelim_DEPENDENCIES) $(EXTRA_test_ratelim_DEPENDENCIES) @rm -f test-ratelim$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ratelim_OBJECTS) $(test_ratelim_LDADD) $(LIBS) test-time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) $(EXTRA_test_time_DEPENDENCIES) @rm -f test-time$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) test-weof$(EXEEXT): $(test_weof_OBJECTS) $(test_weof_DEPENDENCIES) $(EXTRA_test_weof_DEPENDENCIES) @rm -f test-weof$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_cascade.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_http.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_httpclient.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress.gen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_bufferevent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_dns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_et.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_http.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_iocp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_listener.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_minheap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_rpc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_ssl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_testutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-regress_zlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regress-tinytest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-changelist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-eof.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-init.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ratelim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-weof.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $@ $< regress-regress.o: regress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.o -MD -MP -MF $(DEPDIR)/regress-regress.Tpo -c -o regress-regress.o `test -f 'regress.c' || echo '$(srcdir)/'`regress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress.Tpo $(DEPDIR)/regress-regress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.o `test -f 'regress.c' || echo '$(srcdir)/'`regress.c regress-regress.obj: regress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.obj -MD -MP -MF $(DEPDIR)/regress-regress.Tpo -c -o regress-regress.obj `if test -f 'regress.c'; then $(CYGPATH_W) 'regress.c'; else $(CYGPATH_W) '$(srcdir)/regress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress.Tpo $(DEPDIR)/regress-regress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.obj `if test -f 'regress.c'; then $(CYGPATH_W) 'regress.c'; else $(CYGPATH_W) '$(srcdir)/regress.c'; fi` regress-regress_buffer.o: regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_buffer.o -MD -MP -MF $(DEPDIR)/regress-regress_buffer.Tpo -c -o regress-regress_buffer.o `test -f 'regress_buffer.c' || echo '$(srcdir)/'`regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_buffer.Tpo $(DEPDIR)/regress-regress_buffer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_buffer.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_buffer.o `test -f 'regress_buffer.c' || echo '$(srcdir)/'`regress_buffer.c regress-regress_buffer.obj: regress_buffer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_buffer.obj -MD -MP -MF $(DEPDIR)/regress-regress_buffer.Tpo -c -o regress-regress_buffer.obj `if test -f 'regress_buffer.c'; then $(CYGPATH_W) 'regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/regress_buffer.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_buffer.Tpo $(DEPDIR)/regress-regress_buffer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_buffer.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_buffer.obj `if test -f 'regress_buffer.c'; then $(CYGPATH_W) 'regress_buffer.c'; else $(CYGPATH_W) '$(srcdir)/regress_buffer.c'; fi` regress-regress_http.o: regress_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_http.o -MD -MP -MF $(DEPDIR)/regress-regress_http.Tpo -c -o regress-regress_http.o `test -f 'regress_http.c' || echo '$(srcdir)/'`regress_http.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_http.Tpo $(DEPDIR)/regress-regress_http.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_http.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_http.o `test -f 'regress_http.c' || echo '$(srcdir)/'`regress_http.c regress-regress_http.obj: regress_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_http.obj -MD -MP -MF $(DEPDIR)/regress-regress_http.Tpo -c -o regress-regress_http.obj `if test -f 'regress_http.c'; then $(CYGPATH_W) 'regress_http.c'; else $(CYGPATH_W) '$(srcdir)/regress_http.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_http.Tpo $(DEPDIR)/regress-regress_http.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_http.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_http.obj `if test -f 'regress_http.c'; then $(CYGPATH_W) 'regress_http.c'; else $(CYGPATH_W) '$(srcdir)/regress_http.c'; fi` regress-regress_dns.o: regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_dns.o -MD -MP -MF $(DEPDIR)/regress-regress_dns.Tpo -c -o regress-regress_dns.o `test -f 'regress_dns.c' || echo '$(srcdir)/'`regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_dns.Tpo $(DEPDIR)/regress-regress_dns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_dns.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_dns.o `test -f 'regress_dns.c' || echo '$(srcdir)/'`regress_dns.c regress-regress_dns.obj: regress_dns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_dns.obj -MD -MP -MF $(DEPDIR)/regress-regress_dns.Tpo -c -o regress-regress_dns.obj `if test -f 'regress_dns.c'; then $(CYGPATH_W) 'regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/regress_dns.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_dns.Tpo $(DEPDIR)/regress-regress_dns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_dns.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_dns.obj `if test -f 'regress_dns.c'; then $(CYGPATH_W) 'regress_dns.c'; else $(CYGPATH_W) '$(srcdir)/regress_dns.c'; fi` regress-regress_testutils.o: regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_testutils.o -MD -MP -MF $(DEPDIR)/regress-regress_testutils.Tpo -c -o regress-regress_testutils.o `test -f 'regress_testutils.c' || echo '$(srcdir)/'`regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_testutils.Tpo $(DEPDIR)/regress-regress_testutils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_testutils.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_testutils.o `test -f 'regress_testutils.c' || echo '$(srcdir)/'`regress_testutils.c regress-regress_testutils.obj: regress_testutils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_testutils.obj -MD -MP -MF $(DEPDIR)/regress-regress_testutils.Tpo -c -o regress-regress_testutils.obj `if test -f 'regress_testutils.c'; then $(CYGPATH_W) 'regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/regress_testutils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_testutils.Tpo $(DEPDIR)/regress-regress_testutils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_testutils.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_testutils.obj `if test -f 'regress_testutils.c'; then $(CYGPATH_W) 'regress_testutils.c'; else $(CYGPATH_W) '$(srcdir)/regress_testutils.c'; fi` regress-regress_rpc.o: regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_rpc.o -MD -MP -MF $(DEPDIR)/regress-regress_rpc.Tpo -c -o regress-regress_rpc.o `test -f 'regress_rpc.c' || echo '$(srcdir)/'`regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_rpc.Tpo $(DEPDIR)/regress-regress_rpc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_rpc.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_rpc.o `test -f 'regress_rpc.c' || echo '$(srcdir)/'`regress_rpc.c regress-regress_rpc.obj: regress_rpc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_rpc.obj -MD -MP -MF $(DEPDIR)/regress-regress_rpc.Tpo -c -o regress-regress_rpc.obj `if test -f 'regress_rpc.c'; then $(CYGPATH_W) 'regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/regress_rpc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_rpc.Tpo $(DEPDIR)/regress-regress_rpc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_rpc.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_rpc.obj `if test -f 'regress_rpc.c'; then $(CYGPATH_W) 'regress_rpc.c'; else $(CYGPATH_W) '$(srcdir)/regress_rpc.c'; fi` regress-regress.gen.o: regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.gen.o -MD -MP -MF $(DEPDIR)/regress-regress.gen.Tpo -c -o regress-regress.gen.o `test -f 'regress.gen.c' || echo '$(srcdir)/'`regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress.gen.Tpo $(DEPDIR)/regress-regress.gen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress.gen.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.gen.o `test -f 'regress.gen.c' || echo '$(srcdir)/'`regress.gen.c regress-regress.gen.obj: regress.gen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress.gen.obj -MD -MP -MF $(DEPDIR)/regress-regress.gen.Tpo -c -o regress-regress.gen.obj `if test -f 'regress.gen.c'; then $(CYGPATH_W) 'regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/regress.gen.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress.gen.Tpo $(DEPDIR)/regress-regress.gen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress.gen.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress.gen.obj `if test -f 'regress.gen.c'; then $(CYGPATH_W) 'regress.gen.c'; else $(CYGPATH_W) '$(srcdir)/regress.gen.c'; fi` regress-regress_et.o: regress_et.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_et.o -MD -MP -MF $(DEPDIR)/regress-regress_et.Tpo -c -o regress-regress_et.o `test -f 'regress_et.c' || echo '$(srcdir)/'`regress_et.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_et.Tpo $(DEPDIR)/regress-regress_et.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_et.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_et.o `test -f 'regress_et.c' || echo '$(srcdir)/'`regress_et.c regress-regress_et.obj: regress_et.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_et.obj -MD -MP -MF $(DEPDIR)/regress-regress_et.Tpo -c -o regress-regress_et.obj `if test -f 'regress_et.c'; then $(CYGPATH_W) 'regress_et.c'; else $(CYGPATH_W) '$(srcdir)/regress_et.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_et.Tpo $(DEPDIR)/regress-regress_et.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_et.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_et.obj `if test -f 'regress_et.c'; then $(CYGPATH_W) 'regress_et.c'; else $(CYGPATH_W) '$(srcdir)/regress_et.c'; fi` regress-regress_bufferevent.o: regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_bufferevent.o -MD -MP -MF $(DEPDIR)/regress-regress_bufferevent.Tpo -c -o regress-regress_bufferevent.o `test -f 'regress_bufferevent.c' || echo '$(srcdir)/'`regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_bufferevent.Tpo $(DEPDIR)/regress-regress_bufferevent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_bufferevent.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_bufferevent.o `test -f 'regress_bufferevent.c' || echo '$(srcdir)/'`regress_bufferevent.c regress-regress_bufferevent.obj: regress_bufferevent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_bufferevent.obj -MD -MP -MF $(DEPDIR)/regress-regress_bufferevent.Tpo -c -o regress-regress_bufferevent.obj `if test -f 'regress_bufferevent.c'; then $(CYGPATH_W) 'regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/regress_bufferevent.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_bufferevent.Tpo $(DEPDIR)/regress-regress_bufferevent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_bufferevent.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_bufferevent.obj `if test -f 'regress_bufferevent.c'; then $(CYGPATH_W) 'regress_bufferevent.c'; else $(CYGPATH_W) '$(srcdir)/regress_bufferevent.c'; fi` regress-regress_listener.o: regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_listener.o -MD -MP -MF $(DEPDIR)/regress-regress_listener.Tpo -c -o regress-regress_listener.o `test -f 'regress_listener.c' || echo '$(srcdir)/'`regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_listener.Tpo $(DEPDIR)/regress-regress_listener.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_listener.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_listener.o `test -f 'regress_listener.c' || echo '$(srcdir)/'`regress_listener.c regress-regress_listener.obj: regress_listener.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_listener.obj -MD -MP -MF $(DEPDIR)/regress-regress_listener.Tpo -c -o regress-regress_listener.obj `if test -f 'regress_listener.c'; then $(CYGPATH_W) 'regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/regress_listener.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_listener.Tpo $(DEPDIR)/regress-regress_listener.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_listener.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_listener.obj `if test -f 'regress_listener.c'; then $(CYGPATH_W) 'regress_listener.c'; else $(CYGPATH_W) '$(srcdir)/regress_listener.c'; fi` regress-regress_util.o: regress_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_util.o -MD -MP -MF $(DEPDIR)/regress-regress_util.Tpo -c -o regress-regress_util.o `test -f 'regress_util.c' || echo '$(srcdir)/'`regress_util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_util.Tpo $(DEPDIR)/regress-regress_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_util.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_util.o `test -f 'regress_util.c' || echo '$(srcdir)/'`regress_util.c regress-regress_util.obj: regress_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_util.obj -MD -MP -MF $(DEPDIR)/regress-regress_util.Tpo -c -o regress-regress_util.obj `if test -f 'regress_util.c'; then $(CYGPATH_W) 'regress_util.c'; else $(CYGPATH_W) '$(srcdir)/regress_util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_util.Tpo $(DEPDIR)/regress-regress_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_util.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_util.obj `if test -f 'regress_util.c'; then $(CYGPATH_W) 'regress_util.c'; else $(CYGPATH_W) '$(srcdir)/regress_util.c'; fi` regress-tinytest.o: tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-tinytest.o -MD -MP -MF $(DEPDIR)/regress-tinytest.Tpo -c -o regress-tinytest.o `test -f 'tinytest.c' || echo '$(srcdir)/'`tinytest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-tinytest.Tpo $(DEPDIR)/regress-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tinytest.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-tinytest.o `test -f 'tinytest.c' || echo '$(srcdir)/'`tinytest.c regress-tinytest.obj: tinytest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-tinytest.obj -MD -MP -MF $(DEPDIR)/regress-tinytest.Tpo -c -o regress-tinytest.obj `if test -f 'tinytest.c'; then $(CYGPATH_W) 'tinytest.c'; else $(CYGPATH_W) '$(srcdir)/tinytest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-tinytest.Tpo $(DEPDIR)/regress-tinytest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tinytest.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-tinytest.obj `if test -f 'tinytest.c'; then $(CYGPATH_W) 'tinytest.c'; else $(CYGPATH_W) '$(srcdir)/tinytest.c'; fi` regress-regress_main.o: regress_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_main.o -MD -MP -MF $(DEPDIR)/regress-regress_main.Tpo -c -o regress-regress_main.o `test -f 'regress_main.c' || echo '$(srcdir)/'`regress_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_main.Tpo $(DEPDIR)/regress-regress_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_main.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_main.o `test -f 'regress_main.c' || echo '$(srcdir)/'`regress_main.c regress-regress_main.obj: regress_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_main.obj -MD -MP -MF $(DEPDIR)/regress-regress_main.Tpo -c -o regress-regress_main.obj `if test -f 'regress_main.c'; then $(CYGPATH_W) 'regress_main.c'; else $(CYGPATH_W) '$(srcdir)/regress_main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_main.Tpo $(DEPDIR)/regress-regress_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_main.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_main.obj `if test -f 'regress_main.c'; then $(CYGPATH_W) 'regress_main.c'; else $(CYGPATH_W) '$(srcdir)/regress_main.c'; fi` regress-regress_minheap.o: regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_minheap.o -MD -MP -MF $(DEPDIR)/regress-regress_minheap.Tpo -c -o regress-regress_minheap.o `test -f 'regress_minheap.c' || echo '$(srcdir)/'`regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_minheap.Tpo $(DEPDIR)/regress-regress_minheap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_minheap.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_minheap.o `test -f 'regress_minheap.c' || echo '$(srcdir)/'`regress_minheap.c regress-regress_minheap.obj: regress_minheap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_minheap.obj -MD -MP -MF $(DEPDIR)/regress-regress_minheap.Tpo -c -o regress-regress_minheap.obj `if test -f 'regress_minheap.c'; then $(CYGPATH_W) 'regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/regress_minheap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_minheap.Tpo $(DEPDIR)/regress-regress_minheap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_minheap.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_minheap.obj `if test -f 'regress_minheap.c'; then $(CYGPATH_W) 'regress_minheap.c'; else $(CYGPATH_W) '$(srcdir)/regress_minheap.c'; fi` regress-regress_thread.o: regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_thread.o -MD -MP -MF $(DEPDIR)/regress-regress_thread.Tpo -c -o regress-regress_thread.o `test -f 'regress_thread.c' || echo '$(srcdir)/'`regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_thread.Tpo $(DEPDIR)/regress-regress_thread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_thread.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_thread.o `test -f 'regress_thread.c' || echo '$(srcdir)/'`regress_thread.c regress-regress_thread.obj: regress_thread.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_thread.obj -MD -MP -MF $(DEPDIR)/regress-regress_thread.Tpo -c -o regress-regress_thread.obj `if test -f 'regress_thread.c'; then $(CYGPATH_W) 'regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/regress_thread.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_thread.Tpo $(DEPDIR)/regress-regress_thread.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_thread.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_thread.obj `if test -f 'regress_thread.c'; then $(CYGPATH_W) 'regress_thread.c'; else $(CYGPATH_W) '$(srcdir)/regress_thread.c'; fi` regress-regress_zlib.o: regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_zlib.o -MD -MP -MF $(DEPDIR)/regress-regress_zlib.Tpo -c -o regress-regress_zlib.o `test -f 'regress_zlib.c' || echo '$(srcdir)/'`regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_zlib.Tpo $(DEPDIR)/regress-regress_zlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_zlib.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_zlib.o `test -f 'regress_zlib.c' || echo '$(srcdir)/'`regress_zlib.c regress-regress_zlib.obj: regress_zlib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_zlib.obj -MD -MP -MF $(DEPDIR)/regress-regress_zlib.Tpo -c -o regress-regress_zlib.obj `if test -f 'regress_zlib.c'; then $(CYGPATH_W) 'regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/regress_zlib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_zlib.Tpo $(DEPDIR)/regress-regress_zlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_zlib.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_zlib.obj `if test -f 'regress_zlib.c'; then $(CYGPATH_W) 'regress_zlib.c'; else $(CYGPATH_W) '$(srcdir)/regress_zlib.c'; fi` regress-regress_iocp.o: regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_iocp.o -MD -MP -MF $(DEPDIR)/regress-regress_iocp.Tpo -c -o regress-regress_iocp.o `test -f 'regress_iocp.c' || echo '$(srcdir)/'`regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_iocp.Tpo $(DEPDIR)/regress-regress_iocp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_iocp.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_iocp.o `test -f 'regress_iocp.c' || echo '$(srcdir)/'`regress_iocp.c regress-regress_iocp.obj: regress_iocp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_iocp.obj -MD -MP -MF $(DEPDIR)/regress-regress_iocp.Tpo -c -o regress-regress_iocp.obj `if test -f 'regress_iocp.c'; then $(CYGPATH_W) 'regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/regress_iocp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_iocp.Tpo $(DEPDIR)/regress-regress_iocp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_iocp.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_iocp.obj `if test -f 'regress_iocp.c'; then $(CYGPATH_W) 'regress_iocp.c'; else $(CYGPATH_W) '$(srcdir)/regress_iocp.c'; fi` regress-regress_ssl.o: regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_ssl.o -MD -MP -MF $(DEPDIR)/regress-regress_ssl.Tpo -c -o regress-regress_ssl.o `test -f 'regress_ssl.c' || echo '$(srcdir)/'`regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_ssl.Tpo $(DEPDIR)/regress-regress_ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_ssl.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_ssl.o `test -f 'regress_ssl.c' || echo '$(srcdir)/'`regress_ssl.c regress-regress_ssl.obj: regress_ssl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT regress-regress_ssl.obj -MD -MP -MF $(DEPDIR)/regress-regress_ssl.Tpo -c -o regress-regress_ssl.obj `if test -f 'regress_ssl.c'; then $(CYGPATH_W) 'regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/regress_ssl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/regress-regress_ssl.Tpo $(DEPDIR)/regress-regress_ssl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regress_ssl.c' object='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) $(regress_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o regress-regress_ssl.obj `if test -f 'regress_ssl.c'; then $(CYGPATH_W) 'regress_ssl.c'; else $(CYGPATH_W) '$(srcdir)/regress_ssl.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs 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" 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 # 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; \ else \ 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 for $(PACKAGE_STRING)$${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-script.sh.log: test-script.sh @p='test-script.sh'; \ b='test-script.sh'; \ $(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: $(DISTFILES) @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 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: 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) -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) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -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: .MAKE: all check check-am install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ 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 test-script.sh: test.sh cp $< $@ regress.gen.c regress.gen.h: rpcgen-attempted rpcgen-attempted: $(srcdir)/regress.rpc $(srcdir)/../event_rpcgen.py $(srcdir)/rpcgen_wrapper.sh date -u > $@ if $(srcdir)/rpcgen_wrapper.sh $(srcdir); then \ echo "rpcgen okay"; \ else \ echo "No Python installed; stubbing out RPC test." >&2; \ echo " "> regress.gen.c; \ echo "#define NO_PYTHON_EXISTS" > regress.gen.h; \ fi verify: check bench test-init test-eof test-weof test-time test-changelist: ../libevent.la # 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-0.7.7/libevent/test/regress_testutils.h0000644000076400001440000000474512074262762016321 00000000000000/* * 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 _TESTUTILS_H #define _TESTUTILS_H #include "event2/dns.h" struct regress_dns_server_table { const char *q; const char *anstype; const char *ans; int seen; }; 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 /* _TESTUTILS_H */ lldpd-0.7.7/libevent/test/regress.c0000644000076400001440000015354012074262762014172 00000000000000/* * 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. */ #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 #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 "util-internal.h" #include "log-internal.h" #include "regress.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" #define SECONDS 1 #ifndef SHUT_WR #define SHUT_WR 1 #endif #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, 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) { struct timeval tv; int diff; evutil_gettimeofday(&tcalled, NULL); if (evutil_timercmp(&tcalled, &tset, >)) evutil_timersub(&tcalled, &tset, &tv); else evutil_timersub(&tset, &tcalled, &tv); diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000; if (diff < 0) diff = -diff; if (diff < 100) test_ok = 1; } 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, 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], 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], 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(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_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 = 0; tv.tv_sec = SECONDS; evtimer_set(&ev, timeout_cb, NULL); evtimer_add(&ev, &tv); evutil_gettimeofday(&tset, NULL); event_dispatch(); 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 }; event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count); event_add(&ev, &msec100); /* Wait for a bit */ #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif 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 >= 6) 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 now; struct timeval tmp_100_ms = { 0, 100*1000 }; struct timeval tmp_200_ms = { 0, 200*1000 }; const struct timeval *ms_100, *ms_200; ms_100 = event_base_init_common_timeout(base, &tmp_100_ms); ms_200 = event_base_init_common_timeout(base, &tmp_200_ms); tt_assert(ms_100); tt_assert(ms_200); tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms), ==, ms_200); tt_int_op(ms_100->tv_sec, ==, 0); tt_int_op(ms_200->tv_sec, ==, 0); tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000); tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000); 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) { event_add(&info[i].ev, ms_100); } else { event_add(&info[i].ev, ms_200); } } event_base_assert_ok(base); event_base_dispatch(base); evutil_gettimeofday(&now, NULL); event_base_assert_ok(base); for (i=0; i<10; ++i) { struct timeval tmp; int ms_diff; tt_int_op(info[i].count, ==, 6); evutil_timersub(&now, &info[i].called_at, &tmp); ms_diff = tmp.tv_usec/1000 + tmp.tv_sec*1000; if (i % 2) { tt_int_op(ms_diff, >, 500); tt_int_op(ms_diff, <, 700); } else { tt_int_op(ms_diff, >, -100); tt_int_op(ms_diff, <, 100); } } /* 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 static void signal_cb(evutil_socket_t fd, short event, void *arg); #define current_base event_global_current_base_ extern struct event_base *current_base; static void child_signal_cb(evutil_socket_t fd, short event, void *arg) { struct timeval tv; int *pint = arg; *pint = 1; tv.tv_usec = 500000; tv.tv_sec = 0; event_loopexit(&tv); } static void test_fork(void) { int status, got_sigchld = 0; struct event ev, sig_ev; pid_t pid; setup_test("After fork: "); 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_read_cb, &ev); if (event_add(&ev, NULL) == -1) exit(1); evsignal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld); evsignal_add(&sig_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); 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 : 76); } /* wait for the child to read the data */ sleep(1); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } TT_BLATHER(("Before waitpid")); if (waitpid(pid, &status, 0) == -1) { fprintf(stdout, "FAILED (fork)\n"); exit(1); } TT_BLATHER(("After waitpid")); if (WEXITSTATUS(status) != 76) { fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); exit(1); } /* 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], SHUT_WR); event_dispatch(); if (!got_sigchld) { fprintf(stdout, "FAILED (sigchld)\n"); exit(1); } evsignal_del(&sig_ev); end: cleanup_test(); } 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(void) { struct event ev; struct itimerval itv; setup_test("Simple signal: "); evsignal_set(&ev, SIGALRM, signal_cb, &ev); evsignal_add(&ev, NULL); /* find bugs in which operations are re-ordered */ evsignal_del(&ev); evsignal_add(&ev, NULL); memset(&itv, 0, sizeof(itv)); itv.it_value.tv_sec = 1; 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_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 = 1; 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); raise(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 */ raise(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); raise(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); raise(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); raise(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) raise(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); raise(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(); if (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 */ } else { tt_fail_msg("failed to create event_base for test"); } base1 = event_init(); tt_assert(base1); event_assign(&ev1, base1, 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 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 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], 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 = 0; tv.tv_sec = 1; event_loopexit(&tv); evutil_gettimeofday(&tv_start, NULL); event_dispatch(); evutil_gettimeofday(&tv_end, NULL); evutil_timersub(&tv_end, &tv_start, &tv_end); evtimer_del(&ev); tt_assert(event_base_got_exit(global_base)); tt_assert(!event_base_got_break(global_base)); if (tv.tv_sec < 2) test_ok = 1; end: cleanup_test(); } static void test_loopexit_multiple(void) { struct timeval tv; struct event_base *base; setup_test("Loop Multiple exit: "); base = event_base_new(); tv.tv_usec = 0; tv.tv_sec = 1; event_base_loopexit(base, &tv); tv.tv_usec = 0; tv.tv_sec = 2; event_base_loopexit(base, &tv); event_base_dispatch(base); tt_assert(event_base_got_exit(base)); tt_assert(!event_base_got_break(base)); event_base_free(base); 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; readd_test_event_last_added = ev_other; if (read(fd, buf, sizeof(buf)) < 0) { tt_fail_perror("read"); } event_add(ev_other, NULL); ++test_ok; } static void test_nonpersist_readd(void) { struct event ev1, ev2; setup_test("Re-add nonpersistent events: "); event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2); event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1); if (write(pair[0], "Hello", 5) < 0) { tt_fail_perror("write(pair[0])"); } if (write(pair[1], "Hello", 5) < 0) { tt_fail_perror("write(pair[1])\n"); } if (event_add(&ev1, NULL) == -1 || event_add(&ev2, NULL) == -1) { test_ok = 0; } if (test_ok != 0) exit(1); event_loop(EVLOOP_ONCE); if (test_ok != 2) exit(1); /* 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. */ if (!readd_test_event_last_added) { test_ok = 0; } else if (readd_test_event_last_added == &ev1) { if (!event_pending(&ev1, EV_READ, NULL) || event_pending(&ev2, EV_READ, NULL)) test_ok = 0; } else { if (event_pending(&ev1, EV_READ, NULL) || !event_pending(&ev2, EV_READ, NULL)) test_ok = 0; } event_del(&ev1); event_del(&ev2); cleanup_test(); } 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_sec = 1; 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) { u_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] = rand(); 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 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); if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); } shutdown(data->pair[1], SHUT_WR); event_base_dispatch(data->base); tt_int_op(called, ==, 101); 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, diff; 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, >)); evutil_timeradd(&now, &tv, &tv); evutil_timersub(&tv2, &tv, &diff); tt_int_op(diff.tv_sec, ==, 0); tt_int_op(labs(diff.tv_usec), <, 1000); 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); } } #ifndef WIN32 /* You can't do this test on windows, since dup2 doesn't work on sockets */ static void dfd_cb(evutil_socket_t fd, short e, void *data) { *(int*)data = (int)e; } /* 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; const int is_evport = !strcmp(event_base_get_method(base),"evport"); 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)); if (is_evport && one_at_a_time) { TT_DECLARE("NOTE", ("evport can't pass this in 2.0; skipping\n")); tt_skip(); } 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); 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: ; } 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(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), 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, &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", test_simpleclose, TT_FORK, &basic_setup, NULL }, 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), LEGACY(nonpersist_readd, TT_ISOLATED), 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_pending", test_event_pending, 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 }, #ifndef WIN32 LEGACY(fork, TT_ISOLATED), #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(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-0.7.7/libevent/test/regress_ssl.c0000644000076400001440000003217312074262762015051 00000000000000/* * 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. */ #ifdef WIN32 #include #include #endif #ifndef WIN32 #include #include #include #endif #include "event2/util.h" #include "event2/event.h" #include "event2/bufferevent_ssl.h" #include "event2/buffer.h" #include "event2/listener.h" #include "regress.h" #include "tinytest.h" #include "tinytest_macros.h" #include #include #include #include #include /* A short pre-generated key, to save the cost of doing an RSA key generation * step during the unit tests. It's only 512 bits long, and 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" "MIIBOgIBAAJBAKibTEzXjj+sqpipePX1lEk5BNFuL/dDBbw8QCXgaJWikOiKHeJq\n" "3FQ0OmCnmpkdsPFE4x3ojYmmdgE2i0dJwq0CAwEAAQJAZ08gpUS+qE1IClps/2gG\n" "AAer6Bc31K2AaiIQvCSQcH440cp062QtWMC3V5sEoWmdLsbAHFH26/9ZHn5zAflp\n" "gQIhANWOx/UYeR8HD0WREU5kcuSzgzNLwUErHLzxP7U6aojpAiEAyh2H35CjN/P7\n" "NhcZ4QYw3PeUWpqgJnaE/4i80BSYkSUCIQDLHFhLYLJZ80HwHTADif/ISn9/Ow6b\n" "p6BWh3DbMar/eQIgBPS6azH5vpp983KXkNv9AL4VZi9ac/b+BeINdzC6GP0CIDmB\n" "U6GFEQTZ3IfuiVabG5pummdC4DNbcdI+WKrSFNmQ\n" "-----END RSA PRIVATE KEY-----\n"; static EVP_PKEY * 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; } static X509 * getcert(void) { /* 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; EVP_PKEY *key = getkey(); 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_time_adj(X509_get_notBefore(x509), 0, &now); now += 3600; X509_time_adj(X509_get_notAfter(x509), 0, &now); X509_set_pubkey(x509, key); tt_assert(0 != X509_sign(x509, key, EVP_sha1())); return x509; end: X509_free(x509); return NULL; } static int disable_tls_11_and_12 = 0; static SSL_CTX *the_ssl_ctx = NULL; static 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 void init_ssl(void) { 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())); } } /* ==================== Here's a simple test: we read a number from the input, increment it, and reply, until we get to 1001. */ static int test_is_done = 0; static int n_connected = 0; static int got_close = 0; static int got_error = 0; static int renegotiate_at = -1; static int stop_when_connected = 0; static int pending_connect_events = 0; static struct event_base *exit_base = NULL; static void respond_to_number(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_input(bev); char *line; int n; line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); if (! line) return; n = atoi(line); if (n <= 0) TT_FAIL(("Bad number: %s", 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 (!strcmp(ctx, "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) { TT_BLATHER(("Got event %d", (int)what)); if (what & BEV_EVENT_CONNECTED) { SSL *ssl; X509 *peer_cert; ++n_connected; ssl = bufferevent_openssl_get_ssl(bev); tt_assert(ssl); peer_cert = SSL_get_peer_certificate(ssl); if (0==strcmp(ctx, "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); } } else if (what & BEV_EVENT_EOF) { TT_BLATHER(("Got a good EOF")); ++got_close; bufferevent_free(bev); } else if (what & BEV_EVENT_ERROR) { TT_BLATHER(("Got an error.")); ++got_error; bufferevent_free(bev); } end: ; } 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) { int state1 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_CONNECTING; int state2 = is_open ? BUFFEREVENT_SSL_OPEN :BUFFEREVENT_SSL_ACCEPTING; 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*)"client"); bufferevent_setcb(*bev2_out, respond_to_number, done_writing_cb, eventcb, (void*)"server"); } static void regress_bufferevent_openssl(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev1, *bev2; SSL *ssl1, *ssl2; X509 *cert = getcert(); EVP_PKEY *key = getkey(); const int start_open = strstr((char*)data->setup_data, "open")!=NULL; const int filter = strstr((char*)data->setup_data, "filter")!=NULL; int flags = BEV_OPT_DEFER_CALLBACKS; struct bufferevent *bev_ll[2] = { NULL, NULL }; evutil_socket_t *fd_pair = NULL; tt_assert(cert); tt_assert(key); init_ssl(); if (strstr((char*)data->setup_data, "renegotiate")) { if (SSLeay() >= 0x10001000 && SSLeay() < 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, cert); SSL_use_PrivateKey(ssl2, key); if (! start_open) flags |= BEV_OPT_CLOSE_ON_FREE; if (!filter) { tt_assert(strstr((char*)data->setup_data, "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); if (!filter) { tt_int_op(bufferevent_getfd(bev1), ==, data->pair[0]); } else { tt_ptr_op(bufferevent_get_underlying(bev1), ==, bev_ll[0]); } if (start_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); } bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_enable(bev2, EV_READ|EV_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. tt_int_op(got_close, ==, 1); tt_int_op(got_error, ==, 0); */ end: return; } 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; SSL *ssl = SSL_new(get_ssl_ctx()); SSL_use_certificate(ssl, getcert()); SSL_use_PrivateKey(ssl, getkey()); bev = bufferevent_openssl_socket_new( data->base, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); bufferevent_setcb(bev, respond_to_number, NULL, eventcb, (void*)"server"); bufferevent_enable(bev, EV_READ|EV_WRITE); /* Only accept once, then disable ourself. */ evconnlistener_disable(listener); } 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; init_ssl(); 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); bev = bufferevent_openssl_socket_new( data->base, -1, SSL_new(get_ssl_ctx()), BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); tt_assert(bev); bufferevent_setcb(bev, respond_to_number, NULL, eventcb, (void*)"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_int_op(((struct sockaddr*)&ss)->sa_family, ==, AF_INET); tt_assert(0 == bufferevent_socket_connect(bev, (struct sockaddr*)&ss, slen)); evbuffer_add_printf(bufferevent_get_output(bev), "1\n"); bufferevent_enable(bev, EV_READ|EV_WRITE); event_base_dispatch(base); end: ; } struct testcase_t ssl_testcases[] = { { "bufferevent_socketpair", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"socketpair" }, { "bufferevent_filter", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"filter" }, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"socketpair renegotiate" }, { "bufferevent_renegotiate_filter", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"filter renegotiate" }, { "bufferevent_socketpair_startopen", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"socketpair open" }, { "bufferevent_filter_startopen", regress_bufferevent_openssl, TT_ISOLATED, &basic_setup, (void*)"filter open" }, { "bufferevent_connect", regress_bufferevent_openssl_connect, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, END_OF_TESTCASES, }; lldpd-0.7.7/libevent/test/tinytest_local.h0000644000076400001440000000025112074262762015550 00000000000000 #ifdef WIN32 #include #endif #include "event2/util.h" #include "util-internal.h" #ifdef snprintf #undef snprintf #endif #define snprintf evutil_snprintf lldpd-0.7.7/libevent/test/regress_buffer.c0000644000076400001440000013542312074262762015523 00000000000000/* * 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. */ #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 "evbuffer-internal.h" #include "log-internal.h" #include "regress.h" /* 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) != 0); 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]; 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); /* move three bytes over */ evbuffer_remove_buffer(src, dst, 3); evbuffer_validate(src); evbuffer_validate(dst); end: evbuffer_free(src); evbuffer_free(dst); } 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_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 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); } int _evbuffer_testing_use_sendfile(void); int _evbuffer_testing_use_mmap(void); int _evbuffer_testing_use_linear_file_access(void); static void test_evbuffer_add_file(void *ptr) { const char *impl = ptr; struct evbuffer *src = evbuffer_new(); const char *data = "this is what we add as file system data."; size_t datalen; const char *compare; int fd = -1; evutil_socket_t pair[2] = {-1, -1}; int r=0, n_written=0; /* Add a test for a big file. XXXX */ tt_assert(impl); if (!strcmp(impl, "sendfile")) { if (!_evbuffer_testing_use_sendfile()) tt_skip(); TT_BLATHER(("Using sendfile-based implementaion")); } else if (!strcmp(impl, "mmap")) { if (!_evbuffer_testing_use_mmap()) tt_skip(); TT_BLATHER(("Using mmap-based implementaion")); } else if (!strcmp(impl, "linear")) { if (!_evbuffer_testing_use_linear_file_access()) tt_skip(); TT_BLATHER(("Using read-based implementaion")); } else { TT_DIE(("Didn't recognize the implementation")); } /* 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 datalen = strlen(data); fd = regress_make_tmpfile(data, datalen); tt_assert(fd != -1); tt_assert(evbuffer_add_file(src, fd, 0, datalen) != -1); evbuffer_validate(src); while (evbuffer_get_length(src) && (r = evbuffer_write(src, pair[0])) > 0) { evbuffer_validate(src); n_written += r; } tt_int_op(r, !=, -1); tt_int_op(n_written, ==, datalen); evbuffer_validate(src); tt_int_op(evbuffer_read(src, pair[1], (int)strlen(data)), ==, datalen); evbuffer_validate(src); compare = (char *)evbuffer_pullup(src, datalen); tt_assert(compare != NULL); if (memcmp(compare, data, datalen)) tt_abort_msg("Data from add_file differs."); evbuffer_validate(src); end: if (pair[0] >= 0) evutil_closesocket(pair[0]); if (pair[1] >= 0) evutil_closesocket(pair[1]); evbuffer_free(src); } #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 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); 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) { u_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, (u_char*)test1, strlen(test1)); evbuffer_validate(buf); evbuffer_drain(buf, strlen(test1)); evbuffer_validate(buf); evbuffer_add(buf, (u_char*)test2, strlen(test2)); evbuffer_validate(buf); p = evbuffer_find(buf, (u_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, (u_char *)test3, EVBUFFER_INITIAL_LENGTH); evbuffer_validate(buf); p = evbuffer_find(buf, (u_char *)"xy", 2); tt_want(p == NULL); /* simple test for match at end of allocated buffer */ p = evbuffer_find(buf, (u_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); /* 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) == -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); /* 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); 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(evbuffer_pullup(buf_out1, -1), ==, "0->36; 36->26; 26->31; 31->38; "); tt_str_op(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); evbuffer_setcb(buf, self_draining_callback, NULL); 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); evbuffer_setcb(buf, NULL, NULL); evbuffer_add_printf(buf, "This will not."); tt_str_op(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 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.", 42); 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); } /* 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]; 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); 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); tmp[n]='\0'; tt_str_op(tmp,==,"Here is string 1000. Here is string 999. "); end: if (buf1) evbuffer_free(buf1); if (buf2) evbuffer_free(buf2); } 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*/ 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 evbuffer *buf = 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(ptr, "start"); char *cp; char charbuf[128]; int r; size_t orig_length; struct evbuffer_iovec v[1]; if (!start) tt_str_op(ptr, ==, "end"); buf = evbuffer_new(); tmp_buf = evbuffer_new(); tt_assert(tmp_buf); evbuffer_add(buf, string, strlen(string)); evbuffer_freeze(buf, start); /* Freeze the start or the end.*/ #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 == 0) { 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); /* TODO: test add_buffer, add_file, read */ 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); /* TODO: Test remove_buffer, add_buffer, write, prepend_buffer */ if (start) tt_int_op(orig_length, ==, evbuffer_get_length(buf)); end: if (buf) evbuffer_free(buf); if (tmp_buf) evbuffer_free(tmp_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 }, { "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" }, { "expand", test_evbuffer_expand, 0, NULL, NULL }, { "reference", test_evbuffer_reference, 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 }, { "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL }, { "peek", test_evbuffer_peek, 0, NULL, NULL }, { "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" }, { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" }, /* TODO: need a temp file implementation for Windows */ { "add_file_sendfile", test_evbuffer_add_file, TT_FORK, &nil_setup, (void*)"sendfile" }, { "add_file_mmap", test_evbuffer_add_file, TT_FORK, &nil_setup, (void*)"mmap" }, { "add_file_linear", test_evbuffer_add_file, TT_FORK, &nil_setup, (void*)"linear" }, END_OF_TESTCASES }; lldpd-0.7.7/libevent/test/regress_listener.c0000644000076400001440000001414312074262762016072 00000000000000/* * 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. */ #ifdef WIN32 #include #include #endif #include #ifndef WIN32 #include #include # ifdef _XOPEN_SOURCE_EXTENDED # include # endif #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" #include "util-internal.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 = -1, fd2 = -1, fd3 = -1; 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_int_op(evconnlistener_get_fd(listener1), >=, 0); tt_int_op(evconnlistener_get_fd(listener2), >=, 0); 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 = -1; 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); } 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"}, { "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"}, 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-0.7.7/libevent/test/test-eof.c0000644000076400001440000000614212074262762014241 00000000000000/* * 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" #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 #ifdef _EVENT___func__ #define __func__ _EVENT___func__ #endif 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++; } #ifndef SHUT_WR #define SHUT_WR 1 #endif 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], SHUT_WR); /* Initalize the event library */ event_init(); /* Initalize one event */ event_set(&ev, pair[1], EV_READ | EV_TIMEOUT, read_cb, &ev); event_add(&ev, &timeout); event_dispatch(); return (test_okay); } lldpd-0.7.7/libevent/test/regress_testutils.c0000644000076400001440000001432012074262762016302 00000000000000/* * 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. */ #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" #include "../util-internal.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 = htonl(0x7f000001UL); 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); if (dns_sock >= 0) evutil_closesocket(dns_sock); } void regress_dns_server_cb(struct evdns_server_request *req, void *data) { struct regress_dns_server_table *tab = 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; 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 (!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-0.7.7/libevent/test/regress_http.c0000644000076400001440000027531112155052147015224 00000000000000/* * 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. */ #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/util.h" #include "log-internal.h" #include "util-internal.h" #include "http-internal.h" #include "regress.h" #include "regress_testutils.h" static struct evhttp *http; /* 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_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 int http_bind(struct evhttp *myhttp, ev_uint16_t *pport) { int port; struct evhttp_bound_socket *sock; sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport); if (sock == NULL) 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; } static struct evhttp * http_setup(ev_uint16_t *pport, struct event_base *base) { struct evhttp *myhttp; /* Try a few different ports */ myhttp = evhttp_new(base); if (http_bind(myhttp, pport) < 0) return NULL; /* Register a callback for certain types of requests */ evhttp_set_cb(myhttp, "/test", http_basic_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, "/", http_dispatcher_cb, base); return (myhttp); } #ifndef NI_MAXSERV #define NI_MAXSERV 1024 #endif static evutil_socket_t http_connect(const char *address, u_short port) { /* Stupid code for connecting */ struct evutil_addrinfo ai, *aitop; char strport[NI_MAXSERV]; struct sockaddr *sa; int 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 ((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) { test_ok = -2; event_base_loopexit(arg, NULL); } static void http_basic_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; event_debug(("%s: called\n", __func__)); evbuffer_add_printf(evb, BASIC_REQUEST_BODY); /* For multi-line headers test */ { const char *multi = evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi"); if (multi) { if (strcmp("END", multi + strlen(multi) - 3) == 0) test_ok++; if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last")) test_ok++; } } /* 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); 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)); event_debug(("%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 void http_complete_write(evutil_socket_t fd, short what, void *arg) { struct bufferevent *bev = arg; const char *http_request = "host\r\n" "Connection: close\r\n" "\r\n"; bufferevent_write(bev, http_request, strlen(http_request)); } static void http_basic_test(void *arg) { struct basic_test_data *data = arg; struct timeval tv; struct bufferevent *bev; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0, port2 = 0; test_ok = 0; http = http_setup(&port, data->base); /* bind to a second socket */ if (http_bind(http, &port2) == -1) { fprintf(stdout, "FAILED (bind)\n"); exit(1); } fd = http_connect("127.0.0.1", port); /* 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); /* first half of the http request */ http_request = "GET /test HTTP/1.1\r\n" "Host: some"; bufferevent_write(bev, http_request, strlen(http_request)); evutil_timerclear(&tv); tv.tv_usec = 10000; event_base_once(data->base, -1, EV_TIMEOUT, http_complete_write, bev, &tv); event_base_dispatch(data->base); tt_assert(test_ok == 3); /* connect to the second port */ bufferevent_free(bev); evutil_closesocket(fd); fd = http_connect("127.0.0.1", port2); /* 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 /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(data->base); tt_assert(test_ok == 5); /* Connect to the second port again. This time, send an absolute uri. */ bufferevent_free(bev); evutil_closesocket(fd); fd = http_connect("127.0.0.1", port2); /* 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 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)); event_base_dispatch(data->base); tt_assert(test_ok == 7); evhttp_free(http); end: ; } 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) { event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg)); /* ignore */ } #ifndef SHUT_WR #ifdef WIN32 #define SHUT_WR SD_SEND #else #define SHUT_WR 1 #endif #endif 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), SHUT_WR); } static void http_badreq_successcb(evutil_socket_t fd, short what, void *arg) { event_debug(("%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; const char *http_request; ev_uint16_t port=0, port2=0; test_ok = 0; exit_base = data->base; http = http_setup(&port, data->base); /* bind to a second socket */ if (http_bind(http, &port2) == -1) TT_DIE(("Bind socket failed")); /* NULL request test */ fd = http_connect("127.0.0.1", port); /* 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, 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); /* 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); } 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_sec = 3; event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv); evhttp_connection_fail(delayed_client, EVCON_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); } event_debug(("%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; const char *http_request; ev_uint16_t port = 0; test_ok = 0; http = http_setup(&port, data->base); fd = http_connect("127.0.0.1", port); /* 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); evhttp_free(http); tt_int_op(test_ok, ==, 2); end: ; } 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, fd2, fd3; const char *http_request; char *result1=NULL, *result2=NULL, *result3=NULL; ev_uint16_t port = 0; exit_base = data->base; test_ok = 0; http = http_setup(&port, data->base); fd1 = http_connect("127.0.0.1", port); /* 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); 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); 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); evutil_closesocket(fd1); evutil_closesocket(fd2); evutil_closesocket(fd3); 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); } 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) { ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; test_ok = 0; http = http_setup(&port, data->base); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); tt_assert(evhttp_connection_get_base(evcon) == data->base); exit_base = data->base; /* * 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); } static void http_persist_connection_test(void *arg) { _http_connection_test(arg, 1); } static struct regress_dns_server_table search_table[] = { { "localhost", "A", "127.0.0.1", 0 }, { NULL, NULL, NULL, 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]; 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; http = http_setup(&port, data->base); 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_request_never_call(struct evhttp_request *req, void *arg) { fprintf(stdout, "FAILED\n"); exit(1); } static void http_do_cancel(evutil_socket_t fd, short what, void *arg) { struct evhttp_request *req = arg; struct timeval tv; struct event_base *base; evutil_timerclear(&tv); tv.tv_sec = 0; tv.tv_usec = 500 * 1000; base = evhttp_connection_get_base(evhttp_request_get_connection(req)); evhttp_cancel_request(req); event_base_loopexit(base, &tv); ++test_ok; } 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 timeval tv; exit_base = data->base; test_ok = 0; http = http_setup(&port, data->base); evcon = evhttp_connection_base_new(data->base, NULL, "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_never_call, NULL); /* 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); tt_int_op(test_ok, ==, 2); /* 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"); /* 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; 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: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_request_done(struct evhttp_request *req, void *arg) { const char *what = 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), "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; exit_base = data->base; http = http_setup(&port, data->base); /* virtual host */ second = evhttp_new(NULL); evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL); third = evhttp_new(NULL); evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL); 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); /* 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 (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(); event_debug(("%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 (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; test_ok = 0; http = http_setup(&port, data->base); 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; test_ok = 0; http = http_setup(&port, data->base); 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; event_debug(("%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; test_ok = 0; http = http_setup(&port, data->base); 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; event_debug(("%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; const char *http_request; ev_uint16_t port = 0; test_ok = 0; http = http_setup(&port, data->base); fd = http_connect("127.0.0.1", port); /* 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); evutil_closesocket(fd); evhttp_free(http); tt_int_op(test_ok, ==, 2); end: ; } 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_sec = 3; 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 = 3; /* 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; test_ok = 0; http = http_setup(&port, data->base); /* 2 second timeout */ evhttp_set_timeout(http, 1); evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); 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_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; #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 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; test_ok = 0; base = event_base_new(); http = http_setup(&port, base); fd = http_connect("127.0.0.1", port); /* 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) { 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, 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) { struct bufferevent *bev; evutil_socket_t fd; const char *http_request; ev_uint16_t port = 0; struct timeval tv_start, tv_end; exit_base = data->base; test_ok = 0; http = http_setup(&port, data->base); evhttp_set_timeout(http, 1); fd = http_connect("127.0.0.1", port); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 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); } 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: ; } static void http_incomplete_test(void *arg) { _http_incomplete_test(arg, 0); } static void http_incomplete_timeout_test(void *arg) { _http_incomplete_test(arg, 1); } /* * 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) { if (!test_ok) goto out; test_ok = -1; if ((what & BEV_EVENT_EOF) != 0) { struct evhttp_request *req = evhttp_request_new(NULL, NULL); const char *header; 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; 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; evhttp_request_free(req); } out: 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(void *arg) { struct basic_test_data *data = arg; struct bufferevent *bev; 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; exit_base = data->base; test_ok = 0; http = http_setup(&port, data->base); fd = http_connect("127.0.0.1", port); /* Stupid thing to send a request */ bev = bufferevent_socket_new(data->base, fd, 0); 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); 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 */ evcon = evhttp_connection_base_new(data->base, NULL, "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_stream_out_test(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; test_ok = 0; exit_base = data->base; http = http_setup(&port, data->base); evcon = evhttp_connection_base_new(data->base, NULL, "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_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; exit_base = data->base; http = http_setup(&port, 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; http = http_setup(&port, 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_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(void *arg) { struct basic_test_data *data = arg; ev_uint16_t port = 0; struct evhttp_connection *evcon = NULL; struct evhttp_request *req = NULL; exit_base = data->base; test_ok = 0; /* auto detect a port */ http = http_setup(&port, data->base); evhttp_free(http); http = NULL; /* Pick an unroutable address. This administratively scoped multicast * address should do when working with TCP. */ evcon = evhttp_connection_base_new(data->base, NULL, "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_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); } static struct event_base *http_make_web_server_base=NULL; static void http_make_web_server(evutil_socket_t fd, short what, void *arg) { ev_uint16_t port = *(ev_uint16_t*)arg; http = http_setup(&port, http_make_web_server_base); } static void http_connection_retry_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 timeval tv, tv_start, tv_end; exit_base = data->base; test_ok = 0; /* auto detect a port */ http = http_setup(&port, data->base); evhttp_free(http); http = NULL; evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port); tt_assert(evcon); 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; evhttp_connection_set_timeout(evcon, 1); 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); evutil_timersub(&tv_end, &tv_start, &tv_end); tt_int_op(tv_end.tv_sec, >, 1); tt_int_op(tv_end.tv_sec, <, 6); 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 one second after the connection tried * to send a request */ evutil_timerclear(&tv); tv.tv_sec = 1; http_make_web_server_base = data->base; event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv); 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(tv_end.tv_sec, <, 6); tt_int_op(test_ok, ==, 1); end: if (evcon) evhttp_connection_free(evcon); if (http) evhttp_free(http); } static void http_primitives(void *ptr) { char *escaped = NULL; struct evhttp *http = NULL; escaped = evhttp_htmlescape("