version 3.0

This commit is contained in:
Bramfeld Team 2015-08-31 14:01:44 +02:00
commit d837490606
209 changed files with 19662 additions and 0 deletions

0
event/Makefile Normal file
View file

91
event/action.h Normal file
View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_ACTION_H
#define EVENT_ACTION_H
////////////////////////////////////////////////////////////////////////////////
// //
// File: action.h //
// Description: basic classes for event callback management //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
class Action
{
protected:
bool cancelled_;
Action () : cancelled_(false)
{
}
public:
virtual ~Action ()
{
ASSERT("/action", cancelled_);
}
virtual void cancel () = 0;
bool is_cancelled ()
{
return cancelled_;
}
};
template<class S, class C> class CallbackAction : public Action
{
typedef void (S::*const method_t)(void);
public:
S* const obj_;
method_t method_;
C* callback_;
public:
CallbackAction (S* obj, method_t method, C* cb) : obj_(obj), method_(method)
{
ASSERT("/action", obj && method);
callback_ = cb;
}
~CallbackAction()
{
delete callback_;
}
virtual void cancel ()
{
cancelled_ = true;
(obj_->*method_) ();
}
};
#endif /* !EVENT_ACTION_H */

46
event/callback.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2008-2012 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_CALLBACK_H
#define EVENT_CALLBACK_H
////////////////////////////////////////////////////////////////////////////////
// //
// File: callback.h //
// Description: base class for event callback specializations //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
class Callback
{
public:
virtual ~Callback () {}
virtual void execute () = 0;
};
#endif /* !EVENT_CALLBACK_H */

150
event/callback_queue.h Normal file
View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2010-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_CALLBACK_QUEUE_H
#define EVENT_CALLBACK_QUEUE_H
#include <deque>
#include <event/callback.h>
#include <event/action.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: callback_queue.h //
// Description: collection classes for event callback management //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
class CallbackQueue
{
class QueuedAction : public Action
{
CallbackQueue& queue_;
uint64_t generation_;
Callback* callback_;
public:
QueuedAction (CallbackQueue& q, uint64_t g, Callback* cb)
: queue_(q),
generation_(g),
callback_(cb)
{
}
~QueuedAction ()
{
delete callback_;
}
virtual void cancel ()
{
cancelled_ = true;
queue_.cancel (this);
}
friend class CallbackQueue;
};
std::deque<QueuedAction*> queue_;
uint64_t generation_;
public:
CallbackQueue ()
: queue_(),
generation_(0)
{ }
~CallbackQueue ()
{
std::deque<QueuedAction*>::iterator it;
for (it = queue_.begin (); it != queue_.end (); ++it)
{
delete *it;
*it = 0;
}
}
Action* schedule (Callback* cb)
{
QueuedAction* a = new QueuedAction (*this, generation_, cb);
queue_.push_back (a);
return (a);
}
/*
* Runs all callbacks that have already been queued, but none that
* are added by callbacks that are called as part of the drain
* operation. Returns true if there are queued callbacks that were
* added during drain.
*/
bool drain (void)
{
generation_++;
while (! queue_.empty ())
{
QueuedAction* a = queue_.front ();
if (a->generation_ >= generation_)
return (true);
queue_.pop_front ();
if (a->callback_)
a->callback_->execute ();
}
return (false);
}
bool empty () const
{
return (queue_.empty ());
}
void perform ()
{
if (! queue_.empty ())
{
QueuedAction* a = queue_.front ();
if (a->callback_)
a->callback_->execute ();
}
}
void cancel (QueuedAction* a)
{
std::deque<QueuedAction*>::iterator it;
for (it = queue_.begin (); it != queue_.end (); ++it)
{
if (*it == a)
{
queue_.erase (it);
break;
}
}
delete a;
}
};
#endif /* !EVENT_CALLBACK_QUEUE_H */

136
event/event.h Normal file
View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2008-2012 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_EVENT_H
#define EVENT_EVENT_H
#include <common/buffer.h>
/*
* The general-purpose event type. Never extended or anything like that.
* Tracking a user-specified pointer is handled by the callback, providers of
* Events can pass extra data by extending their Callback type, e.g. the
* SocketEventCallback used by Socket::accept() to pass back a Socket pointer
* along with an Event.
* XXX In light of this extension, it may make sense to move the Buffer out
* of Event now, since the Callback can handle Buffers independently.
*
* Because we are primarily a data-movement/processing system, a Buffer is an
* integral part of every Event. Plus, Buffers with no data are basically
* free to copy, etc.
*
* Event handlers/callbacks always take a copy of the Event, which is subpar
* but necessary since the first thing most of those callbacks do is to cancel
* the Action that called them, which in turn deletes the underlying SimpleCallback
* object, which would in turn delete the holder of the associated Event if a
* reference or pointer were passed. One can argue that the right thing to do
* is process the event fully before cancelling the Action, but that is not
* how things are done at present.
*/
struct Event {
enum Type {
Invalid,
Done,
EOS,
Error,
};
Type type_;
int error_;
Buffer buffer_;
Event(void)
: type_(Event::Invalid),
error_(0),
buffer_()
{ }
Event(Type type)
: type_(type),
error_(0),
buffer_()
{ }
Event(Type type, int error)
: type_(type),
error_(error),
buffer_()
{ }
Event(Type type, const Buffer& buffer)
: type_(type),
error_(0),
buffer_(buffer)
{ }
Event(Type type, int error, const Buffer& buffer)
: type_(type),
error_(error),
buffer_(buffer)
{ }
Event(const Event& e)
: type_(e.type_),
error_(e.error_),
buffer_(e.buffer_)
{ }
Event& operator= (const Event& e)
{
type_ = e.type_;
error_ = e.error_;
buffer_ = e.buffer_;
return (*this);
}
};
static inline std::ostream&
operator<< (std::ostream& os, Event::Type type)
{
switch (type) {
case Event::Invalid:
return (os << "<Invalid>");
case Event::Done:
return (os << "<Done>");
case Event::EOS:
return (os << "<EOS>");
case Event::Error:
return (os << "<Error>");
default:
return (os << "<Unexpected Event::Type>");
}
}
static inline std::ostream&
operator<< (std::ostream& os, Event e)
{
if (e.type_ != Event::Error && e.error_ == 0)
return (os << e.type_);
return (os << e.type_ << '/' << e.error_ << " [" <<
strerror(e.error_) << "]");
}
#endif /* !EVENT_EVENT_H */

34
event/event_callback.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_EVENT_CALLBACK_H
#define EVENT_EVENT_CALLBACK_H
#include <event/event.h>
#include <event/typed_callback.h>
typedef class TypedCallback<Event> EventCallback;
#endif /* !EVENT_EVENT_CALLBACK_H */

22
event/event_message.h Normal file
View file

@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_message.h //
// Description: sructures for data exchange in shared buffers //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#ifndef EVENT_EVENT_MESSAGE_H
#define EVENT_EVENT_MESSAGE_H
class EventAction;
struct EventMessage
{
int op;
EventAction* action;
};
#endif /* !EVENT_EVENT_MESSAGE_H */

152
event/event_poll_epoll.cc Normal file
View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2009-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <sys/types.h>
#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <event/event_system.h>
#include <event/io_service.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_poll_epoll.cc //
// Description: IO event handling using Linux epoll functions //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
void IoService::open_resources ()
{
handle_ = ::epoll_create (IO_POLL_EVENT_COUNT);
ASSERT(log_, handle_ != -1);
}
void IoService::close_resources ()
{
if (handle_ >= 0)
::close (handle_);
}
void IoService::set_fd (int fd, int rd, int wr, IoNode* node)
{
struct epoll_event eev;
int rv;
eev.events = ((rd > 0 ? EPOLLIN : 0) | (wr > 0 ? EPOLLOUT : 0));
eev.data.ptr = node;
if (eev.events)
rv = ::epoll_ctl (handle_, (rd && wr ? EPOLL_CTL_MOD : EPOLL_CTL_ADD), fd, &eev);
else
rv = ::epoll_ctl (handle_, EPOLL_CTL_DEL, fd, &eev);
if (rv < 0 && errno != EEXIST && errno != ENOENT)
CRITICAL(log_) << "Could not add event to epoll.";
}
void IoService::poll (int ms)
{
struct epoll_event eev[IO_POLL_EVENT_COUNT];
int evcnt;
evcnt = ::epoll_wait (handle_, eev, IO_POLL_EVENT_COUNT, ms);
if (evcnt < 0 && errno != EINTR)
CRITICAL(log_) << "Could not poll epoll.";
for (int i = 0; i < evcnt; ++i)
{
int flg = eev[i].events;
IoNode* node = (IoNode*) eev[i].data.ptr;
EventAction* act;
Event ok;
if ((flg & EPOLLIN))
{
if (node && (act = node->read_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeAccept && (ev.type_ = Event::Done)) || read_channel (node->fd, ev, 1))
{
schedule (act);
node->reading = false;
set_fd (node->fd, -1, (node->writing ? 2 : 0), node);
}
}
else if (node)
read_channel (node->fd, ok, 0);
}
if ((flg & EPOLLOUT))
{
if (node && (act = node->write_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeConnect && (ev.type_ = Event::Done)) ||
(act->mode_ == StreamModeWrite && write_channel (node->fd, ev)) ||
(act->mode_ == StreamModeEnd && close_channel (node->fd, ev)))
{
schedule (act);
node->writing = false;
set_fd (node->fd, (node->reading ? 2 : 0), -1, node);
}
}
}
if (! (flg & (EPOLLIN | EPOLLOUT)))
{
if ((flg & EPOLLERR))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->reading = false;
set_fd (node->fd, -1, 0, node);
}
if (node && (act = node->write_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->writing = false;
set_fd (node->fd, 0, -1, node);
}
}
else if ((flg & EPOLLHUP))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::EOS;
schedule (act);
node->reading = false;
set_fd (node->fd, -1, (node->writing ? 2 : 0), node);
}
}
}
}
}

159
event/event_poll_kqueue.cc Normal file
View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <sys/types.h>
#include <sys/errno.h>
#include <sys/event.h>
#include <sys/time.h>
#include <unistd.h>
#include <event/event_system.h>
#include <event/io_service.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_poll_kqueue.cc //
// Description: IO event handling using FreeBSD kevent functions //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
void IoService::open_resources ()
{
handle_ = kqueue ();
ASSERT(log_, handle_ != -1);
}
void IoService::close_resources ()
{
if (handle_ >= 0)
::close (handle_);
}
void IoService::set_fd (int fd, int rd, int wr, IoNode* node)
{
struct kevent kev;
int rv;
if (rd == 1)
EV_SET (&kev, fd, EVFILT_READ, EV_ADD, 0, 0, node);
else if (wr == 1)
EV_SET (&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, node);
else if (rd == -1)
EV_SET (&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, node);
else if (wr == -1)
EV_SET (&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, node);
rv = ::kevent (handle_, &kev, 1, 0, 0, 0);
if (rv < 0 && errno != EEXIST && errno != ENOENT)
CRITICAL(log_) << "Could not add event to kqueue.";
}
void IoService::poll (int ms)
{
struct kevent kev[IO_POLL_EVENT_COUNT];
struct timespec ts;
int evcnt;
if (ms != -1)
{
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
}
evcnt = ::kevent (handle_, 0, 0, kev, IO_POLL_EVENT_COUNT, (ms == -1 ? 0 : &ts));
if (evcnt < 0 && errno != EINTR)
CRITICAL(log_) << "Could not poll kqueue.";
for (int i = 0; i < evcnt; i++)
{
int sck = kev[i].ident;
int flt = kev[i].filter;
int flg = kev[i].flags;
IoNode* node = (IoNode*) kev[i].udata;
EventAction* act;
Event ok;
if ((flg & EV_ERROR))
{
if (flt == EVFILT_READ && node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->reading = false;
set_fd (sck, -1, (node->writing ? 2 : 0), node);
}
else if (flt == EVFILT_WRITE && node && (act = node->write_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->writing = false;
set_fd (sck, (node->reading ? 2 : 0), -1, node);
}
}
else if ((flg & EV_EOF))
{
if (flt == EVFILT_READ && node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::EOS;
schedule (act);
node->reading = false;
set_fd (sck, -1, (node->writing ? 2 : 0), node);
}
}
else if ((flt == EVFILT_READ))
{
if (node && (act = node->read_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeAccept && (ev.type_ = Event::Done)) || read_channel (sck, ev, 1))
{
schedule (act);
node->reading = false;
set_fd (sck, -1, (node->writing ? 2 : 0), node);
}
}
else if (node)
read_channel (sck, ok, 0);
}
else if ((flt == EVFILT_WRITE))
{
if (node && (act = node->write_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeConnect && (ev.type_ = Event::Done)) ||
(act->mode_ == StreamModeWrite && write_channel (sck, ev)) ||
(act->mode_ == StreamModeEnd && close_channel (sck, ev)))
{
schedule (act);
node->writing = false;
set_fd (sck, (node->reading ? 2 : 0), -1, node);
}
}
}
}
}

157
event/event_poll_poll.cc Normal file
View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <sys/errno.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <event/event_system.h>
#include <event/io_service.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_poll_poll.cc //
// Description: IO event handling using standard poll functions //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
void IoService::open_resources ()
{
}
void IoService::close_resources ()
{
}
void IoService::set_fd (int fd, int rd, int wr, IoNode* node)
{
}
void IoService::poll (int ms)
{
struct pollfd fds[fd_map_.size () + 1];
int i, j, f;
int cnt;
fds[0].fd = rfd_;
fds[0].events = POLLIN;
fds[0].revents = 0;
j = 1;
std::map<int, IoNode>::iterator it;
for (it = fd_map_.begin (); it != fd_map_.end (); ++it)
{
if ((f = (it->second.reading ? POLLIN : 0) | (it->second.writing ? POLLOUT : 0)))
{
fds[j].fd = it->first;
fds[j].events = f;
fds[j].revents = 0;
++j;
}
}
cnt = ::poll (fds, j, ms);
if (cnt < 0 && errno != EINTR)
CRITICAL(log_) << "Could not poll.";
for (i = 0; i < j; ++i)
{
if (fds[i].revents == 0)
continue;
if (cnt-- == 0)
break;
int sck = fds[i].fd;
int flg = fds[i].revents;
it = fd_map_.find (sck);
IoNode* node = (it != fd_map_.end () ? &it->second : 0);
EventAction* act;
Event ok;
if ((flg & POLLIN))
{
if (node && (act = node->read_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeAccept && (ev.type_ = Event::Done)) || read_channel (sck, ev, 1))
{
schedule (act);
node->reading = false;
}
}
else if (node)
read_channel (sck, ok, 0);
}
if ((flg & POLLOUT))
{
if (node && (act = node->write_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeConnect && (ev.type_ = Event::Done)) ||
(act->mode_ == StreamModeWrite && write_channel (sck, ev)) ||
(act->mode_ == StreamModeEnd && close_channel (sck, ev)))
{
schedule (act);
node->writing = false;
}
}
}
if (! (flg & (POLLIN | POLLOUT)))
{
if ((flg & (POLLERR | POLLNVAL)))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->reading = false;
}
if (node && (act = node->write_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->writing = false;
}
}
else if ((flg & POLLHUP))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::EOS;
schedule (act);
node->reading = false;
}
}
}
}
}

174
event/event_poll_port.cc Normal file
View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2009-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <sys/types.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <errno.h>
#include <poll.h>
#include <port.h>
#include <unistd.h>
#include <event/event_system.h>
#include <event/io_service.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_poll_port.cc //
// Description: IO event handling using SunOS port functions //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
void IoService::open_resources ()
{
handle_ = port_create ();
ASSERT(log_, handle_ != -1);
}
void IoService::close_resources ()
{
if (handle_ >= 0)
::close (handle_);
}
void IoService::set_fd (int fd, int rd, int wr, IoNode* node)
{
int events;
int rv;
events = ((rd > 0 ? EPOLLIN : 0) | (wr > 0 ? EPOLLOUT : 0));
if (events)
{
rv = ::port_associate (handle_, PORT_SOURCE_FD, fd, events, node);
if (rv < 0 && errno != EEXIST)
CRITICAL(log_) << "Could not add event to port.";
}
else
{
rv = ::port_dissociate (handle_, PORT_SOURCE_FD, fd);
if (rv < 0 && errno != ENOENT)
CRITICAL(log_) << "Could not add event to port.";
}
}
void IoService::poll (int ms)
{
port_event_t pev[IO_POLL_EVENT_COUNT];
unsigned int evcnt = 1;
struct timespec ts;
int rv;
if (ms != -1)
{
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
}
rv = ::port_getn (handle_, pev, IO_POLL_EVENT_COUNT, &evcnt, (ms == -1 ? 0 : &ts));
if (rv < 0)
{
if (errno != EINTR)
CRITICAL(log_) << "Could not poll port.";
evcnt = 0;
}
for (unsigned int i = 0; i < evcnt; ++i)
{
int sck = pev[i].portev_object;
int flg = pev[i].portev_events;
IoNode* node = (IoNode*) pev[i].portev_user;
EventAction* act;
Event ok;
if ((flg & POLLIN))
{
if (node && (act = node->read_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeAccept && (ev.type_ = Event::Done)) || read_channel (sck, ev, 1))
{
schedule (act);
node->reading = false;
}
else
set_fd (sck, 1, (node->writing ? 2 : 0), node);
}
else if (node)
{
read_channel (sck, ok, 0);
set_fd (sck, 1, (node->writing ? 2 : 0), node);
}
}
if ((flg & POLLOUT))
{
if (node && (act = node->write_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeConnect && (ev.type_ = Event::Done)) ||
(act->mode_ == StreamModeWrite && write_channel (sck, ev)) ||
(act->mode_ == StreamModeEnd && close_channel (sck, ev)))
{
schedule (act);
node->writing = false;
}
else
set_fd (sck, (node->reading ? 2 : 0), 1, node);
}
}
if (! (flg & (POLLIN | POLLOUT)))
{
if ((flg & POLLERR))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->reading = false;
}
if (node && (act = node->write_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::Error;
schedule (act);
node->writing = false;
}
}
else if ((flg & POLLHUP))
{
if (node && (act = node->read_action))
{
if (act->callback_)
act->callback_->param ().type_ = Event::EOS;
schedule (act);
node->reading = false;
}
}
}
}
}

138
event/event_poll_select.cc Normal file
View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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 <sys/errno.h>
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
#include <event/event_system.h>
#include <event/io_service.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_poll_select.cc //
// Description: IO event handling using traditional select calls //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
void IoService::open_resources ()
{
}
void IoService::close_resources ()
{
}
void IoService::set_fd (int fd, int rd, int wr, IoNode* node)
{
}
void IoService::poll (int ms)
{
fd_set read_set, write_set;
struct timeval tv;
int maxfd;
int fdcnt;
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_SET(rfd_, &read_set);
maxfd = rfd_;
std::map<int, IoNode>::iterator it;
for (it = fd_map_.begin (); it != fd_map_.end (); ++it)
{
if (it->second.reading)
FD_SET (it->first, &read_set);
if (it->second.writing)
FD_SET (it->first, &write_set);
if (maxfd < it->first)
maxfd = it->first;
}
ASSERT(log_, maxfd != -1);
if (ms != -1)
{
tv.tv_sec = ms / 1000;
tv.tv_usec = ms % 1000;
}
fdcnt = ::select (maxfd + 1, &read_set, &write_set, 0, (ms == -1 ? 0 : &tv));
if (fdcnt < 0 && errno != EINTR)
CRITICAL(log_) << "Could not poll select.";
for (int sck = 0; sck <= maxfd && fdcnt > 0; ++sck)
{
if (FD_ISSET (sck, &read_set))
{
it = fd_map_.find (sck);
IoNode* node = (it != fd_map_.end () ? &it->second : 0);
EventAction* act;
Event ok;
if (node && (act = node->read_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeAccept && (ev.type_ = Event::Done)) || read_channel (sck, ev, 1))
{
schedule (act);
node->reading = false;
}
}
else if (node)
read_channel (sck, ok, 0);
ASSERT(log_, fdcnt > 0);
fdcnt--;
}
if (FD_ISSET (sck, &write_set))
{
it = fd_map_.find (sck);
IoNode* node = (it != fd_map_.end () ? &it->second : 0);
EventAction* act;
Event ok;
if (node && (act = node->write_action))
{
Event& ev = (act->callback_ ? act->callback_->param () : ok);
if ((act->mode_ == StreamModeConnect && (ev.type_ = Event::Done)) ||
(act->mode_ == StreamModeWrite && write_channel (sck, ev)) ||
(act->mode_ == StreamModeEnd && close_channel (sck, ev)))
{
schedule (act);
node->writing = false;
}
}
ASSERT(log_, fdcnt > 0);
fdcnt--;
}
}
}

133
event/event_system.cc Normal file
View file

@ -0,0 +1,133 @@
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_system.cc //
// Description: global event handling core class implementation //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#include <event/event_system.h>
namespace
{
static void signal_reload (int) { event_system.reload (); }
static void signal_stop (int) { event_system.stop (); }
}
EventSystem::EventSystem () : log_ ("/event/system"), reload_ (false), stop_ (false)
{
::signal (SIGHUP, signal_reload);
::signal (SIGINT, signal_stop);
::signal (SIGPIPE, SIG_IGN);
struct rlimit rlim;
int rv = ::getrlimit (RLIMIT_NOFILE, &rlim);
if (rv == 0 && rlim.rlim_cur < rlim.rlim_max)
{
rlim.rlim_cur = rlim.rlim_max;
rv = ::setrlimit (RLIMIT_NOFILE, &rlim);
}
}
void EventSystem::run ()
{
EventMessage msg;
INFO(log_) << "Starting event system.";
io_service_.start ();
while (1)
{
if (gateway_.read (msg))
{
if (msg.op >= 0)
{
if (msg.action && ! msg.action->is_cancelled ())
{
if (msg.action->callback_)
msg.action->callback_->execute ();
else
msg.action->cancel ();
}
}
else
{
delete msg.action;
}
}
if (reload_)
{
if (! interest_queue_[EventInterestReload].empty ())
{
INFO(log_) << "Running reload handlers.";
interest_queue_[EventInterestReload].drain ();
INFO(log_) << "Reload handlers have been run.";
}
reload_ = false;
::signal (SIGHUP, signal_reload);
}
if (stop_)
{
if (! interest_queue_[EventInterestStop].empty ())
{
INFO(log_) << "Running stop handlers.";
interest_queue_[EventInterestStop].drain ();
INFO(log_) << "Stop handlers have been run.";
}
break;
}
}
io_service_.stop ();
}
void EventSystem::reload ()
{
::signal (SIGHUP, SIG_IGN);
reload_ = true;
gateway_.wakeup ();
}
void EventSystem::stop ()
{
::signal (SIGINT, SIG_IGN);
stop_ = true;
gateway_.wakeup ();
}
Action* EventSystem::register_interest (EventInterest interest, Callback* cb)
{
return interest_queue_[interest].schedule (cb);
}
Action* EventSystem::track (int fd, StreamMode mode, EventCallback* cb)
{
EventAction* act;
if ((act = new EventAction (*this, fd, mode, cb)))
{
EventMessage msg = {1, act};
io_service_.take_message (msg);
}
return (cb ? act : 0);
}
void EventSystem::cancel (EventAction* act)
{
if (act)
{
EventMessage msg = {-1, act};
io_service_.take_message (msg);
}
}
EventSystem event_system;

92
event/event_system.h Normal file
View file

@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////////
// //
// File: event_system.h //
// Description: global event handling core class definition //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#ifndef EVENT_EVENT_SYSTEM_H
#define EVENT_EVENT_SYSTEM_H
#include <common/buffer.h>
#include <common/ring_buffer.h>
#include <event/action.h>
#include <event/event_callback.h>
#include <event/object_callback.h>
#include <event/callback_queue.h>
#include <event/event_message.h>
#include <event/io_service.h>
class EventAction;
enum EventInterest
{
EventInterestReload,
EventInterestStop,
EventInterests
};
enum StreamMode
{
StreamModeConnect,
StreamModeAccept,
StreamModeRead,
StreamModeWrite,
StreamModeEnd
};
class EventSystem
{
private:
LogHandle log_;
IoService io_service_;
WaitBuffer<EventMessage> gateway_;
CallbackQueue interest_queue_[EventInterests];
bool reload_, stop_;
public:
EventSystem ();
void run ();
void reload ();
void stop ();
Action* register_interest (EventInterest interest, Callback* cb);
Action* track (int fd, StreamMode mode, EventCallback* cb);
void cancel (EventAction* act);
int take_message (const EventMessage& msg) { return gateway_.write (msg); }
};
class EventAction : public Action
{
public:
EventSystem& system_;
int fd_;
StreamMode mode_;
EventCallback* callback_;
public:
EventAction (EventSystem& sys, int fd, StreamMode mode, EventCallback* cb) : system_ (sys)
{
fd_ = fd; mode_ = mode; callback_ = cb;
}
~EventAction ()
{
delete callback_;
}
virtual void cancel ()
{
cancelled_ = true;
system_.cancel (this);
}
};
extern EventSystem event_system;
#endif /* !EVENT_EVENT_SYSTEM_H */

329
event/io_service.cc Normal file
View file

@ -0,0 +1,329 @@
////////////////////////////////////////////////////////////////////////////////
// //
// File: io_service.h //
// Description: servicing of network IO requests for the event system //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#include <unistd.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <limits.h>
#include <event/event_system.h>
#include <event/io_service.h>
IoService::IoService () : Thread ("IoService"), log_ ("/io/thread")
{
handle_ = rfd_ = wfd_ = -1;
int fd[2];
if (::pipe (fd) == 0)
rfd_ = fd[0], wfd_ = fd[1];
}
IoService::~IoService ()
{
if (rfd_ >= 0)
::close (rfd_);
if (wfd_ >= 0)
::close (wfd_);
}
void IoService::main ()
{
EventMessage msg;
INFO(log_) << "Starting IO thread.";
open_resources ();
IoNode node = {rfd_, true, false, 0, 0};
set_fd (rfd_, 1, 0, &node);
while (! stop_)
{
while (gateway_.read (msg))
{
if (msg.op >= 0)
handle_request (msg.action);
else
cancel (msg.action);
}
poll (-1);
}
set_fd (rfd_, -1, 0);
close_resources ();
}
void IoService::stop ()
{
stop_ = true;
wakeup ();
Thread::stop ();
}
void IoService::handle_request (EventAction* act)
{
Event ev;
if (act)
{
switch (act->mode_)
{
case StreamModeConnect:
if (connect_channel (act->fd_, (act->callback_ ? act->callback_->param () : ev)))
schedule (act);
else
track (act);
return;
case StreamModeAccept:
track (act);
return;
case StreamModeRead:
if (read_channel (act->fd_, (act->callback_ ? act->callback_->param () : ev), 1))
schedule (act);
else
track (act);
return;
case StreamModeWrite:
if (write_channel (act->fd_, (act->callback_ ? act->callback_->param () : ev)))
schedule (act);
else
track (act);
return;
case StreamModeEnd:
if (close_channel (act->fd_, (act->callback_ ? act->callback_->param () : ev)))
schedule (act);
else
track (act);
return;
}
}
}
bool IoService::connect_channel (int fd, Event& ev)
{
struct sockaddr adr;
int n = 0;
if (ev.buffer_.length () <= sizeof adr)
ev.buffer_.copyout ((uint8_t*) &adr, (n = ev.buffer_.length ()));
int rv = ::connect (fd, &adr, n);
switch (rv)
{
case 0:
ev.type_ = Event::Done;
break;
case -1:
switch (errno)
{
case EINPROGRESS:
return false;
default:
ev.type_ = Event::Error;
ev.error_ = errno;
break;
}
break;
}
return true;
}
bool IoService::read_channel (int fd, Event& ev, int flg)
{
ssize_t len;
len = ::read (fd, read_pool_, sizeof read_pool_);
if (len < 0)
{
switch (errno)
{
case EAGAIN:
return false;
default:
ev.type_ = Event::Error;
ev.error_ = errno;
break;
}
}
else if (len == 0)
{
ev.type_ = Event::EOS;
}
else if (flg & 1)
{
ev.type_ = Event::Done;
ev.buffer_.append (read_pool_, len);
}
return true;
}
bool IoService::write_channel (int fd, Event& ev)
{
struct iovec iov[IOV_MAX];
size_t iovcnt;
ssize_t len;
if (ev.buffer_.empty ())
{
ev.type_ = Event::Done;
}
else
{
iovcnt = ev.buffer_.fill_iovec (iov, IOV_MAX);
len = ::writev (fd, iov, iovcnt);
if (len < 0)
{
switch (errno)
{
case EAGAIN:
return false;
default:
ev.type_ = Event::Error;
ev.error_ = errno;
break;
}
}
else if ((size_t) len < ev.buffer_.length ())
{
ev.buffer_.skip (len);
return false;
}
else
{
ev.type_ = Event::Done;
}
}
return true;
}
bool IoService::close_channel (int fd, Event& ev)
{
int rv = ::close (fd);
if (rv == -1 && errno == EAGAIN)
return false;
ev.type_ = Event::Done;
return true;
}
void IoService::track (EventAction* act)
{
std::map<int, IoNode>::iterator it;
int fd;
if (act)
{
fd = act->fd_;
it = fd_map_.find (fd);
switch (act->mode_)
{
case StreamModeAccept:
case StreamModeRead:
if (it == fd_map_.end ())
{
IoNode node = {fd, true, false, act, 0};
set_fd (fd, 1, 0, &(fd_map_[fd] = node));
}
else if (act->mode_ == StreamModeRead)
{
it->second.reading = true, it->second.read_action = act;
set_fd (fd, 1, (it->second.writing ? 2 : 0), &it->second);
}
else
{
if (act->callback_) act->callback_->param ().type_ = Event::Error;
schedule (act);
}
break;
case StreamModeConnect:
case StreamModeWrite:
case StreamModeEnd:
if (it == fd_map_.end ())
{
IoNode node = {fd, false, true, 0, act};
set_fd (fd, 0, 1, &(fd_map_[fd] = node));
}
else if (act->mode_ == StreamModeWrite)
{
it->second.writing = true, it->second.write_action = act;
set_fd (fd, (it->second.reading ? 2 : 0), 1, &it->second);
}
else
{
if (act->callback_) act->callback_->param ().type_ = Event::Error;
schedule (act);
}
break;
}
}
}
void IoService::cancel (EventAction* act)
{
std::map<int, IoNode>::iterator it;
int fd;
if (act)
{
fd = act->fd_;
it = fd_map_.find (fd);
switch (act->mode_)
{
case StreamModeAccept:
case StreamModeRead:
if (it != fd_map_.end () && it->second.read_action == act)
{
it->second.reading = false, it->second.read_action = 0;
if (it->second.write_action == 0)
fd_map_.erase (it);
set_fd (fd, -1, (it->second.writing ? 2 : 0), &it->second);
}
break;
case StreamModeConnect:
case StreamModeWrite:
case StreamModeEnd:
if (it != fd_map_.end () && it->second.write_action == act)
{
it->second.writing = false, it->second.write_action = 0;
if (it->second.read_action == 0)
fd_map_.erase (it);
set_fd (fd, (it->second.reading ? 2 : 0), -1, &it->second);
}
break;
}
terminate (act);
}
}
void IoService::schedule (EventAction* act)
{
EventMessage msg = {1, act};
event_system.take_message (msg);
}
void IoService::terminate (EventAction* act)
{
EventMessage msg = {-1, act};
event_system.take_message (msg);
}

73
event/io_service.h Normal file
View file

@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////////////////////////
// //
// File: io_service.h //
// Description: servicing of network IO requests for the event system //
// Project: WANProxy XTech //
// Author: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
#ifndef EVENT_IO_SERVICE_H
#define EVENT_IO_SERVICE_H
#include <unistd.h>
#include <map>
#include <common/buffer.h>
#include <common/ring_buffer.h>
#include <common/thread/thread.h>
#include <event/action.h>
#include <event/event_callback.h>
#include <event/event_message.h>
#define IO_READ_BUFFER_SIZE 0x10000
#define IO_POLL_EVENT_COUNT 512
struct IoNode
{
int fd;
bool reading;
bool writing;
EventAction* read_action;
EventAction* write_action;
};
class IoService : public Thread
{
private:
LogHandle log_;
RingBuffer<EventMessage> gateway_;
uint8_t read_pool_[IO_READ_BUFFER_SIZE];
std::map<int, IoNode> fd_map_;
int handle_, rfd_, wfd_;
public:
IoService ();
virtual ~IoService ();
virtual void main ();
virtual void stop ();
private:
void handle_request (EventAction* act);
bool connect_channel (int fd, Event& ev);
bool read_channel (int fd, Event& ev, int flg);
bool write_channel (int fd, Event& ev);
bool close_channel (int fd, Event& ev);
void track (EventAction* act);
void cancel (EventAction* act);
void schedule (EventAction* act);
void terminate (EventAction* act);
void open_resources ();
void close_resources ();
void set_fd (int fd, int rd, int wr, IoNode* node = 0);
void poll (int ms);
public:
bool idle () const { return fd_map_.empty (); }
void wakeup () { ::write (wfd_, "*", 1); }
void take_message (const EventMessage& msg) { gateway_.write (msg); wakeup (); }
};
#endif /* !EVENT_IO_SERVICE_H */

41
event/lib.mk Normal file
View file

@ -0,0 +1,41 @@
VPATH+= ${TOPDIR}/event
SRCS+= event_system.cc
SRCS+= io_service.cc
ifndef USE_POLL
ifeq "${OSNAME}" "Darwin"
USE_POLL= kqueue
endif
ifeq "${OSNAME}" "FreeBSD"
USE_POLL= kqueue
endif
ifeq "${OSNAME}" "OpenBSD"
USE_POLL= kqueue
endif
ifeq "${OSNAME}" "Linux"
USE_POLL= epoll
endif
ifeq "${OSNAME}" "Interix"
USE_POLL= select
endif
ifeq "${OSNAME}" "SunOS"
USE_POLL= port
endif
ifndef USE_POLL
USE_POLL= poll
endif
endif
ifeq "${OSNAME}" "Linux"
# Required for clock_gettime(3).
LDADD+= -lrt
endif
SRCS+= event_poll_${USE_POLL}.cc

107
event/object_callback.h Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2008-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_OBJECT_CALLBACK_H
#define EVENT_OBJECT_CALLBACK_H
#include <event/callback.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: object_callback.h //
// Description: template classes for event callback handling //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
template<class C>
class ObjectMethodCallback : public Callback {
public:
typedef void (C::*const method_t)(void);
private:
C *const obj_;
method_t method_;
public:
template<typename T>
ObjectMethodCallback(C *obj, T method)
: Callback(),
obj_(obj),
method_(method)
{ }
~ObjectMethodCallback()
{ }
virtual void execute ()
{
(obj_->*method_)();
}
};
template<class C, typename A>
class ObjectMethodArgCallback : public Callback {
public:
typedef void (C::*const method_t)(A);
private:
C *const obj_;
method_t method_;
A arg_;
public:
template<typename Tm>
ObjectMethodArgCallback(C *obj, Tm method, A arg)
: Callback(),
obj_(obj),
method_(method),
arg_(arg)
{ }
~ObjectMethodArgCallback()
{ }
virtual void execute ()
{
(obj_->*method_)(arg_);
}
};
template<class C>
Callback *callback(C *obj, typename ObjectMethodCallback<C>::method_t method)
{
Callback *cb = new ObjectMethodCallback<C>(obj, method);
return (cb);
}
template<class C, typename A>
Callback *callback(C *obj, void (C::*const method)(A), A arg)
{
Callback *cb = new ObjectMethodArgCallback<C, A>(obj, method, arg);
return (cb);
}
#endif /* !EVENT_OBJECT_CALLBACK_H */

138
event/typed_callback.h Normal file
View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2010-2012 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_TYPED_CALLBACK_H
#define EVENT_TYPED_CALLBACK_H
#include <event/callback.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: typed_callback.h //
// Description: template classes for event callback handling //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
template<typename T>
class TypedCallback : public Callback {
protected:
T param_;
protected:
TypedCallback()
: Callback(),
param_()
{ }
public:
virtual ~TypedCallback()
{ }
void param(T p)
{
param_ = p;
}
T& param()
{
return param_;
}
void reset(void)
{
param_ = T();
}
};
template<typename T, class C>
class ObjectTypedCallback : public TypedCallback<T> {
public:
typedef void (C::*const method_t)(T);
private:
C *const obj_;
method_t method_;
public:
template<typename Tm>
ObjectTypedCallback(C *obj, Tm method)
: TypedCallback<T>(),
obj_(obj),
method_(method)
{ }
~ObjectTypedCallback()
{ }
virtual void execute ()
{
(obj_->*method_)(TypedCallback<T>::param_);
}
};
template<typename T, class C, typename A>
class ObjectTypedArgCallback : public TypedCallback<T> {
public:
typedef void (C::*const method_t)(T, A);
private:
C *const obj_;
method_t method_;
A arg_;
public:
template<typename Tm>
ObjectTypedArgCallback(C *obj, Tm method, A arg)
: TypedCallback<T>(),
obj_(obj),
method_(method),
arg_(arg)
{ }
~ObjectTypedArgCallback()
{ }
virtual void execute ()
{
(obj_->*method_)(TypedCallback<T>::param_, arg_);
}
};
template<typename T, class C>
TypedCallback<T> *callback(C *obj, void (C::*const method)(T))
{
TypedCallback<T> *cb = new ObjectTypedCallback<T, C>(obj, method);
return (cb);
}
template<typename T, class C, typename A>
TypedCallback<T> *callback(C *obj, void (C::*const method)(T, A), A arg)
{
TypedCallback<T> *cb = new ObjectTypedArgCallback<T, C, A>(obj, method, arg);
return (cb);
}
#endif /* !EVENT_TYPED_CALLBACK_H */

141
event/typed_pair_callback.h Normal file
View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2010-2011 Juli Mallett. 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 AUTHOR 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 AUTHOR 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.
*/
#ifndef EVENT_TYPED_PAIR_CALLBACK_H
#define EVENT_TYPED_PAIR_CALLBACK_H
#include <event/callback.h>
////////////////////////////////////////////////////////////////////////////////
// //
// File: typed_pair_callback.h //
// Description: template classes for event callback handling //
// Project: WANProxy XTech //
// Adapted by: Andreu Vidal Bramfeld-Software //
// Last modified: 2015-04-01 //
// //
////////////////////////////////////////////////////////////////////////////////
/*
* XXX
* Feels like I can get std::pair and some sort
* of application template to do the heavy lifting
* here to avoid duplication of TypedCallback<T>.
*/
template<typename Ta, typename Tb>
class TypedPairCallback : public Callback {
protected:
bool have_param_;
std::pair<Ta, Tb> param_;
protected:
TypedPairCallback()
: Callback(),
have_param_(false),
param_()
{ }
public:
virtual ~TypedPairCallback()
{ }
public:
void param(Ta a, Tb b)
{
param_.first = a;
param_.second = b;
have_param_ = true;
}
};
template<typename Ta, typename Tb, class C>
class ObjectTypedPairCallback : public TypedPairCallback<Ta, Tb> {
public:
typedef void (C::*const method_t)(Ta, Tb);
private:
C *const obj_;
method_t method_;
public:
template<typename Tm>
ObjectTypedPairCallback(C *obj, Tm method)
: TypedPairCallback<Ta, Tb>(),
obj_(obj),
method_(method)
{ }
~ObjectTypedPairCallback()
{ }
virtual void execute ()
{
ASSERT("/typed/pair/callback", (TypedPairCallback<Ta,Tb>::have_param_));
(obj_->*method_)((TypedPairCallback<Ta,Tb>::param_.first), (TypedPairCallback<Ta,Tb>::param_.second));
}
};
template<typename Ta, typename Tb, class C, typename A>
class ObjectTypedPairArgCallback : public TypedPairCallback<Ta, Tb> {
public:
typedef void (C::*const method_t)(Ta, Tb, A);
private:
C *const obj_;
method_t method_;
A arg_;
public:
template<typename Tm>
ObjectTypedPairArgCallback(C *obj, Tm method, A arg)
: TypedPairCallback<Ta, Tb>(),
obj_(obj),
method_(method),
arg_(arg)
{ }
~ObjectTypedPairArgCallback()
{ }
virtual void execute ()
{
ASSERT("/typed/pair/callback", (TypedPairCallback<Ta,Tb>::have_param_));
(obj_->*method_)((TypedPairCallback<Ta,Tb>::param_.first), (TypedPairCallback<Ta,Tb>::param_.second), arg_);
}
};
template<typename Ta, typename Tb, class C>
TypedPairCallback<Ta, Tb> *callback(C *obj, void (C::*const method)(Ta, Tb))
{
TypedPairCallback<Ta, Tb> *cb = new ObjectTypedPairCallback<Ta, Tb, C>(obj, method);
return (cb);
}
template<typename Ta, typename Tb, class C, typename A>
TypedPairCallback<Ta, Tb> *callback(C *obj, void (C::*const method)(Ta, Tb, A), A arg)
{
TypedPairCallback<Ta, Tb> *cb = new ObjectTypedPairArgCallback<Ta, Tb, C, A>(obj, method, arg);
return (cb);
}
#endif /* !EVENT_TYPED_PAIR_CALLBACK_H */