From 31d89f274bc28655bca3e6aec19b90080cb09add Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 13 May 2009 20:37:21 +0000 Subject: [PATCH] Add a "ctrl" mechanism to bufferevents for property access. OpenSSL uses something like this to implement get/set access for properties on its BIOs, so that it doesn't need to add a pair of get/set functions to the vtable struct for every new abstract property it provides an accessor for. Doing this lets us make bufferevent_setfd abstract, and implement an abstract bufferevent_getfd. svn:r1284 --- ChangeLog | 2 ++ buffer_iocp.c | 6 ++++++ bufferevent-internal.h | 14 +++++++++++++ bufferevent.c | 38 ++++++++++++++++++++++++++++++++++++ bufferevent_async.c | 18 ++++++++++++++++- bufferevent_filter.c | 19 ++++++++++++++++++ bufferevent_pair.c | 1 + bufferevent_sock.c | 27 ++++++++++++++++++++++--- include/event2/bufferevent.h | 15 +++++++++++++- iocp-internal.h | 3 +++ 10 files changed, 138 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index ecbd598d..2f1b28d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,8 @@ Changes in 2.0.2-alpha: o Rename the evbuffercb and everrorcb callbacks to bufferevent_data_cb and bufferevent_event_cb respectively. The old names are available in bufferevent_compat.h. o Rename the EVBUFFER_* codes used by bufferevent event callbacks to BEV_EVENT_*, to avoid namespace collision with evbuffer flags. The old names are available in bufferevent_compat.h. o Move the EVBUFFER_INPUT and EVBUFFER_OUTPUT macros to bufferevent_compat.h + o Add a bufferevent_getfd() function to mirror bufferevent_setfd() + o Make bufferevent_setfd() return an error code if the operation is not successful. Changes in 2.0.1-alpha: o free minheap on event_base_free(); from Christopher Layne diff --git a/buffer_iocp.c b/buffer_iocp.c index 620efd8d..b54d1806 100644 --- a/buffer_iocp.c +++ b/buffer_iocp.c @@ -300,3 +300,9 @@ done: return r; } +evutil_socket_t +_evbuffer_overlapped_get_fd(struct evbuffer *buf) +{ + struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); + return buf_o ? buf_o->fd : -1; +} diff --git a/bufferevent-internal.h b/bufferevent-internal.h index d937db3c..7ea92172 100644 --- a/bufferevent-internal.h +++ b/bufferevent-internal.h @@ -60,6 +60,17 @@ struct bufferevent_private { void *lock; }; +enum bufferevent_ctrl_op { + BEV_CTRL_SET_FD, + BEV_CTRL_GET_FD, + BEV_CTRL_GET_UNDERLYING, +}; + +union bufferevent_ctrl_data { + void *ptr; + evutil_socket_t fd; +}; + /** Implementation table for a bufferevent: holds function pointers and other information to make the various bufferevent types work. @@ -101,6 +112,9 @@ struct bufferevent_ops { /** Called to flush data. */ int (*flush)(struct bufferevent *, short, enum bufferevent_flush_mode); + + /** Called to access miscellaneous fields. */ + int (*ctrl)(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); }; extern const struct bufferevent_ops bufferevent_ops_socket; diff --git a/bufferevent.c b/bufferevent.c index 2d614dae..06386844 100644 --- a/bufferevent.c +++ b/bufferevent.c @@ -531,3 +531,41 @@ bufferevent_enable_locking(struct bufferevent *bufev, void *lock) #endif } +int +bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd) +{ + union bufferevent_ctrl_data d; + int res = -1; + d.fd = fd; + BEV_LOCK(bev); + if (bev->be_ops->ctrl) + res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d); + BEV_UNLOCK(bev); + return res; +} + +evutil_socket_t +bufferevent_getfd(struct bufferevent *bev) +{ + union bufferevent_ctrl_data d; + int res = -1; + d.fd = -1; + BEV_LOCK(bev); + if (bev->be_ops->ctrl) + res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d); + BEV_UNLOCK(bev); + return (res<0) ? -1 : d.fd; +} + +struct bufferevent * +bufferevent_get_underlying(struct bufferevent *bev) +{ + union bufferevent_ctrl_data d; + int res = -1; + d.ptr = NULL; + BEV_LOCK(bev); + if (bev->be_ops->ctrl) + res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d); + BEV_UNLOCK(bev); + return (res<0) ? NULL : d.ptr; +} diff --git a/bufferevent_async.c b/bufferevent_async.c index 6d503979..878a8a0f 100644 --- a/bufferevent_async.c +++ b/bufferevent_async.c @@ -65,6 +65,7 @@ static int be_async_disable(struct bufferevent *, short); static void be_async_destruct(struct bufferevent *); static void be_async_adj_timeouts(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 *); const struct bufferevent_ops bufferevent_ops_async = { "socket_async", @@ -74,9 +75,9 @@ const struct bufferevent_ops bufferevent_ops_async = { be_async_destruct, be_async_adj_timeouts, be_async_flush, + be_async_ctrl, }; - struct bufferevent_async { struct bufferevent_private bev; unsigned read_in_progress : 1; @@ -285,3 +286,18 @@ err: bufferevent_free(&bev_a->bev.bev); return NULL; } + +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: + case BEV_CTRL_GET_UNDERLYING: + default: + return -1; + } +} diff --git a/bufferevent_filter.c b/bufferevent_filter.c index fa7c1f54..3c5a1d4a 100644 --- a/bufferevent_filter.c +++ b/bufferevent_filter.c @@ -70,6 +70,7 @@ static void be_filter_writecb(struct bufferevent *, void *); static void be_filter_errorcb(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); @@ -104,6 +105,7 @@ const struct bufferevent_ops bufferevent_ops_filter = { be_filter_destruct, be_filter_adj_timeouts, be_filter_flush, + be_filter_ctrl, }; /* Given a bufferevent that's really the bev filter of a bufferevent_filtered, @@ -441,3 +443,20 @@ be_filter_flush(struct bufferevent *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: + default: + return -1; + } +} diff --git a/bufferevent_pair.c b/bufferevent_pair.c index 15022662..e6924046 100644 --- a/bufferevent_pair.c +++ b/bufferevent_pair.c @@ -273,4 +273,5 @@ const struct bufferevent_ops bufferevent_ops_pair = { be_pair_destruct, be_pair_adj_timeouts, be_pair_flush, + NULL, /* ctrl */ }; diff --git a/bufferevent_sock.c b/bufferevent_sock.c index dd1ca3fc..d2723739 100644 --- a/bufferevent_sock.c +++ b/bufferevent_sock.c @@ -73,6 +73,9 @@ static int be_socket_disable(struct bufferevent *, short); static void be_socket_destruct(struct bufferevent *); static void 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", @@ -82,6 +85,7 @@ const struct bufferevent_ops bufferevent_ops_socket = { be_socket_destruct, be_socket_adj_timeouts, be_socket_flush, + be_socket_ctrl, }; static int @@ -287,7 +291,7 @@ bufferevent_socket_connect(struct bufferevent *bev, EVUTIL_CLOSESOCKET(fd); return -1; } - bufferevent_setfd(bev, fd); + be_socket_setfd(bev, fd); } if (connect(fd, sa, socklen)<0) { @@ -400,8 +404,8 @@ be_socket_flush(struct bufferevent *bev, short iotype, } -void -bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd) +static void +be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd) { BEV_LOCK(bufev); assert(bufev->be_ops == &bufferevent_ops_socket); @@ -458,3 +462,20 @@ 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: + default: + return -1; + } +} diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h index 228ec9a4..80dcbd9d 100644 --- a/include/event2/bufferevent.h +++ b/include/event2/bufferevent.h @@ -207,11 +207,24 @@ void bufferevent_setcb(struct bufferevent *bufev, /** 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 */ -void bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd); +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. diff --git a/iocp-internal.h b/iocp-internal.h index 1470620d..ac76e848 100644 --- a/iocp-internal.h +++ b/iocp-internal.h @@ -97,6 +97,9 @@ void event_overlapped_init(struct event_overlapped *, iocp_callback cb); */ struct evbuffer *evbuffer_overlapped_new(evutil_socket_t fd); +/** XXXX Document (nickm) */ +evutil_socket_t _evbuffer_overlapped_get_fd(struct evbuffer *buf); + /** Start reading data onto the end of an overlapped evbuffer. An evbuffer can only have one read pending at a time. While the read -- 2.40.0