From 5b055ba30d67ae0a9b246683044a6a53448ee45a Mon Sep 17 00:00:00 2001 From: Chris Brody Date: Sat, 12 Apr 2008 18:40:19 +0200 Subject: [PATCH] EvBufferEvent & smtp_buffer_test from eventxx/ioevent.git --- EvBufferEvent.hpp | 108 +++++++++++++++++++++++++++ EvBufferEventInternal.hpp | 124 +++++++++++++++++++++++++++++++ test/smtp_buffer_test.cpp | 183 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100755 EvBufferEvent.hpp create mode 100755 EvBufferEventInternal.hpp create mode 100755 test/smtp_buffer_test.cpp diff --git a/EvBufferEvent.hpp b/EvBufferEvent.hpp new file mode 100755 index 0000000..21565a4 --- /dev/null +++ b/EvBufferEvent.hpp @@ -0,0 +1,108 @@ +#ifndef _EV_BUFFER_EVENT__HPP_ +#define _EV_BUFFER_EVENT__HPP_ + +#include + + +struct EvBufferEvent : EvBufferEventInternal +{ + + /// C read/write callback function used in the C evbuffer API. + typedef void (*readwritecb)(struct bufferevent *, void *); + + /// C error callback function used in the C evbuffer API. + typedef void (*errorcb)(struct bufferevent *, short, void *); + + // TODO: EvBufferEvent(int fd, ...) throw(...) { ... } + + // Future: to be deprecated by EvBufferEvent(int fd, ...) throw(...) + /* public: for now */ + /** + * Constructor to setup callbacks + */ + EvBufferEvent(readwritecb readcb, readwritecb writecb, errorcb errcb, void * arg) + { + _readcb = readcb; + _writecb = writecb; + _errorcb = errcb; + + _arg = arg; + } + + // Future: to be deprecated by EvBufferEvent(...) throw(...) + /* public: for now */ + /** + * Open the bufferevent object with the file/socket descriptor + */ + void open(int fd) /* throw(...) */ + { + (void)_bufferevent_new(fd); + } + + /** + * Open the bufferevent object by accepting a connection on the socket descriptor + */ + void accept(int listen_sock) /* throw(...) */ + { + (void)_bufev_socket_accept(listen_sock); + } + + /* public: */ + + /** + * Write data to the buffer. + * + * @param buf Buffer of data to be written. + * + * @param len Length of data to be written. + * + */ + int write(const void * buf, int len) + { + return _write((char *)buf, len); + } + + /** + * Read data from the buffer. + * + * @param buf Buffer to store data. + * + * @param len Size of buffer to store data. + * + */ + int read(char * buf, int len) + { + return _read(buf, len); + } + + /* protected: */ + /* virtual */ + void _readcb_handler() + { + (*_readcb)(_bufferevent, _arg); + } + + /* virtual */ + void _writecb_handler() + { + (*_writecb)(_bufferevent, _arg); + } + + /* virtual */ + void _errorcb_handler(short what) + { + (*_errorcb)(_bufferevent, what, _arg); + } + + protected: + EvBufferEvent() { } + + /* private: */ + readwritecb _readcb, _writecb; + errorcb _errorcb; + void * _arg; +}; + +#endif // _EV_BUFFER_EVENT__HPP_ + +// vim: set filetype=cpp : diff --git a/EvBufferEventInternal.hpp b/EvBufferEventInternal.hpp new file mode 100755 index 0000000..260bbec --- /dev/null +++ b/EvBufferEventInternal.hpp @@ -0,0 +1,124 @@ +#ifndef _EV_BUFFER_EVENT_INTERNAL__HPP_ +#define _EV_BUFFER_EVENT_INTERNAL__HPP_ + +#include + + +struct EvBufferEventInternal +{ + + /* protected: */ + /** + * Constructor to setup callbacks + */ + EvBufferEventInternal() + { + _bufferevent = NULL; + } + + /* protected: */ + /** + * Open the bufferevent object with the file/socket descriptor + * by calling ::bufferevent_new() + */ + struct bufferevent * _bufferevent_new(int fd) /* throw(...) */ + { + return _bufferevent = + ::bufferevent_new(fd, _readcb_wrapper, _writecb_wrapper, _errorcb_wrapper, + reinterpret_cast< void * >(this)); + } + + /** + * Open the bufferevent object with the listen socket descriptor + * by calling ::bufev_socket_accept() + */ + struct bufferevent * _bufev_socket_accept(int listen_sock) /* throw(...) */ + { + return _bufferevent = + ::bufev_socket_accept(listen_sock, _readcb_wrapper, _writecb_wrapper, _errorcb_wrapper, + reinterpret_cast< void * >(this)); + } + + /* TODO (future): protected: */ + /** + * Enable certain bufferevent callbacks by calling ::bufferevent_enable() + */ + int _enable(short ev) + { + return ::bufferevent_enable(_bufferevent, ev); + } + + /** + * Disable certain bufferevent callbacks by calling ::bufferevent_disable() + */ + int _disable(short ev) + { + return ::bufferevent_disable(_bufferevent, ev); + } + + int _write(char * buf, int len) + { + return ::bufferevent_write(_bufferevent, buf, len); + } + + int _read(char * buf, int len) + { + return ::bufferevent_read(_bufferevent, buf, len); + } + + int _input_length() + { + return EVBUFFER_LENGTH(_bufferevent->input); + } + int _output_length() + { + return EVBUFFER_LENGTH(_bufferevent->output); + } + + /* public: */ + virtual ~EvBufferEventInternal() + { + if (_bufferevent != NULL) + ::bufferevent_free(_bufferevent); + } + + /* protected: */ + struct bufferevent * _bufferevent; + + /* TODO (future): protected: */ + virtual void _readcb_handler() + { /* to be overridden by derived bufferevent class */ } + + virtual void _writecb_handler() + { /* to be overridden by derived bufferevent class */ } + + virtual void _errorcb_handler(short) + { /* to be overridden by derived bufferevent class */ } + + /* TODO (future): private: */ + static void _readcb_wrapper(bufferevent *, void * arg) + { + EvBufferEventInternal * bufferevent_self = reinterpret_cast< EvBufferEventInternal * >(arg); + + bufferevent_self->_readcb_handler(); + } + + static void _writecb_wrapper(bufferevent *, void * arg) + { + EvBufferEventInternal * bufferevent_self = reinterpret_cast< EvBufferEventInternal * >(arg); + + bufferevent_self->_writecb_handler(); + } + + static void _errorcb_wrapper(bufferevent *, short what, void * arg) + { + EvBufferEventInternal * bufferevent_self = reinterpret_cast< EvBufferEventInternal * >(arg); + + bufferevent_self->_errorcb_handler(what); + } + +}; + +#endif // _EV_BUFFER_EVENT_INTERNAL__HPP_ + +// vim: set filetype=cpp : diff --git a/test/smtp_buffer_test.cpp b/test/smtp_buffer_test.cpp new file mode 100755 index 0000000..90092ab --- /dev/null +++ b/test/smtp_buffer_test.cpp @@ -0,0 +1,183 @@ + +#include + +#include + +#include + +#include + +enum { + STATE_INIT = 0, + STATE_DATA +}; + +struct cc { + int state; + + EvBufferEvent * be; + struct bufferevent * bev; + + const char * cur_line; + +}; + +void react_helo(struct cc * c) +{ + bufferevent * bev = c->bev; + evbuffer * b = ::evbuffer_new(); + + const char * line = c->cur_line; + + ::evbuffer_add_printf(b, "250 Hello %s\r\n", line + 5); + ::bufferevent_write_buffer(bev, b); + + ::evbuffer_free(b); +} + +void react_250_ok(struct cc * c) +{ + bufferevent * bev = c->bev; + evbuffer * b = ::evbuffer_new(); + + ::evbuffer_add_printf(b, "250 Ok\r\n"); + ::bufferevent_write_buffer(bev, b); + + ::evbuffer_free(b); +} + +void react_data(struct cc * c) +{ + bufferevent * bev = c->bev; + evbuffer * b = ::evbuffer_new(); + + ::evbuffer_add_printf(b, "354 End data with .\r\n"); + ::bufferevent_write_buffer(bev, b); + + c->state = STATE_DATA; + + ::evbuffer_free(b); +} + +void react_data_line(struct cc * c) +{ + bufferevent * bev = c->bev; + evbuffer * b = ::evbuffer_new(); + + ::evbuffer_add_printf(b, "250 Ok\r\n"); + ::bufferevent_write_buffer(bev, b); + + c->state = STATE_INIT; + + ::evbuffer_free(b); +} + +void react_bye(struct cc * c) +{ + bufferevent * bev = c->bev; + evbuffer * b = ::evbuffer_new(); + + ::evbuffer_add_printf(b, "221 Bye\r\n"); + ::bufferevent_write_buffer(bev, b); + + ::evbuffer_free(b); +} + +void readcb(struct bufferevent *bev, void * v) +{ + char * line; + + struct cc * c = (struct cc *)v; + + while (line = ::evbuffer_readline(bev->input)) + { + c->cur_line = line; + + if (c->state == STATE_INIT) + { + if (!strncmp(line, "HELO ", 5) || + !strncmp(line, "EHLO ", 5)) + { + react_helo(c); + } + else + if (!strncmp(line, "MAIL", 4)) + { + react_250_ok(c); + } + else + if (!strncmp(line, "RCPT", 4)) + { + react_250_ok(c); + } + else + if (!strncmp(line, "DATA", 4)) + { + react_data(c); + } + else + if (!strncmp(line, "QUIT", 4)) + { + react_bye(c); + } + } + else + { + if (strcmp(line, ".")) + { + react_data_line(c); + } + } + + free(line); + c->cur_line = NULL; + } + +} + +void writecb(struct bufferevent *, void *) +{ + +} + +void errorcb(struct bufferevent *, short, void *) +{ + +} + +void accept_handler(int s1, short, void *) +{ + struct cc * c = new cc; + c->state = STATE_INIT; + + EvBufferEvent * be = new EvBufferEvent(readcb, writecb, errorcb, c); + + be->accept(s1); + + c->be = be; + c->bev = be->_bufferevent; + + c->cur_line = NULL; + + evbuffer * b = ::evbuffer_new(); + + ::bufferevent_enable(be->_bufferevent, EV_READ); + + be->write("220 www.example.com ESMTP postfix\r\n", 35); + +} + +main() +{ + ::event_init(); + + int sock = ::bind_socket(NULL, 5525); + + ::bufev_socket_listen(sock, 10); + + ioevent accept_event(sock, EV_READ, &accept_handler, NULL); + ::event_add(&accept_event, NULL); + + ::event_dispatch(); + +} -- 2.11.4.GIT