diff options
author | Phil Mesnier <mesnier_p@ociweb.com> | 2004-11-05 04:29:02 +0000 |
---|---|---|
committer | Phil Mesnier <mesnier_p@ociweb.com> | 2004-11-05 04:29:02 +0000 |
commit | 2cf7df592ed63aea6d00d49d0ee54b7293caf49f (patch) | |
tree | b6af3fc856b24ad1964ae6f33982a9bf97d2da50 /protocols | |
parent | 5fbd7766eaa709261927d7e059fa5348b39b2057 (diff) | |
download | ATCD-2cf7df592ed63aea6d00d49d0ee54b7293caf49f.tar.gz |
ChangeLog tag: Thu Nov 4 22:08:40 2004 Phil Mesnier <mesnier_p@ociweb.com>
Diffstat (limited to 'protocols')
34 files changed, 4256 insertions, 0 deletions
diff --git a/protocols/ace/HTBP/HTBP.mpc b/protocols/ace/HTBP/HTBP.mpc new file mode 100644 index 00000000000..21c99d9a407 --- /dev/null +++ b/protocols/ace/HTBP/HTBP.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project(HTBP) : acelib, core { + sharedname = ACE_HTBP + dynamicflags = HTBP_BUILD_DLL +} diff --git a/protocols/ace/HTBP/HTBP_Addr.cpp b/protocols/ace/HTBP/HTBP_Addr.cpp new file mode 100644 index 00000000000..0ea811bb108 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Addr.cpp @@ -0,0 +1,89 @@ +// $Id$ + +#include "HTBP_Addr.h" +#include "ace/OS_NS_string.h" + +ACE_RCSID (HTBP, + ACE_HTBP_Addr, + "$Id$") + + // Constructor + ACE::HTBP::Addr::Addr () +{ +} + +// Creates a ACE_INET_Addr from a PORT_NUMBER and the remote +// HOST_NAME. + +ACE::HTBP::Addr::Addr (u_short port_number, + const char host_name[], + int address_family) + : ACE_INET_Addr (port_number, host_name, address_family), + htid_ () +{ +} + +ACE::HTBP::Addr::Addr (const char *htid) + : htid_(htid) +{ +} + +ACE::HTBP::Addr::Addr (const ACE::HTBP::Addr &other) + : ACE_INET_Addr (other), + htid_(other.htid_) +{ + +} + +// Destructor +ACE::HTBP::Addr::~Addr () +{ +} + +int +ACE::HTBP::Addr::set (u_short port, + const char host[], + const char *htid) +{ + if (htid != 0 && ACE_OS::strlen (htid) != 0) + return this->set_htid (htid); + return this->ACE_INET_Addr::set(port,host); +} + +int +ACE::HTBP::Addr::set_htid (const char *htid) +{ + this->htid_ = htid; + this->set_port_number (0); + return 0; +} + +const char * +ACE::HTBP::Addr::get_htid (void) const +{ + return this->htid_.c_str(); +} + +int +ACE::HTBP::Addr::addr_to_string (ACE_TCHAR buffer[], + size_t size, + int ipaddr_format) const +{ + if (this->htid_.length() == 0) + return this->ACE_INET_Addr::addr_to_string(buffer,size,ipaddr_format); + if (size < htid_.length()) + return -1; + ACE_OS::strncpy (buffer, + ACE_TEXT_CHAR_TO_TCHAR(htid_.c_str()), + size); + return 0; +} + +int +ACE::HTBP::Addr::string_to_addr (const char address[]) +{ + // if (ACE_OS::strchr (address,':')) + return this->ACE_INET_Addr::string_to_addr(address); + // this->htid_ = address; + // return 0; +} diff --git a/protocols/ace/HTBP/HTBP_Addr.h b/protocols/ace/HTBP/HTBP_Addr.h new file mode 100644 index 00000000000..3cbbaa397f7 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Addr.h @@ -0,0 +1,87 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file HTBP_Addr.h + * + * $Id$ + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_HTBP_ADDR_H +#define ACE_HTBP_ADDR_H +#include /**/ "ace/pre.h" + +#include "HTBP_Export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/INET_Addr.h" +#include "ace/Synch.h" +#include "ace/SString.h" + +namespace ACE +{ + namespace HTBP + { + + /** + * @class Addr + * + * @brief Defines the member functions of the pure virtual class + * Addr + * + * This class derives from ACE_INET_Addr. It is the base class for + * the Inside, Proxy and Outside classes + */ + class HTBP_Export Addr : public ACE_INET_Addr + { + public: + /// Constructor + Addr (); + + Addr (const Addr &other); + + /// Create an Addr suitable for use on the inside of a firewall this + /// take a string used to populate the htid_ member. With this address, + /// the IP addr form is ignored. + Addr (const char *htid); + + /// Initialize an Addr for the outside of a firewall. In this form, + /// the htid_ is an empty string and the arguments are passed to the + /// base address type. + Addr (u_short port_number, + const char host_name[], + int address_family = AF_UNSPEC); + + /// Destructor + virtual ~Addr (); + + int set (u_short port, + const char host [], + const char *htid); + + /// Methods to help convert the OutSide_Addr to a String + /// and vice versa + int addr_to_string (ACE_TCHAR buffer[], + size_t size, + int ipaddr_format = 1) const; + int string_to_addr (const char address[]); + + int set_htid(const char *htid); + const char *get_htid (void) const; + + private: + /// HTID - web-obtained unique-identifier + ACE_CString htid_; + }; + + } +} + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_ADDR_H */ diff --git a/protocols/ace/HTBP/HTBP_Channel.cpp b/protocols/ace/HTBP/HTBP_Channel.cpp new file mode 100644 index 00000000000..ee00eb90efc --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Channel.cpp @@ -0,0 +1,532 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Channel.cpp + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= +#include "HTBP_Channel.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Channel.inl" +#endif + +#include "HTBP_Session.h" +#include "HTBP_Filter_Factory.h" + +#include "ace/Message_Block.h" + + +// Initialization and termination methods. +/// Constructor. +ACE::HTBP::Channel::Channel (ACE::HTBP::Session *s) + : filter_ (0), + session_ (s), + ace_stream_ (), + notifier_ (0), + leftovers_ (1000), + data_len_ (0), + data_consumed_ (0), + state_ (Init), + error_buffer_ (0) +{ + ACE_NEW (this->notifier_,ACE::HTBP::Notifier(this)); + this->filter_ = get_filter (); + this->request_count_ = ACE_static_cast (unsigned long,ACE_OS::time()); +} + +/// Constructor, takes ownership of the supplied stream +ACE::HTBP::Channel::Channel (ACE_SOCK_Stream &s) + : filter_ (0), + session_ (0), + ace_stream_ (s.get_handle()), + notifier_ (0), + leftovers_ (1000), + data_len_ (0), + data_consumed_ (0), + state_ (Init), + error_buffer_ (0) + +{ + filter_ = get_filter (); + this->request_count_ = ACE_static_cast (unsigned long,ACE_OS::time()); +} + +ACE::HTBP::Channel::Channel (ACE_HANDLE h) + : filter_ (0), + session_ (0), + ace_stream_ (h), + notifier_ (0), + leftovers_ (1000), + data_len_ (0), + data_consumed_ (0), + state_ (Init), + error_buffer_ (0) +{ + filter_ = get_filter (); + this->request_count_ = ACE_static_cast (unsigned long,ACE_OS::time()); +} + +/// Destructor. +ACE::HTBP::Channel::~Channel (void) +{ + delete this->filter_; + delete this->notifier_; +} + + /// Dump the state of an object. +void +ACE::HTBP::Channel::dump (void) const +{ +} + +unsigned long +ACE::HTBP::Channel::request_count (void) +{ + return this->request_count_++; +} + +void +ACE::HTBP::Channel::register_notifier (ACE_Reactor *r) +{ + if (r == 0) + return; + if (this->notifier_ == 0) + { + ACE_NEW (this->notifier_,ACE::HTBP::Notifier(this)); + } + else + { + if (notifier_->get_handle() == ACE_INVALID_HANDLE) + { + delete this->notifier_; + ACE_NEW (this->notifier_,ACE::HTBP::Notifier(this)); + } + } + + r->register_handler(notifier_,ACE_Event_Handler::READ_MASK); +} + +ACE::HTBP::Notifier * +ACE::HTBP::Channel::notifier (void) +{ + return this->notifier_; +} + +ACE_HANDLE +ACE::HTBP::Channel::get_handle (void) const +{ + return this->ace_stream_.get_handle (); +} + +void +ACE::HTBP::Channel::data_consumed (size_t n) +{ + this->data_consumed_ += n; + if (this->data_consumed_ == this->data_len_) + { + this->filter_->recv_data_trailer(this); + this->filter_->send_ack(this); + } +} + +int +ACE::HTBP::Channel::load_buffer (void) +{ + this->leftovers_.crunch(); + if (this->state() == Detached || + this->state() == Ack_Sent) + { + this->data_len_ = 0; + this->data_consumed_ = 0; + } + + ssize_t nread = 0; + errno = 0; +#if 0 + if (this->session_ && + (this->session_->sock_flags() & ACE_NONBLOCK == ACE_NONBLOCK)) +#endif + { + nread = + ACE::handle_read_ready (this->ace_stream().get_handle(), + &ACE_Time_Value::zero); + if (nread == -1 && errno == ETIME) + errno = EWOULDBLOCK; + } + if (nread != -1) + nread = this->ace_stream().recv (this->leftovers_.wr_ptr(), + this->leftovers_.space()); + if (nread < 1) + { + if (nread == 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) + { + this->state_ = Closed; +#if 0 + ACE_ERROR ((LM_ERROR, + "load_buffer[%d] %p\n", + this->ace_stream_.get_handle(),"recv")); +#endif + } + return nread; + } + this->leftovers_.wr_ptr(nread); + *this->leftovers_.wr_ptr() = '\0'; +#if 0 + ACE_DEBUG ((LM_DEBUG,"load_buffer[%d] received %d \n", + this->ace_stream_.get_handle(),leftovers_.length())); + ACE_HEX_DUMP ((LM_DEBUG,leftovers_.rd_ptr(),leftovers_.length())); +#endif + return nread; +} + +int +ACE::HTBP::Channel::flush_buffer (void) +{ + if (this->session_) + return this->session_->flush_outbound_queue(); + return 0; +} + +int +ACE::HTBP::Channel::send_ack (void) +{ + return this->filter_->send_ack(this); +} + +int +ACE::HTBP::Channel::recv_ack (void) +{ + if (load_buffer() == -1) + return -1; + return this->filter_->recv_ack(this); +} + +void +ACE::HTBP::Channel::state (ACE::HTBP::Channel::State s) +{ + if (s == Detached) + { + this->session_->detach(this); + this->session_ = 0; + } + this->state_ = s; +} + +int +ACE::HTBP::Channel::consume_error (void) +{ + if (error_buffer_ == 0) + { + ACE_NEW_RETURN (error_buffer_, + ACE_Message_Block (this->data_len_ + 1), + 0); + } + + ssize_t result = 0; + size_t n = error_buffer_->size(); + char *buf = error_buffer_->wr_ptr(); + + if (this->leftovers_.length() > 0) + { + result = ACE_MIN (n,this->leftovers_.length()); + ACE_OS::memcpy (buf,this->leftovers_.rd_ptr(), result); + this->leftovers_.rd_ptr(result); + buf += result; + } + + if (result < (ssize_t)n && + result < (ssize_t)data_len_) + { + n -= result; + result += this->ace_stream_.recv(buf, n); + } + if (result > 0) + { + this->error_buffer_->wr_ptr(result); + this->data_consumed_ += result; + if (this->data_consumed_ == this->data_len_) + { + *this->error_buffer_->wr_ptr() = '\0'; + ACE_DEBUG ((LM_DEBUG,"Received entire error buffer: \n%s\n", + this->error_buffer_->rd_ptr())); + delete error_buffer_; + error_buffer_ = 0; + + return 1; + } + } + return 0; +} + +//--------------------------------------------------------------------------- +// = I/O functions. + +/// The ACE::HTBP::Channel is a sibling of the ACE_SOCK_IO class, rather than a +/// decendant. This is due to the requirement to wrap all messages with +/// an HTTP request or reply wrapper, and to send application data in only +/// one direction on one stream. + +int +ACE::HTBP::Channel::pre_recv(void) +{ + if (this->state_ == Init || + this->state_ == Detached || + this->state_ == Header_Pending || + this->state_ == Ack_Sent) + { + if (this->load_buffer() == -1 && this->leftovers_.length() == 0) + { + if (errno != EWOULDBLOCK) + this->state_ = Closed; + ACE_DEBUG ((LM_DEBUG,"pre_recv returning -1, state = %d\n",state_)); + return -1; + } + if (this->filter_->recv_data_header(this) == -1) + ACE_DEBUG ((LM_DEBUG,"recv_data_header failed, %p\n","pre_recv")); + } + switch (this->state_) + { + case Data_Queued: + case Ack_Sent: + case Ready: + return 0; + case Header_Pending: + errno = EWOULDBLOCK; + return -1; + default: + ACE_DEBUG ((LM_DEBUG,"channel[%d] state = %d, %p\n", + this->get_handle(), + this->state_,"pre_recv")); + } + return -1; +} + +/// Recv an <n> byte buffer from the connected socket. +ssize_t +ACE::HTBP::Channel::recv (void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->pre_recv() == -1 && this->leftovers_.length() == 0) + return -1; + + if (this->leftovers_.length() > 0) + { + result = ACE_MIN (n,this->leftovers_.length()); + ACE_OS::memcpy (buf,this->leftovers_.rd_ptr(), result); + this->leftovers_.rd_ptr(result); + buf = (char *)buf + result; + } + + if (result < (ssize_t)n && + result < (ssize_t)data_len_) + { + n -= result; + result += this->ace_stream_.recv(buf, n, flags, timeout); + } + if (result > 0) + data_consumed((size_t)result); + return result; +} + + /// Recv an <n> byte buffer from the connected socket. +ssize_t +ACE::HTBP::Channel::recv (void *buf, + size_t n, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->pre_recv() == -1) + return -1; + + result = 0; + if (this->leftovers_.length() > 0) + { + result = ACE_MIN (n,this->leftovers_.length()); + ACE_OS::memcpy (buf,this->leftovers_.rd_ptr(), result); + this->leftovers_.rd_ptr(result); + buf = (char *)buf + result; + } + + if ((size_t)result < n && (size_t)result < this->data_len()) + { + n -= result; + result += this->ace_stream_.recv(buf, n, timeout); + } + + if (result > 0) + this->data_consumed((size_t)result); + return result; +} + + /// Recv an <iovec> of size <n> from the connected socket. +ssize_t +ACE::HTBP::Channel::recvv (iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->pre_recv() == -1) + return -1; + + if (this->leftovers_.length()) + { + int ndx = 0; + iovec *iov2 = new iovec[iovcnt]; + for (int i = 0; i < iovcnt; i++) + { + size_t n = ACE_MIN ((size_t) iov[i].iov_len , + (size_t) this->leftovers_.length()); + if (n > 0) + { + ACE_OS::memcpy (iov[i].iov_base,this->leftovers_.rd_ptr(), n); + this->leftovers_.rd_ptr(n); + result += n; + } + if (n < (size_t) iov[i].iov_len) + { + iov2[ndx].iov_len = iov[i].iov_len - n; + iov2[ndx].iov_base = (char *)iov[i].iov_base + n; + ndx++; + } + } + if (ndx > 0) + result += this->ace_stream_.recvv(iov2,ndx,timeout); + delete [] iov2; + } + else + result = this->ace_stream_.recvv(iov,iovcnt,timeout); + + if (result > 0) + this->data_consumed((size_t)result); + return result; +} + +ssize_t +ACE::HTBP::Channel::recvv (iovec *io_vec, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->pre_recv() == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG,"recvv, leftover len = %d\n", + this->leftovers_.length())); + if (this->leftovers_.length()) + { + io_vec->iov_base = 0; + io_vec->iov_len = 0; + ACE_NEW_RETURN (io_vec->iov_base, + char[this->leftovers_.length()],-1); + io_vec->iov_len = this->leftovers_.length(); + ACE_OS::memcpy (io_vec->iov_base, + this->leftovers_.rd_ptr(), + io_vec->iov_len); + result = io_vec->iov_len; + this->leftovers_.length(0); + } + else + result = this->ace_stream_.recvv(io_vec,timeout); + + if (result > 0) + this->data_consumed((size_t)result); + return result; +} + +ssize_t +ACE::HTBP::Channel::send (const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->filter_->send_data_header(n,this) == -1) + return -1; + result = this->ace_stream_.send(buf,n,flags,timeout); + if (result == -1) + return -1; + if (this->filter_->send_data_trailer(this) == -1) + return -1; + return result; +} + +ssize_t +ACE::HTBP::Channel::send (const void *buf, + size_t n, + const ACE_Time_Value *timeout) +{ + ssize_t result = 0; + if (this->filter_ == 0) + ACE_ERROR_RETURN ((LM_DEBUG, "ACE::HTBP::Channel::send: filter is null\n"),-1); + if (this->filter_->send_data_header(n,this) == -1) + return -1; + result = this->ace_stream_.send (buf,n,timeout); + if (result == -1) + return -1; + if (this->filter_->send_data_trailer(this) == -1) + return -1; + return result; +} + +ssize_t +ACE::HTBP::Channel::sendv (const iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout) +{ + if (this->ace_stream_.get_handle() == ACE_INVALID_HANDLE) + this->session_->inbound(); + + ssize_t result = 0; + size_t n = 0; + for (int i = 0; i < iovcnt; n += iov[i++].iov_len); + + if (this->filter_->send_data_header(n,this) == -1) + ACE_ERROR_RETURN ((LM_ERROR,"sendv, %p\n","send_data_header"),-1); + + result = this->ace_stream_.sendv (iov,iovcnt,timeout); + + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR,"sendv, %p\n","ace_stream_.sendv"),-1); + + if (this->filter_->send_data_trailer(this) == -1) + ACE_ERROR_RETURN ((LM_ERROR,"sendv, %p\n","send_data_trailer\n"),-1); + + return result; +} + +int +ACE::HTBP::Channel::enable (int value) const +{ + this->ace_stream_.enable(value); + + return 0; //this->ace_stream_.enable(value); +} + +int +ACE::HTBP::Channel::disable (int value) const +{ + this->ace_stream_.disable(value); + + return 0;//this->ace_stream_.disable(value); +} + +ACE::HTBP::Filter * +ACE::HTBP::Channel::get_filter () +{ + ACE::HTBP::Filter_Factory *factory = 0; + + // @todo Should I be throwing an exception here if + // memory is not allocated right ? + ACE_NEW_RETURN (factory, + ACE::HTBP::Filter_Factory, + 0); + int inside = (this->session_ != 0); + return factory->get_filter (inside); +} diff --git a/protocols/ace/HTBP/HTBP_Channel.h b/protocols/ace/HTBP/HTBP_Channel.h new file mode 100644 index 00000000000..3109ed656eb --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Channel.h @@ -0,0 +1,277 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Channel.h + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= + +#ifndef ACE_HTBP_CHANNEL_H +#define ACE_HTBP_CHANNEL_H +#include /**/ "ace/pre.h" + +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" +#include "HTBP_Addr.h" +#include "HTBP_Filter.h" +#include "HTBP_Notifier.h" + + +namespace ACE +{ + namespace HTBP + { + // Forward declarations. + class Session; + + /** + * @class ACE::HTBP::Channel + * + * @brief Defines the methods in the <Ht_Channel> abstraction. + * + * This adds additional wrapper methods atop the <IO> + * class. + * + * <buf> is the buffer to write from or receive into. + * <len> is the number of bytes to transfer. + * The <timeout> parameter in the following methods indicates how + * long to blocking trying to transfer data. If <timeout> == 0, + * then the call behaves as a normal send/recv call, i.e., for + * blocking sockets, the call will block until action is possible; + * for non-blocking sockets, EWOULDBLOCK will be returned if no + * action is immediately possible. + * If <timeout> != 0, the call will wait for data to arrive no longer + * than the relative time specified in *<timeout>. + * The "_n()" I/O methods keep looping until all the data has been + * transferred. These methods also work for sockets in non-blocking + * mode i.e., they keep looping on EWOULDBLOCK. <timeout> is used + * to make sure we keep making progress, i.e., the same timeout + * value is used for every I/O operation in the loop and the timeout + * is not counted down. + * The return values for the "*_n()" methods match the return values + * from the non "_n()" methods and are specified as follows: + * - On complete transfer, the number of bytes transferred is returned. + * - On timeout, -1 is returned, errno == ETIME. + * - On error, -1 is returned, errno is set to appropriate error. + * - On EOF, 0 is returned, errno is irrelevant. + * + * On partial transfers, i.e., if any data is transferred before + * timeout/error/EOF, <bytes_transferred> will contain the number of + * bytes transferred. + * Methods with <iovec> parameter are I/O vector variants of the I/O + * operations. + * Methods with the extra <flags> argument will always result in + * <send> getting called. Methods without the extra <flags> argument + * will result in <send> getting called on Win32 platforms, and + * <write> getting called on non-Win32 platforms. + */ + class HTBP_Export Channel + { + public: + friend class Notifier; + // Initialization and termination methods. + /// Constructor. + Channel (Session *s = 0); + + Channel (ACE_SOCK_Stream &s); + Channel (ACE_HANDLE h); + + /// Destructor. + ~Channel (void); + + enum State { + Init, + Ready, + Data_Queued, + Ack_Sent, + Header_Sent, + Closed, + Send_Ack, + Detached, + Wait_For_Ack, + Header_Pending + }; + + // = I/O functions. + + /// The Channel is a sibling of the ACE_SOCK_IO class, rather than a + /// decendant. This is due to the requirement to wrap all messages with + /// an HTTP request or reply wrapper, and to send application data in only + /// one direction on one stream. + + /// Recv an <n> byte buffer from the connected socket. + ssize_t recv (void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout = 0); + + /// Recv an <n> byte buffer from the connected socket. + ssize_t recv (void *buf, + size_t n, + const ACE_Time_Value *timeout = 0); + + /// Recv an <iovec> of size <n> from the connected socket. + ssize_t recvv (iovec iov[], + int n, + const ACE_Time_Value *timeout = 0); + + /// Same as above. Deprecated. + ssize_t recv (iovec iov[], + size_t n, + const ACE_Time_Value *timeout = 0); + + /** + * Allows a client to read from a socket without having to provide a + * buffer to read. This method determines how much data is in the + * socket, allocates a buffer of this size, reads in the data, and + * returns the number of bytes read. The caller is responsible for + * deleting the member in the <iov_base> field of <io_vec> using + * delete [] io_vec->iov_base. + */ + ssize_t recvv (iovec *io_vec, + const ACE_Time_Value *timeout = 0); + + /// Send an <n> byte buffer to the connected socket. + ssize_t send (const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout = 0); + + /// Send an <n> byte buffer to the connected socket. + ssize_t send (const void *buf, + size_t n, + const ACE_Time_Value *timeout = 0); + + /// Send an <iovec> of size <n> to the connected socket. + ssize_t sendv (const iovec iov[], + int n, + const ACE_Time_Value *timeout = 0); + + // = Selectively close endpoints. + /// Close down the reader. + int close_reader (void); + + /// Close down the writer. + int close_writer (void); + + /** + * Close down the socket (we need this to make things work correctly + * on Win32, which requires use to do a <close_writer> before doing + * the close to avoid losing data). + */ + int close (void); + + // = Meta-type info + typedef ACE_INET_Addr PEER_ADDR; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + public: + Session *session (void) const; + void session (Session *); + + Notifier *notifier (void); + + void register_notifier (ACE_Reactor *r); + + ACE_HANDLE get_handle (void) const; + + const ACE_SOCK_Stream &ace_stream (void) const; + ACE_SOCK_Stream &ace_stream (void); + + ///@notes Added the following methods to continue with + /// current compilation of HTIOP. Might not be needed in + /// future. - Priyanka + /// {@ + void set_handle (ACE_HANDLE h); + + /** + * Enable asynchronous I/O (ACE_SIGIO), urgent data (ACE_SIGURG), + * non-blocking I/O (ACE_NONBLOCK), or close-on-exec (ACE_CLOEXEC), + * which is passed as the <value>. + */ + int enable (int value) const; + + /** + * Disable asynchronous I/O (ACE_SIGIO), urgent data (ACE_SIGURG), + * non-blocking I/O (ACE_NONBLOCK), or close-on-exec (ACE_CLOEXEC), + * which is passed as the <value>. + */ + int disable (int value) const; + //@} + + // buffer related methods. + ACE_Message_Block &leftovers (void); + size_t data_len (void) const; + void data_len (size_t n); + size_t data_consumed (void) const; + void data_consumed (size_t n); + int load_buffer (void); + int flush_buffer (void); + int recv_ack (void); + int send_ack (void); + unsigned long request_count(); + Filter *filter (void) const; + void filter (Filter *); + State state (void) const; + void state (Channel::State s); + int pre_recv(void); + int consume_error (void); + + private: + + /// Get the filter from the Filter_Factory + Filter * get_filter (); + + /// The filter_ is a pluggable component used to manage the + /// wrapping of data in a way suitable for the proxy to + /// manage. The actual filter instance is owned by the + /// session. Different filters may be required depending on + /// which side of the proxy we are on, and the direction of data + /// flow. + Filter *filter_; + + /// The session_ is a reference to the persistent session this + /// stream is associated with. On the inside, sessions are + /// created by the Connector, which then create streams on + /// demand. + Session *session_; + + /// Since this stream implements its own send and recv methods, + /// the filter cannot simply call the send and recv methods of + /// this class. Therefore an ACE_SOCK_Stream wrapper around the + /// same socket instance is necessary to avoid recursion. + ACE_SOCK_Stream ace_stream_; + + Notifier *notifier_; + + ACE_Message_Block leftovers_; + size_t data_len_; + size_t data_consumed_; + State state_; + ACE_Message_Block *error_buffer_; + unsigned long request_count_; + }; + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Channel.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_CHANNEL_H */ diff --git a/protocols/ace/HTBP/HTBP_Channel.inl b/protocols/ace/HTBP/HTBP_Channel.inl new file mode 100644 index 00000000000..70fc4834842 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Channel.inl @@ -0,0 +1,122 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE::HTBP::Channel.i + + +ACE_INLINE +ACE::HTBP::Session * +ACE::HTBP::Channel::session (void) const +{ + return this->session_; +} + +// session assignment only occurs when the stream is transferred to another +// session. Do *not* delete the old session object. +ACE_INLINE +void +ACE::HTBP::Channel::session (ACE::HTBP::Session *s) +{ + this->session_ = s; +} + +// I'm not sure of the proper use case for getting the filter reference. The +// problem is that the filter is not reference counted, so the returned value +// should not be stored. +ACE_INLINE +ACE::HTBP::Filter * +ACE::HTBP::Channel::filter (void) const +{ + return this->filter_; +} + +// Filters are owned by the channel. If a new filter is applied, the old one +// must be deleted. +ACE_INLINE +void +ACE::HTBP::Channel::filter (ACE::HTBP::Filter *f) +{ + if (this->filter_) + delete this->filter_; + this->filter_ = f; +} + +ACE_INLINE +int +ACE::HTBP::Channel::close_reader (void) +{ + return this->ace_stream_.close_reader(); +} + +ACE_INLINE +int +ACE::HTBP::Channel::close_writer (void) +{ + return this->ace_stream_.close_writer(); +} + +ACE_INLINE +int +ACE::HTBP::Channel::close (void) +{ + return this->ace_stream_.close(); +} + +ACE_INLINE +ACE::HTBP::Channel::State +ACE::HTBP::Channel::state (void) const +{ + return this->state_; +} + +ACE_INLINE +ACE_Message_Block & +ACE::HTBP::Channel::leftovers (void) +{ + return this->leftovers_; +} + +ACE_INLINE +size_t +ACE::HTBP::Channel::data_len(void) const +{ + return this->data_len_; +} + +ACE_INLINE +void +ACE::HTBP::Channel::data_len(size_t n) +{ + this->data_len_ = n; +} + +ACE_INLINE +size_t +ACE::HTBP::Channel::data_consumed(void) const +{ + return this->data_consumed_; +} + + +ACE_INLINE +const ACE_SOCK_Stream& +ACE::HTBP::Channel::ace_stream (void) const +{ + return this->ace_stream_; +} + +ACE_INLINE +ACE_SOCK_Stream& +ACE::HTBP::Channel::ace_stream (void) +{ + return this->ace_stream_; +} + +ACE_INLINE +void +ACE::HTBP::Channel::set_handle (ACE_HANDLE h) +{ + if (h == 0) + return; + this->ace_stream_.set_handle (h); +} diff --git a/protocols/ace/HTBP/HTBP_Environment.cpp b/protocols/ace/HTBP/HTBP_Environment.cpp new file mode 100644 index 00000000000..60d3b017f17 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Environment.cpp @@ -0,0 +1,197 @@ +// $Id$ + +#include "HTBP_Environment.h" + +ACE_RCSID (HTBP, + ACE_HTBP_Environment, + "$Id$") + +ACE::HTBP::Environment::Environment (ACE_Configuration *config, + int using_registry, + const ACE_TCHAR *persistent_file) + : config_ (config), + imp_exp_ (0), + own_config_ (config != 0) +{ + initialize (using_registry, + persistent_file); +} + +ACE::HTBP::Environment::~Environment () +{ + if (!own_config_) + this->clear(); + else + delete this->config_; + + delete this->imp_exp_; +} + +void +ACE::HTBP::Environment::clear () +{ + if (this->config_) + this->config_->remove_section (config_->root_section (), + ACE_TEXT("htbp"), + 1); +} + +int +ACE::HTBP::Environment::initialize (int use_registry, + const ACE_TCHAR *persistent_file) +{ + if (this->config_ == 0) + { + int result = -1; + if (use_registry) + result = this->open_registry_config(); + if (result == -1) + result = this->open_persistent_config (persistent_file); + if (result != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::Environment::initialize (): ") + ACE_TEXT("Open Config failed")), + -1); + } + } + + + ACE_NEW_RETURN (this->imp_exp_, + ACE_Ini_ImpExp (*this->config_), + -1); + + if (this->config_->open_section (config_->root_section (), + ACE_TEXT("htbp"), 1, + this->htbp_key_) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::Environment::initialize (). ") + ACE_TEXT("Open HTBP Section failed")), + -1); + return 0; +} + +int +ACE::HTBP::Environment::open_registry_config () +{ +#if defined (ACE_WIN32) + HKEY root = + ACE_Configuration_Win32Registry::resolve_key + (HKEY_LOCAL_MACHINE,ACE_TEXT("Software\\HTBP\\Environment")); + + ACE_NEW_RETURN (this->config_, + ACE_Configuration_Win32Registry (root), + -1); + return 0; +#else + errno = ENOTSUP; + return -1; +#endif /* ACE_WIN32 */ +} + +int +ACE::HTBP::Environment::open_persistent_config (const ACE_TCHAR *persistent_file) +{ + ACE_Configuration_Heap *heap; + ACE_NEW_RETURN (heap, + ACE_Configuration_Heap, + -1); + // do this before trying to open so it isn't leaked if the open fails. + this->config_ = heap; + if (persistent_file == 0) + heap->open(); + else + if (heap->open (persistent_file) != 0) + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ACE::HTBP::Environment::open_config: %p\n"), + persistent_file), + -1 ); + return 0; +} + +int +ACE::HTBP::Environment::get_htid_url (ACE_TString &htid_url) const +{ + return this->config_->get_string_value (this->htbp_key_, + ACE_TEXT("htid_url"), + htid_url); +} + +int +ACE::HTBP::Environment::set_htid_url (const ACE_TCHAR *htid_generator_url) +{ + return this->config_->set_string_value (this->htbp_key_, + ACE_TEXT("htid_url"), + htid_generator_url); +} + + +int +ACE::HTBP::Environment::get_htid_via_proxy (int &via_proxy) const +{ + return this->config_->get_integer_value (this->htbp_key_, + ACE_TEXT("htid_via_proxy"), + (u_int &)via_proxy); +} + +int +ACE::HTBP::Environment::set_htid_via_proxy (int via_proxy) +{ + return this->config_->set_integer_value (this->htbp_key_, + ACE_TEXT("htid_via_proxy"), + (u_int)via_proxy); +} + +int +ACE::HTBP::Environment::get_proxy_host (ACE_TString &proxy_host) const +{ + return this->config_->get_string_value (this->htbp_key_, + ACE_TEXT("proxy_host"), + proxy_host); +} + +int +ACE::HTBP::Environment::set_proxy_host (const ACE_TCHAR *proxy_host) +{ + return this->config_->set_string_value (this->htbp_key_, + ACE_TEXT("proxy_host"), + proxy_host); +} + +int +ACE::HTBP::Environment::get_proxy_port (unsigned int &proxy_port) const +{ + int result = this->config_->get_integer_value (this->htbp_key_, + ACE_TEXT("proxy_port"), + proxy_port); + if (result != 0) + { + ACE_TString port_str; + result = this->config_->get_string_value (this->htbp_key_, + ACE_TEXT("proxy_port"), + port_str); + if (result == 0) + proxy_port = ACE_OS::strtol(port_str.c_str(),0,10); + } + return result; +} + +int +ACE::HTBP::Environment::set_proxy_port (unsigned int proxy_port) +{ + return this->config_->set_integer_value (this->htbp_key_, + ACE_TEXT("proxy_port"), + proxy_port); +} + +int +ACE::HTBP::Environment::import_config (const ACE_TCHAR *filename) +{ + return this->imp_exp_->import_config (filename); +} + +int +ACE::HTBP::Environment::export_config (const ACE_TCHAR *filename) +{ + return this->imp_exp_->export_config (filename); +} diff --git a/protocols/ace/HTBP/HTBP_Environment.h b/protocols/ace/HTBP/HTBP_Environment.h new file mode 100644 index 00000000000..2f4cc90a5ac --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Environment.h @@ -0,0 +1,107 @@ +// -*- C++ -*- +// $Id$ + +#ifndef ACE_HTBP_ENVIRONMENT_H +#define ACE_HTBP_ENVIRONMENT_H +#include /**/ "ace/pre.h" + +#include "HTBP_Export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Configuration.h" +#include "ace/Configuration_Import_Export.h" +#include "ace/Singleton.h" + + +namespace ACE +{ + namespace HTBP + { + + /** + * @class Environment + * + * @brief + * + * This class manages the storage of configuration data, either in a + * flat file for Unix systems, or in the Windows registry + */ + class HTBP_Export Environment + { + public: + + /// Constructor + Environment (ACE_Configuration *config = 0, + int using_registry = 0, + const ACE_TCHAR *persistent_file = 0); + + /// Destructor + ~Environment (); + + /// removes all htbp related values from the configuration + void clear (void); + + /// Accessors to HTID URL + /// Returns 0 on success + /// {@ + int get_htid_url (ACE_TString &htid_url) const; + int set_htid_url (const ACE_TCHAR *htid_generator_url); + /// @} + + /// Accessors to HTID via proxy - If value is true, HTID request goes + /// through configured proxy otherwise it uses a direct connection. + /// Returns 0 on success + /// {@ + int get_htid_via_proxy (int &htid_via_proxy) const; + int set_htid_via_proxy (int htid_via_proxy); + /// @} + + /// Accessors to Proxy Address + /// Returns 0 on success + /// {@ + int get_proxy_host (ACE_TString &proxy_host) const; + int set_proxy_host (const ACE_TCHAR *proxy_host); + /// @} + + /// Returns 0 on success + /// {@ + int get_proxy_port (unsigned int &proxy_port) const; + int set_proxy_port (unsigned int proxy_port); + /// @} + + /// Import the configuration from the filename + int import_config (const ACE_TCHAR *filename); + + /// Export the configuration to the filename + int export_config (const ACE_TCHAR *filename); + + private: + /// Open config, set sections etc + int initialize (int use_registry, + const ACE_TCHAR *persistent_file); + + /// Open an ACE_Configuration of the appropriate type. + int open_registry_config (); + int open_persistent_config (const ACE_TCHAR *persistent_file); + + /// Our Proxy and HTID generator URL database + ACE_Configuration *config_; + + /// Flat section of HTBP related items + ACE_Configuration_Section_Key htbp_key_; + + /// the wrapper used to import or export initialization values + ACE_Ini_ImpExp *imp_exp_; + + /// We created the config instance, so we must clean it up + int own_config_; + + }; + } +} + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_ENVIRONMENT_H */ diff --git a/protocols/ace/HTBP/HTBP_Export.h b/protocols/ace/HTBP/HTBP_Export.h new file mode 100644 index 00000000000..19ce8a89547 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Export.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl -d -s HTBP +// ------------------------------ +#ifndef HTBP_EXPORT_H +#define HTBP_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (HTBP_HAS_DLL) +# define HTBP_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && HTBP_HAS_DLL */ + +#if !defined (HTBP_HAS_DLL) +# define HTBP_HAS_DLL 1 +#endif /* ! HTBP_HAS_DLL */ + +#if defined (HTBP_HAS_DLL) && (HTBP_HAS_DLL == 1) +# if defined (HTBP_BUILD_DLL) +# define HTBP_Export ACE_Proper_Export_Flag +# define HTBP_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define HTBP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* HTBP_BUILD_DLL */ +# define HTBP_Export ACE_Proper_Import_Flag +# define HTBP_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define HTBP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* HTBP_BUILD_DLL */ +#else /* HTBP_HAS_DLL == 1 */ +# define HTBP_Export +# define HTBP_SINGLETON_DECLARATION(T) +# define HTBP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* HTBP_HAS_DLL == 1 */ + +// Set HTBP_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (HTBP_NTRACE) +# if (ACE_NTRACE == 1) +# define HTBP_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define HTBP_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !HTBP_NTRACE */ + +#if (HTBP_NTRACE == 1) +# define HTBP_TRACE(X) +#else /* (HTBP_NTRACE == 1) */ +# define HTBP_TRACE(X) ACE_TRACE_IMPL(X) +#endif /* (HTBP_NTRACE == 1) */ + +#endif /* HTBP_EXPORT_H */ + +// End of auto generated file. diff --git a/protocols/ace/HTBP/HTBP_Filter.cpp b/protocols/ace/HTBP/HTBP_Filter.cpp new file mode 100644 index 00000000000..0e239e0b419 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Filter.cpp @@ -0,0 +1,56 @@ +// ACE_HTBP_Filter.cpp +// $Id$ + +#include "ace/Log_Msg.h" + +#include <sstream> + +#include "HTBP_Session.h" +#include "HTBP_Filter.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Filter.inl" +#endif + +ACE_RCSID(HTBP,ACE_HTBP_Filter,"$ID: $") + +ACE::HTBP::Filter::Filter (void) + :http_code_ (0) +{ +} + +ACE::HTBP::Filter::~Filter (void) +{ +} + +char * +ACE::HTBP::Filter::header_complete (ACE::HTBP::Channel *ch) +{ + if (ch->leftovers().length() == 0) + { + return 0; + } + if (ch->leftovers().space() > 0) + *ch->leftovers().wr_ptr() = '\0'; + char *start = ch->leftovers().rd_ptr(); + char *nl = ACE_OS::strchr (start,'\n'); + if (this->http_code_ == 0) + { + char *code = ACE_OS::strstr (start,"HTTP/1."); + if (code && code < nl) + { + code += 9; // skip past "HTTP/1.1 " + this->http_code_ = strtol(code,0,10); + } + } + + while (nl) + { + if ((nl == start) || + (nl == start +1 && *start == '\r')) + return nl + 1; + start = nl + 1; + nl = ACE_OS::strchr (start,'\n'); + } + return 0; +} diff --git a/protocols/ace/HTBP/HTBP_Filter.h b/protocols/ace/HTBP/HTBP_Filter.h new file mode 100644 index 00000000000..9548f377d1b --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Filter.h @@ -0,0 +1,100 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Filter.h + * + * $Id$ + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_HTBP_FILTER_H +#define ACE_HTBP_FILTER_H +#include /**/ "ace/pre.h" + +#include "ace/OS.h" +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" + +namespace ACE +{ + namespace HTBP + { + + // Forward declarations. + class Channel; + + /** + * @class ACE_HTBP_Filter + * + * @brief Defines the methods in the <ACE_HTBP_Filter> abstraction. + * + * A filter is responsible for wrapping / unwrapping messages + * depending on direction of flow on each stream. There will be 4 + * filters participating in a session, inside-send, inside-recv, + * outside-send, ouside-recv. It is anticipated that specialized + * filters will be implemented that tune the filter behavior based + * on proxy particulars. That, or there will be a matrix + * configuration parameters that may be tweeked to match the + * configuration. It remains to be seen which is easier to + * manage. + */ + class HTBP_Export Filter + { + public: + Filter (void); + + virtual ~Filter (void); + + /// Inside and outside Send filters need to supply a data header that + /// sets the stage before sending the data body, and then (maybe) send a + /// data trailer that closes the message. The data header may be formatted + /// differently on the first message, to send optional context information. + virtual ssize_t send_data_header (ssize_t data_len, Channel *ch); + virtual ssize_t send_data_trailer (Channel *ch); + + /// Upon receiving data, the Channel is obliged to send an ack. This is + /// either an empty document if this is the in-to-out stream, or a new + /// long-duration document request if this is the out-to-in stream. + virtual int send_ack (Channel *ch); + virtual int recv_ack (Channel *ch); + + /// receiving data must compliment sending. In the case of an in-to-out + /// stream. It is possible that the stream identity is not known until the + /// first request is received. In this case the filter will have to look + /// lookup the received session ID and either create a new instance or + /// reassign itself to an existing sesion. In that case, the associated + /// stream will have to be reassigned as well. + /// + virtual ssize_t recv_data_header (Channel *ch); + virtual ssize_t recv_data_trailer(Channel *ch); + + /// reset the http_code_ in anticipation of a new message. + void reset_http_code (void); + + /// get the value of the most recent http result code + int http_code (void); + + protected: + char *header_complete (Channel *ch); + + private: + /// Store the most recent HTTP result code. Typically it will be 200, + /// but it could be a 4xx or 5xx code if the proxy reports an error. + int http_code_; + + }; + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Filter.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_FILTER_H */ diff --git a/protocols/ace/HTBP/HTBP_Filter.inl b/protocols/ace/HTBP/HTBP_Filter.inl new file mode 100644 index 00000000000..224b7e02699 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Filter.inl @@ -0,0 +1,60 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE_HTBP_Filter.i + +ACE_INLINE +ssize_t +ACE::HTBP::Filter::send_data_header (ssize_t, ACE::HTBP::Channel * ) +{ + return 0; +} + +ACE_INLINE +ssize_t +ACE::HTBP::Filter::send_data_trailer (ACE::HTBP::Channel *) +{ + return 0; +} + +ACE_INLINE +int +ACE::HTBP::Filter::send_ack (ACE::HTBP::Channel *) +{ + return 0; +} + +ACE_INLINE +int +ACE::HTBP::Filter::recv_ack (ACE::HTBP::Channel *) +{ + return 0; +} + +ACE_INLINE +ssize_t +ACE::HTBP::Filter::recv_data_header (ACE::HTBP::Channel *) +{ + return 0; +} + +ACE_INLINE +ssize_t +ACE::HTBP::Filter::recv_data_trailer(ACE::HTBP::Channel *) +{ + return 0; +} + +ACE_INLINE +void +ACE::HTBP::Filter::reset_http_code (void) +{ + this->http_code_ = 0; +} + +ACE_INLINE +int +ACE::HTBP::Filter::http_code (void) +{ + return this->http_code_; +} diff --git a/protocols/ace/HTBP/HTBP_Filter_Factory.cpp b/protocols/ace/HTBP/HTBP_Filter_Factory.cpp new file mode 100644 index 00000000000..8c42584d143 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Filter_Factory.cpp @@ -0,0 +1,57 @@ +// $Id$ + +#include "HTBP_Filter_Factory.h" +#include "HTBP_Inside_Squid_Filter.h" +#include "HTBP_Outside_Squid_Filter.h" + +#include "HTBP_Stream.h" +#include "ace/Service_Object.h" +#include "ace/Dynamic_Service.h" +#include "ace/Log_Msg.h" + +ACE_RCSID (ACE_HTBP_Filter_Factory, HTBP, "$Id$") + +ACE::HTBP::Filter_Factory::Filter_Factory () +{ +} + +ACE::HTBP::Filter_Factory::~Filter_Factory () +{ +} + +ACE::HTBP::Filter * +ACE::HTBP::Filter_Factory::get_filter (int inside) +{ + ACE::HTBP::Filter *filter = 0; + if (inside) + ACE_NEW_RETURN (filter, + ACE::HTBP::Inside_Squid_Filter (),0); + else + ACE_NEW_RETURN (filter, + ACE::HTBP::Outside_Squid_Filter (),0); + return filter; +} + +int +ACE::HTBP::Filter_Factory::init (int /* argc */, + ACE_TCHAR * /* argv */ []) +{ + return 0; +} + +ACE_STATIC_SVC_DEFINE (ACE_HTBP_Filter_Factory, + ACE_TEXT ("Filter_Factory"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (ACE_HTBP_Filter_Factory), + ACE_Service_Type::DELETE_THIS | + ACE_Service_Type::DELETE_OBJ, + 0) + +ACE_FACTORY_NAMESPACE_DEFINE (HTBP, ACE_HTBP_Filter_Factory, + ACE::HTBP::Filter_Factory) + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Dynamic_Service<ACE::HTBP::Filter_Factory>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Dynamic_Service<ACE::HTBP::Filter_Factory> +#endif diff --git a/protocols/ace/HTBP/HTBP_Filter_Factory.h b/protocols/ace/HTBP/HTBP_Filter_Factory.h new file mode 100644 index 00000000000..84f32000664 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Filter_Factory.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +// $Id$ + +//============================================================================= +/** + * @file HTBP_Filter_Factory.h + * + * $Id$ + * + * @author Priyanka Gontla + */ +//============================================================================= + +#ifndef ACE_HTBP_FILTER_FACTORY +#define ACE_HTBP_FILTER_FACTORY +#include /**/ "ace/pre.h" + +#include "HTBP_Export.h" +#include "HTBP_Filter.h" +#include "ace/Service_Config.h" +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace ACE +{ + namespace HTBP + { + class Stream; + + /** + * @class Filter_Factory + * + * @brief Factory to get the Filters + * + * The Filter Factory is to be used for getting filters based on the + * mode requested. This class is a ACE_Service_Object and should be + * loadable with the help of the service configurator framework. + */ + class HTBP_Export Filter_Factory : public ACE_Service_Object + { + public: + + /// Constructor + Filter_Factory (); + + ~Filter_Factory (); + + /// Initialization hook. + virtual int init (int argc, ACE_TCHAR *argv[]); + + // + Filter *get_filter (int inside); + }; + } +} + +ACE_STATIC_SVC_DECLARE_EXPORT (HTBP, ACE_HTBP_Filter_Factory) +ACE_FACTORY_DECLARE (HTBP, ACE_HTBP_Filter_Factory) + + + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_FILTER_FACTORY */ diff --git a/protocols/ace/HTBP/HTBP_ID_Requestor.cpp b/protocols/ace/HTBP/HTBP_ID_Requestor.cpp new file mode 100644 index 00000000000..3c4b72e38fb --- /dev/null +++ b/protocols/ace/HTBP/HTBP_ID_Requestor.cpp @@ -0,0 +1,135 @@ +// $Id$ + +#include "HTBP_ID_Requestor.h" +#include "HTBP_Environment.h" + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/SOCK_Stream.h" +#include "ace/SOCK_Connector.h" +#include "ace/UUID.h" + +ACE_RCSID(HTBP, + ACE_HTBP_ID_Requestor, + "$Id$") + +ACE_TString ACE::HTBP::ID_Requestor::htid_; +ACE_SYNCH_MUTEX ACE::HTBP::ID_Requestor::htid_lock_; + +ACE::HTBP::ID_Requestor::ID_Requestor (ACE::HTBP::Environment *env) + : port_ (0), + host_ (), + url_() +{ + if (env) + { + env->get_htid_url(url_); + int via_proxy = 0; + env->get_htid_via_proxy (via_proxy); + if (via_proxy && env->get_proxy_host (host_) == 0) + env->get_proxy_port (port_); + } +} + +int +ACE::HTBP::ID_Requestor::connect_to_server (ACE_SOCK_Stream *cli_stream) +{ + if (port_ == 0 || host_.length() == 0) + { + int host_start = url_.find (ACE_TEXT("http://")) + 7; + int port_sep = 0; + int sep = 0; + if (host_start == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::ID_Requestor::") + ACE_TEXT("connect_to_server: ") + ACE_TEXT("invalid URL: \"%s\"\n"), + url_.c_str()), + -1); + port_sep = url_.find (ACE_TEXT(":"),(size_t)host_start); + sep = url_.find (ACE_TEXT("/"),(size_t)host_start); + if (sep == -1 || sep == host_start +1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::ID_Requestor::") + ACE_TEXT("connect_to_server: ") + ACE_TEXT("invalid URL: \"%s\"\n"), + url_.c_str()), + -1); + if (port_sep == -1) + { + port_sep = sep; + port_ = 80; // should be a default? + } + host_ = url_.substr(host_start,port_sep - host_start); + } + + ACE_INET_Addr remote_addr (port_, host_.c_str()); + ACE_SOCK_Connector con; + if (con.connect (*cli_stream, + remote_addr) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::ID_Requestor::connect_to_server: ") + ACE_TEXT("%p\n"), + ACE_TEXT("socket connect")), + -1); + return 0; +} + +int +ACE::HTBP::ID_Requestor::send_request (ACE_SOCK_Stream *cli_stream) +{ + char *buffer; + ACE_NEW_RETURN (buffer, char[this->url_.length()+16],-1); + ACE_OS::sprintf (buffer,"GET %s HTTP/1.0\n\n", + ACE_TEXT_ALWAYS_CHAR(url_.c_str())); + int result = cli_stream->send_n (buffer,ACE_OS::strlen(buffer)); + delete [] buffer; + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ACE::HTBP::ID_Requestor::send_request %p\n"), + ACE_TEXT("socket send")), -1); + return 0; +} + +ACE_TCHAR * +ACE::HTBP::ID_Requestor::get_HTID () +{ + if (ACE::HTBP::ID_Requestor::htid_.length() != 0) + return ACE::HTBP::ID_Requestor::htid_.rep(); + + ACE_Guard<ACE_SYNCH_MUTEX> guard (ACE::HTBP::ID_Requestor::htid_lock_); + + if (ACE::HTBP::ID_Requestor::htid_.length() != 0) + return ACE::HTBP::ID_Requestor::htid_.rep(); + + ACE_SOCK_Stream cli_stream; + ACE_TCHAR * htid = 0; + + if (this->url_.length() == 0 || + this->connect_to_server (&cli_stream) == -1 || + this->send_request (&cli_stream) == -1) + { + ACE_Utils::UUID_Generator gen; + ACE_Utils::UUID *uuid = gen.generateUUID (); + const ACE_CString *uuidstr = uuid->to_string(); + ACE::HTBP::ID_Requestor::htid_ = ACE_TEXT_CHAR_TO_TCHAR (uuidstr->c_str()); + delete uuid; + return ACE::HTBP::ID_Requestor::htid_.rep(); + } + iovec recv_buf; + ssize_t result = cli_stream.recvv (&recv_buf); + cli_stream.close(); + + if (result > 0) + { + ACE_CString answer ((char *)recv_buf.iov_base,recv_buf.iov_len); + ssize_t start = answer.rfind (ACE_TEXT('\n')); + if (start == ACE_CString::npos) + start = 0; + else + start++; + ACE::HTBP::ID_Requestor::htid_ = ACE_TEXT_CHAR_TO_TCHAR(answer.substr (start).c_str()); + htid = ACE::HTBP::ID_Requestor::htid_.rep(); + } + return htid; +} diff --git a/protocols/ace/HTBP/HTBP_ID_Requestor.h b/protocols/ace/HTBP/HTBP_ID_Requestor.h new file mode 100644 index 00000000000..e6cdd87fb1d --- /dev/null +++ b/protocols/ace/HTBP/HTBP_ID_Requestor.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +// $Id$ + +#ifndef HTID_REQUESTOR_H +#define HTID_REQUESTOR_H +#include /**/ "ace/pre.h" + +#include "HTBP_Export.h" +#include "ace/SString.h" +#include "ace/Synch.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Forward declarations +class ACE_SOCK_Stream; + +namespace ACE +{ + namespace HTBP + { + // Forward declarations + class Environment; + + /** + * ACE_HTBP_ID_Requestor + * + * @brief This singleton class is to be used to get a HTID + */ + class HTBP_Export ID_Requestor + { + public: + /// Constructor. + ID_Requestor (Environment * = 0); + + /// Accessor to HTID + ACE_TCHAR *get_HTID (); + + private: + /// Connects to the remote host + int connect_to_server (ACE_SOCK_Stream *cli_stream); + + /// Send HTTP GET request to the server. + int send_request (ACE_SOCK_Stream *cli_stream); + + unsigned port_; + ACE_TString host_; + ACE_TString url_; + + static ACE_TString htid_; + static ACE_SYNCH_MUTEX htid_lock_; + }; + + } +} +#include /**/ "ace/post.h" +#endif /* HTID_REQUESTOR_H */ diff --git a/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.cpp b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.cpp new file mode 100644 index 00000000000..b936cd8e580 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.cpp @@ -0,0 +1,227 @@ +// ACE_HTBP_Filter.cpp +// $Id$ + +#include "ace/Log_Msg.h" + +//#include <sstream> + +#include "HTBP_Session.h" +#include "HTBP_Inside_Squid_Filter.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Inside_Squid_Filter.inl" +#endif + +ACE_RCSID(HTBP,ACE_HTBP_Inside_Squid_Filter,"$ID:$") + +ssize_t +ACE::HTBP::Inside_Squid_Filter::send_data_trailer (ACE::HTBP::Channel *ch) +{ + ch->state(ACE::HTBP::Channel::Wait_For_Ack); + return 0; +} + +int +ACE::HTBP::Inside_Squid_Filter::make_request_header (ACE::HTBP::Channel *ch, + const char *cmd, + char *buffer, + size_t buffer_size) +{ + // the string is formatted as: + // command http://host:port/htid/sessionId/request<requestId>.html HTTP/1.1\n + // host:port is the remote host and port from the channel, + // htid is the local endpoint identifier + // sessionId is the discreet session counter between these peers + // requestId is the discreet request sent for this session. + + ACE::HTBP::Session *session = ch->session(); + + const char * format = "%shttp://%s:%d/%s/%d/request%d.html HTTP/1.1\n"; + char remote_host[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 1]; + unsigned remote_port = session->peer_addr().get_port_number(); + const char *local_htid = session->local_addr().get_htid(); + + ACE_UINT32 tempId = session->session_id().id_; + size_t sid_size = 1; + size_t rid_size = 1; + while (tempId /= 10) sid_size++; + tempId = ch->request_count(); + while (tempId /= 10) rid_size++; + + if (session->peer_addr().get_host_name(remote_host, + sizeof remote_host) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("HTBP::Inside_Squid_Filter:could not get ") + ACE_TEXT("peer_addr hostname\n")), + -1); + + + size_t size = + ACE_OS::strlen(format) + - 12 // subtract out the size of the format specifiers + + ACE_OS::strlen (cmd) + + ACE_OS::strlen (remote_host) + + 5 // maximum size for a the remote port number + + ACE_OS::strlen (local_htid) + + sid_size // size of session id + + rid_size; // size of request id + + if (size > buffer_size) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("HTBP::Inside_Squid_Filter: insufficient ") + ACE_TEXT("buffer space for request header, need %d ") + ACE_TEXT("got %d\n"), + size, buffer_size), + -1); + + ACE_OS::sprintf (buffer,format, + cmd,remote_host,remote_port, + local_htid, session->session_id().id_, + ch->request_count()); + + return ACE_OS::strlen(buffer); +} + +ssize_t +ACE::HTBP::Inside_Squid_Filter::send_data_header (ssize_t data_len, + ACE::HTBP::Channel *ch) +{ + char *buffer = new char[BUFSIZ]; + ssize_t result = -1; + if (this->make_request_header (ch,"POST ",buffer,BUFSIZ) != -1) + { + ACE_CString header (buffer); + header += "Content-Type: application/octet-stream\nContent-Length: "; + char datalenstr[20]; + ACE_OS::itoa (data_len,datalenstr,10); + header += datalenstr; + header += "\n\n"; + result = ch->ace_stream().send(header.c_str(),header.length()); + } + ch->state(result == -1 ? ACE::HTBP::Channel::Closed : + ACE::HTBP::Channel::Header_Sent); + this->reset_http_code(); + return 1; +} + +ssize_t +ACE::HTBP::Inside_Squid_Filter::recv_data_header (ACE::HTBP::Channel *ch) +{ + if (this->http_code() != 200 && this->http_code() != 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("Inside_Squid_Filter::recv_data_header, ") + ACE_TEXT("non-OK result code %d recvd\n"), + this->http_code())); + + errno = ch->consume_error () ? EINVAL : EWOULDBLOCK; + return 0; + } + char *header_end = this->header_complete(ch); + if (header_end == 0) + { + if (ch->state() != ACE::HTBP::Channel::Closed) + { + ch->state (ACE::HTBP::Channel::Header_Pending); + errno = EWOULDBLOCK; + } + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Inside_Squid_Filter::recv_data_header, ") + ACE_TEXT("header not complete\n")), + 0); + } + char *start = ch->leftovers().rd_ptr(); + ACE_CString token = "Content-Length: "; + char *tpos = ACE_OS::strstr(start,token.c_str()); + char *nl = ACE_OS::strchr (start,'\n'); + if (tpos != 0) + { + tpos += token.length(); + *nl = 0; + ch->data_len (strtol(tpos,0,10)); + start = nl+1; + } + + ch->leftovers().rd_ptr(header_end); + if (this->http_code() != 200) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("Inside_Squid_Filter::recv_data_header, ") + ACE_TEXT("non-OK result code %d recvd\n"), + this->http_code())); + + errno = ch->consume_error () ? EINVAL : EWOULDBLOCK; + return 0; + } + + ch->state(ACE::HTBP::Channel::Data_Queued); + return 1; +} + +ssize_t +ACE::HTBP::Inside_Squid_Filter::recv_data_trailer (ACE::HTBP::Channel *ch) +{ + ch->state(ACE::HTBP::Channel::Send_Ack); + return 0; +} + +int +ACE::HTBP::Inside_Squid_Filter::send_ack (ACE::HTBP::Channel *ch) +{ + char *buffer = new char[BUFSIZ]; + ssize_t result = -1; + if (ch->state() == ACE::HTBP::Channel::Ack_Sent) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Inside Filter::send_ack: ") + ACE_TEXT("state is already ACK_SENT\n")), + 1); + } + if (this->make_request_header (ch,"GET ",buffer,BUFSIZ) != -1) + { + ACE_CString header (buffer); + header += "\n"; + result = ch->ace_stream().send(header.c_str(),header.length()); + } + ch->state(result == -1 ? + ACE::HTBP::Channel::Closed : ACE::HTBP::Channel::Ack_Sent); + this->reset_http_code(); + return 1; +} + +int +ACE::HTBP::Inside_Squid_Filter::recv_ack (ACE::HTBP::Channel *ch) +{ + + char *header_end = this->header_complete(ch); + if (header_end == 0) + { + if (ch->state() != ACE::HTBP::Channel::Closed) + errno = EWOULDBLOCK; + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Inside_Squid_Filter::recv_data_header, ") + ACE_TEXT("header not complete\n")),0); + } + if (this->http_code() == 200) + { + ch->leftovers().length(0); + ch->state(ACE::HTBP::Channel::Ready); + return 1; + } + + char *start = ch->leftovers().rd_ptr(); + ACE_CString token = "Content-Length: "; + char *tpos = ACE_OS::strstr(start,token.c_str()); + char *nl = ACE_OS::strchr (start,'\n'); + if (tpos != 0) + { + tpos += token.length(); + *nl = 0; + ch->data_len (strtol(tpos,0,10)); + start = nl+1; + } + + ch->leftovers().rd_ptr(header_end); + errno = ch->consume_error () ? EINVAL : EWOULDBLOCK; + return 0; +} diff --git a/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.h b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.h new file mode 100644 index 00000000000..142607aa49f --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.h @@ -0,0 +1,87 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Inside_Squid_Filter.h + * + * $Id$ + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_HTBP_INSIDE_SQUID_FILTER_H +#define ACE_HTBP_INSIDE_SQUID_FILTER_H +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" +#include "HTBP_Filter.h" + +namespace ACE +{ + namespace HTBP + { + + /** + * @class Inside_Squid_Filter + * + * @brief Defines the methods in the <Filter> abstraction. + * + * A filter is responsible for wrapping / unwrapping messages + * depending on direction of flow on each stream. There will be 4 + * filters participating in a session, inside-send, inside-recv, + * outside-send, ouside-recv. It is anticipated that specialized + * filters will be implemented that tune the filter behavior based + * on proxy particulars. That, or there will be a matrix + * configuration parameters that may be tweeked to match the + * configuration. It remains to be seen which is easier to + * manage. + */ + class HTBP_Export Inside_Squid_Filter : public Filter + { + public: + /// Destructor. + virtual ~Inside_Squid_Filter (void); + + /// Inside and outside Send filters need to supply a data header + /// that sets the stage before sending the data body, and then + /// (maybe) send a data trailer that closes the message. The + /// data header may be formatted differently on the first + /// message, to send optional context information. + virtual ssize_t send_data_header (ssize_t data_len, Channel *); + virtual ssize_t send_data_trailer (Channel *); + + /// Upon receiving data, the Channel is obliged to send an + /// ack. This is either an empty document if this is the + /// in-to-out stream, or a new long-duration document request if + /// this is the out-to-in stream. + virtual int send_ack (Channel *); + virtual int recv_ack (Channel *); + + /// receiving data must compliment sending. In the case of an + /// in-to-out stream. It is possible that the stream identity is + /// not known until the first request is received. In this case + /// the filter will have to look lookup the received session ID + /// and either create a new instance or reassign itself to an + /// existing sesion. In that case, the associated stream will + /// have to be reassigned as well. + /// + virtual ssize_t recv_data_header (Channel *); + virtual ssize_t recv_data_trailer(Channel *); + private: + int make_request_header (Channel *, const char *, char *, size_t ); + + }; + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Inside_Squid_Filter.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_FILTER_H */ diff --git a/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.inl b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.inl new file mode 100644 index 00000000000..d9c4618537e --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Inside_Squid_Filter.inl @@ -0,0 +1,9 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE_HTBP_Inside_Squid_Filter.i + +ACE_INLINE +ACE::HTBP::Inside_Squid_Filter::~Inside_Squid_Filter (void) +{ +} diff --git a/protocols/ace/HTBP/HTBP_Macros.h b/protocols/ace/HTBP/HTBP_Macros.h new file mode 100644 index 00000000000..0cb1300cc1d --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Macros.h @@ -0,0 +1,10 @@ +// $Id$ + +#ifndef ACE_HTBP_MACROS_H +#define ACE_HTBP_MACROS_H + +#if !defined (ACE_HTBP_ENVIRONMENT_CONFIG_FILE) +#define ACE_HTBP_ENVIRONMENT_CONFIG_FILE "HT_Config.conf" +#endif /* ACE_HTBP_ENVIRONMENT_CONFIG_FILE */ + +#endif /* ACE_HTBP_MACROS_H */ diff --git a/protocols/ace/HTBP/HTBP_Notifier.cpp b/protocols/ace/HTBP/HTBP_Notifier.cpp new file mode 100644 index 00000000000..fab0dbd44ba --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Notifier.cpp @@ -0,0 +1,87 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Notifier.cpp + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= +#include "HTBP_Notifier.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Notifier.inl" +#endif + +#include "HTBP_Channel.h" +#include "HTBP_Session.h" +#include "ace/Reactor.h" + +ACE::HTBP::Notifier::Notifier (ACE::HTBP::Channel *s) + : channel_(s) +{ +} + +int +ACE::HTBP::Notifier::handle_input(ACE_HANDLE ) +{ + switch (this->channel_->state()) + { + case ACE::HTBP::Channel::Detached: + this->channel_->pre_recv(); + break; + case ACE::HTBP::Channel::Wait_For_Ack: + this->channel_->recv_ack(); + break; + default: + this->channel_->load_buffer(); + } + + if (this->channel_->state() == ACE::HTBP::Channel::Closed) + { + this->unregister(); + return 0; + } + + if (this->channel_->session_) + { + if (this->channel_ == this->channel_->session_->inbound()) + { + ACE_Event_Handler *h = this->channel_->session_->handler(); + if (h && this->reactor()) + this->reactor()->notify(h, + ACE_Event_Handler::READ_MASK); + else + ACE_DEBUG ((LM_DEBUG,"Notifier cannot notify, session has no handler (%x), or reactor (%x)\n",h,this->reactor())); + } + else + this->channel_->flush_buffer(); + } + else + ACE_DEBUG ((LM_DEBUG,"Notifier has no session to notify!\n")); + return 0; +} + +int +ACE::HTBP::Notifier::handle_output (ACE_HANDLE ) +{ + return -1; + +} + +void +ACE::HTBP::Notifier::unregister (void) +{ + if (this->reactor()) + this->reactor()->remove_handler(this, + ACE_Event_Handler::READ_MASK | + ACE_Event_Handler::DONT_CALL); +} + +ACE_HANDLE +ACE::HTBP::Notifier::get_handle(void) const +{ + return this->channel_->ace_stream().get_handle(); +} diff --git a/protocols/ace/HTBP/HTBP_Notifier.h b/protocols/ace/HTBP/HTBP_Notifier.h new file mode 100644 index 00000000000..24ff34b0d5e --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Notifier.h @@ -0,0 +1,54 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Notifier.h + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= + +#ifndef ACE_HTBP_NOTIFIER_H +#define ACE_HTBP_NOTIFIER_H +#include /**/ "ace/pre.h" + +#include "ace/Event_Handler.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" + +namespace ACE +{ + namespace HTBP + { + // Forward declarations. + class Channel; + + class HTBP_Export Notifier : public ACE_Event_Handler + { + public: + Notifier (Channel *ch); + int handle_input(ACE_HANDLE ); + int handle_output(ACE_HANDLE ); + + void unregister (void); + + ACE_HANDLE get_handle (void) const; + + private: + Channel *channel_; + }; + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Notifier.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_NOTIFIER_H */ diff --git a/protocols/ace/HTBP/HTBP_Notifier.inl b/protocols/ace/HTBP/HTBP_Notifier.inl new file mode 100644 index 00000000000..fec4c7f49c9 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Notifier.inl @@ -0,0 +1,4 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE_HTBP_Notifier.i diff --git a/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.cpp b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.cpp new file mode 100644 index 00000000000..3c035b8dcde --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.cpp @@ -0,0 +1,192 @@ +// ACE_HTBP_Outside_Squid_Filter.cpp +// $Id$ + +#include "ace/Log_Msg.h" + +#include "HTBP_Session.h" +#include "HTBP_Outside_Squid_Filter.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Outside_Squid_Filter.inl" +#endif + +ACE_RCSID(HTBP, + ACE_HTBP_Outside_Squid_Filter, + "$Id$") + +ssize_t +ACE::HTBP::Outside_Squid_Filter::recv_data_header (ACE::HTBP::Channel *ch) +{ + // on the outside of the firewall, this method must do the details + // necessary to call replace_session or whatever to migrate the sock + // stream to the appropriate ACE::HTBP::Channel, then to finally + // assign the right filter to that stream. That filter will an + // ACE::HTBP::Outside_[Send|Recv]_Filter. + + // in the case of an ACE::HTBP::Outside_Recv_Filter, the assigned + // filter must be a null filter first, with a replacement. + + // recv header details + char *header_end = this->header_complete(ch); + if (header_end == 0) + { + if (ch->state() != ACE::HTBP::Channel::Closed) + { + ch->state(ACE::HTBP::Channel::Header_Pending); + errno = EWOULDBLOCK; + } + return 0; + } + + char *start = ch->leftovers().rd_ptr(); + + int is_inbound = 0; + ACE_CString token ("POST "); + if (ACE_OS::strncmp (start,token.c_str(),token.length()) == 0) + is_inbound = 1; + else + { + token = "GET "; + if (ACE_OS::strncmp (start, + token.c_str(), + token.length()) != 0) + { + ch->leftovers().length(0); + errno = EINVAL; + ACE_ERROR_RETURN ((LM_ERROR, + "ACE::HTBP::Outside_Squid_Filter::recv_data_header " + "bad request header\n"),0); + } + } + start += token.length(); + // "http://" is stripped by squid, leaving only "/" + start += (ACE_OS::strncmp (start,"http://",7) == 0) ? 7 : 1; + + // set up the actual session and stream + ACE::HTBP::Session_Id_t session_id; + char * slash = ACE_OS::strchr(start,'/'); + char * nl = ACE_OS::strchr (start,'\n'); + if (slash == 0) + { + ch->leftovers().length(0); + errno = EINVAL; + ACE_ERROR_RETURN ((LM_ERROR, + "ACE::HTBP::Outside_Squid_Filter::recv_data_header " + "missing sender key\n"),0); + } + *slash = 0; + session_id.local_.string_to_addr (start); + start = slash+1; + + slash = ACE_OS::strchr(start,'/'); + if (slash == 0) + { + ch->leftovers().length(0); + errno = EINVAL; + ACE_ERROR_RETURN ((LM_ERROR, + "ACE::HTBP::Outside_Squid_Filter::recv_data_header " + "missing sender key\n"),0); + } + *slash = 0; + session_id.peer_.string_to_addr (start); + start = slash + 1; + + slash = ACE_OS::strchr(start,' '); + if (slash == 0) + { + ch->leftovers().length (0); + errno = EINVAL; + ACE_ERROR_RETURN ((LM_ERROR, + "ACE::HTBP::Outside_Squid_Filter::recv_data_header " + "missing sender key"),0); + } + *slash = 0; + session_id.id_ = strtol(start,0,10); + start = slash + 1; + + if (is_inbound) + { + token = "Content-Length: "; + char *tpos = ACE_OS::strstr(start,token.c_str()); + if (tpos != 0) + { + nl = ACE_OS::strchr(tpos,'\n'); + tpos += token.length(); + *nl = 0; + ch->data_len(strtol(tpos,0,10)); + start = nl+1; + } + } + ch->leftovers().rd_ptr(header_end); + + ACE::HTBP::Session *session = 0; + if (ACE::HTBP::Session::find_session (session_id, session) == -1) + { + ACE_NEW_RETURN (session, ACE::HTBP::Session (session_id), 0); + if (ACE::HTBP::Session::add_session (session) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ACE::HTBP::Outside_Squid_Filter::" + "recv_data_header %p", + "add_session"),0); + } + ch->session(session); + + if (is_inbound) + { + ch->state(ACE::HTBP::Channel::Data_Queued); + session->inbound (ch); + } + else + { + ch->state(ACE::HTBP::Channel::Ready); + session->outbound (ch); + } + return 1; +} + +ssize_t +ACE::HTBP::Outside_Squid_Filter::recv_data_trailer (ACE::HTBP::Channel *ch) +{ + ch->state(ACE::HTBP::Channel::Send_Ack); + return 1; +} + +int +ACE::HTBP::Outside_Squid_Filter::send_ack (ACE::HTBP::Channel *ch) +{ + this->send_data_header (0,ch); + if (ch->state() == ACE::HTBP::Channel::Header_Sent) + ch->state(ACE::HTBP::Channel::Detached); + return 1; +} + +ssize_t +ACE::HTBP::Outside_Squid_Filter::send_data_header (ssize_t data_len, + ACE::HTBP::Channel *ch) +{ + ACE_CString header ("HTTP/1.1 200 OK\n" + "Content-Type: application/octet-stream\n" + "Content-Length: "); + char datalenstr[20]; + ACE_OS::itoa (data_len,datalenstr,10); + header += datalenstr; + header += "\n\n"; + ssize_t result = ch->ace_stream().send(header.c_str(),header.length()); + ch->state(result == -1 ? + ACE::HTBP::Channel::Closed : ACE::HTBP::Channel::Header_Sent); + this->reset_http_code(); + return 1; +} + +ssize_t +ACE::HTBP::Outside_Squid_Filter::send_data_trailer (ACE::HTBP::Channel *ch) +{ + ch->state(ACE::HTBP::Channel::Detached); + return 1; +} + +int +ACE::HTBP::Outside_Squid_Filter::recv_ack (ACE::HTBP::Channel *) +{ + return 1; +} diff --git a/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.h b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.h new file mode 100644 index 00000000000..5f0c820fccd --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.h @@ -0,0 +1,82 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Outside_Squid_Filter.h + * + * $Id$ + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_HTBP_OUTSIDE_SQUID_FILTER_H +#define ACE_HTBP_OUTSIDE_SQUID_FILTER_H +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" +#include "HTBP_Filter.h" + +namespace ACE +{ + namespace HTBP + { + // Forward declarations + class Channel; + + /** + * @class Outside_Squid_Filter + * + * @brief Defines the methods in the <Filter> abstraction. + * + * A filter is responsible for wrapping / unwrapping messages depending on + * direction of flow on each stream. There will be 4 filters participating in + * a session, outside-send, outside-recv, outside-send, ouside-recv. It is + * anticipated that specialized filters will be implemented that tune the + * filter behavior based on proxy particulars. That, or there will be a matrix + * configuration parameters that may be tweeked to match the configuration. + * It remains to be seen which is easier to manage. + */ + class HTBP_Export Outside_Squid_Filter : public Filter + { + public: + /// Destructor. + virtual ~Outside_Squid_Filter (void); + + /// Outside and outside Send filters need to supply a data header that + /// sets the stage before sending the data body, and then (maybe) send a + /// data trailer that closes the message. The data header may be formatted + /// differently on the first message, to send optional context information. + virtual ssize_t send_data_header (ssize_t data_len, Channel *); + virtual ssize_t send_data_trailer (Channel *); + + /// Upon receiving data, the Channel is obliged to send an ack. This is + /// either an empty document if this is the in-to-out stream, or a new + /// long-duration document request if this is the out-to-in stream. + virtual int send_ack (Channel *); + virtual int recv_ack (Channel *); + + /// receiving data must compliment sending. In the case of an in-to-out + /// stream. It is possible that the stream identity is not known until the + /// first request is received. In this case the filter will have to look + /// lookup the received session ID and either create a new instance or + /// reassign itself to an existing sesion. In that case, the associated + /// stream will have to be reassigned as well. + /// + virtual ssize_t recv_data_header (Channel *); + virtual ssize_t recv_data_trailer(Channel *); + }; + + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Outside_Squid_Filter.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_OUTSIDE_FILTER_H */ diff --git a/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.inl b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.inl new file mode 100644 index 00000000000..351c6e53856 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Outside_Squid_Filter.inl @@ -0,0 +1,9 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE_HTBP_Outside_Squid_Filter.i + +ACE_INLINE +ACE::HTBP::Outside_Squid_Filter::~Outside_Squid_Filter (void) +{ +} diff --git a/protocols/ace/HTBP/HTBP_Session.cpp b/protocols/ace/HTBP/HTBP_Session.cpp new file mode 100644 index 00000000000..3aed6b14324 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Session.cpp @@ -0,0 +1,301 @@ +// SOCK_Stream.cpp +// $Id$ + +#include "ace/Log_Msg.h" + +#include "HTBP_Session.h" +#include "ace/SOCK_Connector.h" +#include "ace/Event_Handler.h" +#include "HTBP_Filter.h" +#include "HTBP_ID_Requestor.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Session.inl" +#endif + +ACE_RCSID(HTBP,ACE_HTBP_Session," $") + +ACE::HTBP::Session::Session_Map ACE::HTBP::Session::session_map_; +ACE_UINT32 ACE::HTBP::Session::last_session_id_ = 0; +ACE_SYNCH_MUTEX ACE::HTBP::Session::session_id_lock_; + +/// Static method definitions +ACE_UINT32 +ACE::HTBP::Session::next_session_id () +{ + ACE_Guard<ACE_SYNCH_MUTEX> g(ACE::HTBP::Session::session_id_lock_); + return ++last_session_id_; +} + +int +ACE::HTBP::Session::add_session (ACE::HTBP::Session *s) +{ + return session_map_.bind (s->session_id(),s); +} + +int +ACE::HTBP::Session::remove_session (ACE::HTBP::Session *s) +{ + if (session_map_.current_size() > 0) + return session_map_.unbind(s->session_id()); + return 0; +} + +int +ACE::HTBP::Session::find_session (const ACE::HTBP::Session_Id_t &sid, ACE::HTBP::Session *&out) +{ + ACE::HTBP::Session::Map_Entry *e; + if (session_map_.find (sid,e) == -1) + { + out = 0; + return -1; + } + out = e->int_id_; + return 0; +} + +//---------------------------------------------------------------------------- +ACE::HTBP::Session::Session (void) + : proxy_addr_ (0), + destroy_proxy_addr_ (0), + inbound_ (0), + outbound_ (0), + closed_ (0), + handler_ (0), + reactor_(0), + stream_ (0), + sock_flags_(0) +{ + ACE::HTBP::ID_Requestor req; + ACE_TCHAR * htid = req.get_HTID(); + session_id_.local_ = ACE_TEXT_ALWAYS_CHAR(htid); + delete[] htid; + session_id_.id_ = ACE::HTBP::Session::next_session_id(); + ACE_NEW (inbound_, ACE::HTBP::Channel (this)); + ACE_NEW (outbound_, ACE::HTBP::Channel (this)); +} + +ACE::HTBP::Session::Session (const ACE::HTBP::Addr &peer, + const ACE::HTBP::Addr &local, + ACE_UINT32 sid, + ACE_INET_Addr *proxy, + int take_proxy) + : proxy_addr_ (proxy), + destroy_proxy_addr_ (take_proxy), + inbound_ (0), + outbound_ (0), + closed_ (0), + handler_ (0), + reactor_(0), + stream_ (0), + sock_flags_(0) +{ + session_id_.peer_ = peer; + session_id_.local_ = local; + session_id_.id_ = (sid == 0) ? + ACE::HTBP::Session::next_session_id() : sid; + + ACE_NEW (inbound_,ACE::HTBP::Channel (this)); + ACE_NEW (outbound_,ACE::HTBP::Channel (this)); +} + +ACE::HTBP::Session::Session (const ACE::HTBP::Session_Id_t &id, + ACE_INET_Addr *proxy, + int take_proxy) + : proxy_addr_ (proxy), + destroy_proxy_addr_ (take_proxy), + session_id_(id), + inbound_ (0), + outbound_ (0), + closed_ (0), + handler_ (0), + reactor_ (0), + stream_ (0), + sock_flags_(0) +{ + ACE_NEW (inbound_, ACE::HTBP::Channel (this)); + ACE_NEW (outbound_, ACE::HTBP::Channel (this)); +} + +ACE::HTBP::Session::Session (const ACE::HTBP::Session &other) +{ + this->operator=(other); +} + +ACE::HTBP::Session& +ACE::HTBP::Session::operator= (const ACE::HTBP::Session &) +{ + ACE_ASSERT (this == 0); + return *this; +} + +ACE::HTBP::Session::~Session (void) +{ + if (destroy_proxy_addr_) + delete proxy_addr_; +} + +int +ACE::HTBP::Session::close (void) +{ + if (this->inbound_) + this->inbound_->close(); + if (this->outbound_) + this->outbound_->close(); + this->closed_= 1; + return ACE::HTBP::Session::remove_session (this); +} + + +ACE::HTBP::Channel * +ACE::HTBP::Session::outbound (void) const +{ + if (!this->closed_ && this->proxy_addr_) + ACE_const_cast(ACE::HTBP::Session *,this)->reconnect(); + if ( this->outbound_ == 0) + return 0; + ACE::HTBP::Channel::State s =this->outbound_->state(); + return s == ACE::HTBP::Channel::Init || s == ACE::HTBP::Channel::Ready ? this->outbound_ : 0; +} + +void +ACE::HTBP::Session::reconnect_i (ACE::HTBP::Channel *s) +{ + ACE_SOCK_Connector conn; + char host[100]; + this->proxy_addr_->get_host_name(host,100); + if (conn.connect (s->ace_stream(),*this->proxy_addr_) == -1) + { + ACE_TCHAR buffer[128]; + this->proxy_addr_->addr_to_string(buffer,128, 0); + ACE_ERROR ((LM_ERROR, + ACE_TEXT("ACE::HTBP::Session::reconnect failed to %s, %p\n"), + buffer, s == this->inbound_ ? + ACE_TEXT("inbound") : ACE_TEXT ("outbound"))); + } + s->register_notifier(this->reactor_); + if (s == this->inbound_) + s->send_ack(); +} + +ACE_Event_Handler * +ACE::HTBP::Session::handler (void) +{ + return this->handler_; +} + +void +ACE::HTBP::Session::handler (ACE_Event_Handler * h) +{ + this->handler_ = h; +} + +void +ACE::HTBP::Session::detach (ACE::HTBP::Channel *ch) +{ + if (this->inbound_ == ch) + this->inbound_ = 0; + else if (this->outbound_ == ch) + this->outbound_ = 0; + else + ACE_ERROR ((LM_ERROR, "ACE::HTBP::Session::detach called with unknown channel\n")); +} + +void +ACE::HTBP::Session::reactor (ACE_Reactor *r) +{ + this->reactor_ = r; + this->inbound_->register_notifier(r); + this->outbound_->register_notifier(r); +} + +int +ACE::HTBP::Session::enqueue (ACE_Message_Block *msg) +{ + this->outbound_queue_.enqueue_tail(msg); + return msg->length(); +} + +int +ACE::HTBP::Session::flush_outbound_queue (void) +{ + int result = 0; + if (this->outbound_queue_.message_count() > 0) + { + ACE_Message_Block *msg = 0; + iovec *iov = 0; + ACE_NEW_RETURN (iov, + iovec[this->outbound_queue_.message_count()], + -1); + this->outbound_queue_.peek_dequeue_head (msg); + for (int i = 0; i < this->outbound_queue_.message_count(); i++) + { + iov[i].iov_base = msg->rd_ptr(); + iov[i].iov_len = msg->length(); + msg = msg->next(); + } + result = this->outbound_->sendv (iov,this->outbound_queue_.message_count(),0); + delete [] iov; + while (this->outbound_queue_.dequeue_head(msg)) + msg->release(); + } + return result; +} + +int +ACE::HTBP::Session::close_inbound (void) const +{ + return this->inbound_ ? this->inbound_->close() : 0; +} + +int +ACE::HTBP::Session::close_outbound (void) const +{ + return this->outbound_ ? this->outbound_->close() : 0; +} + +int +ACE::HTBP::Session::enable (int flags) +{ + this->sock_flags_ |= flags; + int result = this->inbound_ ? this->inbound_->enable(flags) : 0; + result |= this->outbound_ ? this->outbound_->enable (flags) : 0; + return result; +} + +int +ACE::HTBP::Session::disable (int flags) +{ + this->sock_flags_ &= ~flags; + int result = this->inbound_ ? this->inbound_->disable(flags) : 0; + result |= this->outbound_ ? this->outbound_->disable (flags) : 0; + return result; +} + +ACE::HTBP::Stream * +ACE::HTBP::Session::stream (void)const +{ + return this->stream_; +} + +void +ACE::HTBP::Session::stream (ACE::HTBP::Stream *s) +{ + this->stream_ = s; +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Hash_Map_Manager_Ex<ACE::HTBP::Session_Id_t, ACE::HTBP::Session*, ACE_Hash<ACE::HTBP::Session_Id_t>,ACE_Equal_To<ACE::HTBP::Session_Id_t>,ACE_SYNCH_MUTEX>; +template class ACE_Hash_Map_Manager<ACE::HTBP::Session_Id_t, ACE::HTBP::Session*, ACE_SYNCH_MUTEX>; +template class ACE_Hash_Map_Entry<ACE::HTBP::Session_Id_t, ACE::HTBP::Session*>; +template class ACE_Hash<ACE::HTBP::Session_Id_t>; +template class ACE_Equal_To<ACE::HTBP::Session_Id_t>; + +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE::HTBP::Session_Id_t, ACE::HTBP::Session*, ACE_Hash<ACE::HTBP::Session_Id_t>,ACE_Equal_To<ACE::HTBP::Session_Id_t>,ACE_SYNCH_MUTEX> +#pragma instantiate ACE_Hash_Map_Manager <ACE::HTBP::Session_Id_t, ACE::HTBP::Session*, ACE_SYNCH_MUTEX> +#pragma instantiate ACE_Hash_Map_Entry <ACE::HTBP::Session_Id_t, ACE::HTBP::Session*> +#pragma instantiate ACE_Hash<ACE::HTBP::Session_Id_t>; + +#pragma instantiate ACE_Equal_To<ACE::HTBP::Session_Id_t> +#endif diff --git a/protocols/ace/HTBP/HTBP_Session.h b/protocols/ace/HTBP/HTBP_Session.h new file mode 100644 index 00000000000..9c162849215 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Session.h @@ -0,0 +1,193 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Session.h + * + * $Id$ + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_HTBP_SESSION_H +#define ACE_HTBP_SESSION_H +#include /**/ "ace/pre.h" + +#include "ace/SOCK_IO.h" +#include "ace/Hash_Map_Manager.h" +#include "ace/Synch.h" +#include "ace/Message_Queue.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Addr.h" +#include "HTBP_Export.h" +#include "HTBP_Channel.h" + +#include "HTBP_Stream.h" + +// Forward declarations. +class ACE_HTBP_Filter; +class ACE_Event_Handler; + +namespace ACE +{ + namespace HTBP + { + + class Session_Id_t + { + public: + ACE_UINT32 id_; + Addr local_; + Addr peer_; + + u_long hash () const; + bool operator ==(const Session_Id_t &other) const; + }; + + /** + * @class Session + * + * @brief Defines the methods in the <Session> abstraction. + * + * A session is an entity that combines two Ht_Channels that connect directly + * to a proxy to manage communication with a remote peer. The Session may + * persist longer than either stream, assuming that the proxy is libel to + * close a connection at any time. + * + * This means that the session needs to be able to reconnect to the remote + * peer. This also means that the session needs to be aware of its location + * If it is outside the proxy and looses a stream, oh well. If it is inside, + * then the next time a stream is required, then it must reconnect before + * returning the stream. + * + * The session does not queue outbound messages. That is going to be the + * responsibility of the application, or a higher level protocol wrapper. + */ + class HTBP_Export Session + { + public: + // Initialization and termination methods. + /// Constructor. + Session (void); + + /// Constructor (sets the underlying session id with <sid>). + Session (const Addr& peer, + const Addr& local, + ACE_UINT32 sid = 0, + ACE_INET_Addr *proxy = 0, + int take_proxy = 0); + Session (const Session_Id_t &id, + ACE_INET_Addr *proxy = 0, + int take_proxy = 0); + + Session (const Session &other); + Session& operator= (const Session &other); + + /// Destructor. + ~Session (void); + + /// The following methods are specific to the Session + static ACE_UINT32 next_session_id (); + + static int add_session (Session *); + static int remove_session (Session *); + static int find_session (const Session_Id_t&, + Session *&out); + + Stream *stream (void) const; + void stream (Stream *); + + int enqueue (ACE_Message_Block *msg); + int flush_outbound_queue (void); + + int close_inbound (void) const; + int close_outbound (void) const; + + /// get references to the actual streams based on the direction + /// of data flow if this session is on the inside of the proxy + /// ie, has a non-null proxy addr, then the inbound stream is + /// the out_to_in stream, otherwise it is the in_to_out + /// stream. The outbound is the opposite of the inbound. + /// Whenever an application wishes to send data, whether that is + /// request or reply data, it uses the outbound stream, and it + /// should associate an event handler with the inbound stream + /// for receiving data. + Channel *inbound (void) const; + Channel *outbound (void) const; + void inbound (Channel *); + void outbound (Channel *); + + int enable (int value); + int disable (int value); + + const Session_Id_t& session_id(void) const; + void session_id (ACE_UINT32 ); + + const ACE_INET_Addr *proxy_addr (void) const; + void proxy_addr (ACE_INET_Addr *, int destroy = 0); + + const Addr &peer_addr (void) const; + const Addr &local_addr (void) const; + + void peer_addr (const Addr &); + void local_addr (const Addr &); + + /// invoke close on both streams, then remove self from session map + int close (void); + + ACE_Event_Handler *handler (void); + void handler (ACE_Event_Handler *); + void reactor (ACE_Reactor *); + void detach (Channel *); + + int sock_flags(void) const; + + private: + /// Connected Stream ensures that the particular stream is + /// connected to the proxy, if possible. The result is same as + /// the reference passed in, so that it may be used inline for + /// the inboundor outbound methods + + void reconnect (); + void reconnect_i (Channel *); + + typedef ACE_Hash_Map_Manager<Session_Id_t, Session*, + ACE_SYNCH_MUTEX> Session_Map; + typedef ACE_Hash_Map_Entry <Session_Id_t, Session*> Map_Entry; + static Session_Map session_map_; + static ACE_UINT32 last_session_id_; + static ACE_SYNCH_MUTEX session_id_lock_; + + ACE_INET_Addr *proxy_addr_; + int destroy_proxy_addr_; + + Session_Id_t session_id_; + + Channel *inbound_; + Channel *outbound_; + + Filter *inbound_filter_; + Filter *outbound_filter_; + + int closed_; + + ACE_Event_Handler *handler_; + ACE_Reactor *reactor_; + + ACE_Message_Queue<ACE_SYNCH> outbound_queue_; + Stream * stream_; + int sock_flags_; + }; + } +} +#if defined (__ACE_INLINE__) +#include "HTBP_Session.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_SESSION_H */ diff --git a/protocols/ace/HTBP/HTBP_Session.inl b/protocols/ace/HTBP/HTBP_Session.inl new file mode 100644 index 00000000000..fb5c337826c --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Session.inl @@ -0,0 +1,109 @@ +/* -*- C++ -*- */ +// $Id$ + +ACE_INLINE +void +ACE::HTBP::Session::reconnect () +{ + if (!this->closed_ && this->proxy_addr_) + { + if (inbound_ && + inbound_->ace_stream().get_handle() == ACE_INVALID_HANDLE) + reconnect_i (inbound_); + if (outbound_ && + outbound_->ace_stream().get_handle() == ACE_INVALID_HANDLE) + reconnect_i (outbound_); + } +} + +ACE_INLINE +void +ACE::HTBP::Session::inbound (ACE::HTBP::Channel *s) +{ + this->inbound_ = s; +} + + +ACE_INLINE +void +ACE::HTBP::Session::outbound (ACE::HTBP::Channel *s) +{ + this->outbound_ = s; +} + +ACE_INLINE +ACE::HTBP::Channel * +ACE::HTBP::Session::inbound (void) const +{ + return this->inbound_; +} + +ACE_INLINE +const ACE::HTBP::Session_Id_t& +ACE::HTBP::Session::session_id(void) const +{ + return this->session_id_; +} + +// I'm wondering if this should be coupled with a map update...? +ACE_INLINE +void +ACE::HTBP::Session::session_id (ACE_UINT32 id) +{ + this->session_id_.id_ = id; +} + +ACE_INLINE +const ACE_INET_Addr * +ACE::HTBP::Session::proxy_addr (void) const +{ + return this->proxy_addr_; +} + +ACE_INLINE +const ACE::HTBP::Addr & +ACE::HTBP::Session::peer_addr (void) const +{ + return this->session_id_.peer_; +} + +ACE_INLINE +const ACE::HTBP::Addr & +ACE::HTBP::Session::local_addr (void) const +{ + return this->session_id_.local_; +} + +ACE_INLINE +void +ACE::HTBP::Session::proxy_addr (ACE_INET_Addr *pa, int destroy) +{ + if (this->destroy_proxy_addr_) + delete this->proxy_addr_; + this->proxy_addr_ = pa; + this->destroy_proxy_addr_ = destroy; +} + +ACE_INLINE +int +ACE::HTBP::Session::sock_flags (void) const +{ + return this->sock_flags_; +} + +//--------------------------------------------------------------------------- +ACE_INLINE +u_long +ACE::HTBP::Session_Id_t::hash () const +{ + return id_; // + local.hash() + peer.hash(); +} + +ACE_INLINE +bool +ACE::HTBP::Session_Id_t::operator ==(const ACE::HTBP::Session_Id_t &other) const +{ + return ((this->id_ == other.id_) && + (this->local_ == other.local_) && + (this->peer_ == other.peer_)); +} diff --git a/protocols/ace/HTBP/HTBP_Stream.cpp b/protocols/ace/HTBP/HTBP_Stream.cpp new file mode 100644 index 00000000000..ffbbb3b9d82 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Stream.cpp @@ -0,0 +1,330 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Stream.cpp + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= +#include "HTBP_Stream.h" + +#if !defined (__ACE_INLINE__) +#include "HTBP_Stream.inl" +#endif + +#include "HTBP_Session.h" +#include "HTBP_Filter_Factory.h" + +#include "ace/Message_Block.h" + + +// Initialization and termination methods. +/// Constructor. +ACE::HTBP::Stream::Stream (ACE::HTBP::Session *s) + : session_ (s) +{ + if (s == 0) + // create a temporary session to be replaced on first recv. + ACE_NEW (session_, ACE::HTBP::Session); + session_->stream (this); +} + +/// Destructor. +ACE::HTBP::Stream::~Stream (void) +{ +} + + /// Dump the state of an object. +void +ACE::HTBP::Stream::dump (void) const +{ +} + + + +//--------------------------------------------------------------------------- +// = I/O functions. + +/// Recv an <n> byte buffer from the connected socket. +ssize_t +ACE::HTBP::Stream::recv (void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) const +{ + if (this->session_->inbound() == 0) + { + errno = EWOULDBLOCK; + ACE_ERROR_RETURN ((LM_ERROR,"recv(buf,n,flags) called, but no " + "inbound channel connected to stream\n"),-1); + } + return this->session_->inbound()->recv(buf,n,flags,timeout); +} + + /// Recv an <n> byte buffer from the connected socket. +ssize_t +ACE::HTBP::Stream::recv (void *buf, + size_t n, + const ACE_Time_Value *timeout) const +{ + if (this->session_->inbound() == 0) + { + errno = EWOULDBLOCK; + ACE_ERROR_RETURN ((LM_ERROR,"recv(buf,n) called, but no " + "inbound channel connected to stream\n"),-1); + } + return this->session_->inbound()->recv(buf,n,timeout); +} + + /// Recv an <iovec> of size <n> from the connected socket. +ssize_t +ACE::HTBP::Stream::recvv (iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout) const +{ + if (this->session_->inbound() == 0) + { + errno = EWOULDBLOCK; + ACE_ERROR_RETURN ((LM_ERROR,"recv(iov,iovcnt) called, but no " + "inbound channel connected to stream\n"),-1); + } + return this->session_->inbound()->recvv(iov,iovcnt,timeout); +} + +ssize_t +ACE::HTBP::Stream::recvv (iovec *io_vec, + const ACE_Time_Value *timeout) const +{ + if (this->session_->inbound() == 0) + { + errno = EWOULDBLOCK; + ACE_ERROR_RETURN ((LM_ERROR,"recv(io_vec) called, but no " + "inbound channel connected to stream\n"),-1); + } + return this->session_->inbound()->recvv(io_vec,timeout); +} + +ssize_t +ACE::HTBP::Stream::recv (void *, + size_t, + ACE_OVERLAPPED *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: Asynch recv not supported\n"),-1); +} + +ssize_t +ACE::HTBP::Stream::send (const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) const +{ + if (this->session_->outbound() == 0) + { + ACE_Message_Block *msg = 0; + ACE_NEW_RETURN (msg,ACE_Message_Block(n),-1); + msg->copy ((const char *)buf,n); + // probably ought to separately enqueue the flags and put the data buf + // in a continuation message + // Also, the timeout poses another interesting problem. + return this->session_->enqueue(msg); + } + return this->session_->outbound()->send(buf,n,flags,timeout); +} + +ssize_t +ACE::HTBP::Stream::send (const void *buf, + size_t n, + const ACE_Time_Value *timeout) const +{ + if (this->session_->outbound() == 0) + { + ACE_Message_Block *msg = 0; + ACE_NEW_RETURN (msg,ACE_Message_Block(n),-1); + msg->copy ((const char *)buf,n); + return this->session_->enqueue(msg); + } + return this->session_->outbound()->send(buf,n,timeout); +} + +ssize_t +ACE::HTBP::Stream::sendv (const iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout) const +{ + if (this->session_->outbound() == 0) + { + ACE_Message_Block *msg = 0; + size_t total = 0; + int i = 0; + for (; i < iovcnt; i++) + total += iov[i].iov_len; + ACE_NEW_RETURN (msg,ACE_Message_Block(total),-1); + for (i = 0; i < iovcnt; i++) + msg->copy ((const char *)iov[i].iov_base,iov[i].iov_len); + return this->session_->enqueue(msg); + } + return this->session_->outbound()->sendv(iov,iovcnt,timeout); +} + +ssize_t +ACE::HTBP::Stream::send (const void *, + size_t , + ACE_OVERLAPPED *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: Asynch send not supported\n"),-1); +} + +ssize_t +ACE::HTBP::Stream::recv_n (void *, + size_t , + int , + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: recv_n not supported\n"),-1); +} + + /// Try to recv exactly <len> bytes into <buf> from the connected socket. +ssize_t +ACE::HTBP::Stream::recv_n (void *, + size_t , + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: recv_n not supported\n"),-1); +} + + /// Receive an <iovec> of size <iovcnt> from the connected socket. +ssize_t +ACE::HTBP::Stream::recvv_n (iovec [], + int , + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: recvv_n not supported\n"),-1); +} + + /// Try to send exactly <len> bytes from <buf> to the connection socket. +ssize_t +ACE::HTBP::Stream::send_n (const void *, + size_t , + int , + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: send_n not supported\n"),-1); +} + + /// Try to send exactly <len> bytes from <buf> to the connected socket. +ssize_t +ACE::HTBP::Stream::send_n (const void *, + size_t , + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: send_n not supported\n"),-1); +} + + /// Send all the <message_block>s chained through their <next> and + /// <cont> pointers. This call uses the underlying OS gather-write + /// operation to reduce the domain-crossing penalty. +ssize_t +ACE::HTBP::Stream::send_n (const ACE_Message_Block *, + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: send_n not supported\n"),-1); +} + + /// Send an <iovec> of size <iovcnt> to the connected socket. +ssize_t +ACE::HTBP::Stream::sendv_n (const iovec [], + int, + const ACE_Time_Value *, + size_t *) const +{ + errno = ENOTSUP; + ACE_ERROR_RETURN ((LM_ERROR, "ACE::HTBP::Stream: sendv_n not supported\n"),-1); +} + +int +ACE::HTBP::Stream::close_reader (void) +{ + return this->session_->close_inbound(); +} + +int +ACE::HTBP::Stream::close_writer (void) +{ + return this->session_->close_outbound(); +} + +int +ACE::HTBP::Stream::close (void) +{ + return this->session_->close(); +} + +int +ACE::HTBP::Stream::enable (int value) const +{ + return this->session_->enable(value); +} + +int +ACE::HTBP::Stream::disable (int value) const +{ + return this->session_->disable(value); +} + +int +ACE::HTBP::Stream::get_local_addr (ACE::HTBP::Addr &local_addr) const +{ + local_addr = this->session_->local_addr (); + return 0; +} + +int +ACE::HTBP::Stream::get_remote_addr (ACE::HTBP::Addr &peer_addr) const +{ + peer_addr = this->session_->peer_addr(); + return 0; +} + +ACE::HTBP::Session * +ACE::HTBP::Stream::session (void) const +{ + return this->session_; +} + +void +ACE::HTBP::Stream::session (ACE::HTBP::Session *s) +{ + delete this->session_; + this->session_ = s; + s->stream (this); +} + + +ACE_HANDLE +ACE::HTBP::Stream::get_handle (void) const +{ + return ACE_INVALID_HANDLE; +} + +void +ACE::HTBP::Stream::set_handle (ACE_HANDLE ) +{ + // no-op +} diff --git a/protocols/ace/HTBP/HTBP_Stream.h b/protocols/ace/HTBP/HTBP_Stream.h new file mode 100644 index 00000000000..c627f5ef6a5 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Stream.h @@ -0,0 +1,291 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file HTBP_Stream.h + * + * $Id$ + * + * @author Phil Mesnier, Priyanka Gontla + */ +//============================================================================= + +#ifndef ACE_HTBP_STREAM_H +#define ACE_HTBP_STREAM_H +#include /**/ "ace/pre.h" + +#include "ace/SOCK_Stream.h" +#include "ace/Message_Block.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "HTBP_Export.h" +#include "HTBP_Addr.h" +#include "HTBP_Filter.h" +#include "HTBP_Notifier.h" + +namespace ACE +{ + namespace HTBP + { + // Forward declarations. + class Session; + + /** + * @class Stream + * + * @brief A stream facade for the HTTP Tunneling Bidirectional Protocol + * + * This adds provides the common interface for applications to do + * I/O that ultimately is wrapped in HTTP for tunneling through + * firewalls. + * + * This class is modelled after the ACE_SOCK_Stream class, and + * provides all of the I/O methods available in that class. Since + * this is a facade, it does not derive from ACE_SOCK_Stream. It + * also does not provide the same performance as ACE_SOCK_Stream, + * as some data may have to be stored by the HTBP classes prior to + * transmission. + * + * <buf> is the buffer to write from or receive into. + * <len> is the number of bytes to transfer. + * The <timeout> parameter in the following methods indicates how + * long to blocking trying to transfer data. If <timeout> == 0, + * then the call behaves as a normal send/recv call, i.e., for + * blocking sockets, the call will block until action is possible; + * for non-blocking sockets, EWOULDBLOCK will be returned if no + * action is immediately possible. + * If <timeout> != 0, the call will wait for data to arrive no longer + * than the relative time specified in *<timeout>. + * The "_n()" I/O methods keep looping until all the data has been + * transferred. These methods also work for sockets in non-blocking + * mode i.e., they keep looping on EWOULDBLOCK. <timeout> is used + * to make sure we keep making progress, i.e., the same timeout + * value is used for every I/O operation in the loop and the timeout + * is not counted down. + * The return values for the "*_n()" methods match the return values + * from the non "_n()" methods and are specified as follows: + * - On complete transfer, the number of bytes transferred is returned. + * - On timeout, -1 is returned, errno == ETIME. + * - On error, -1 is returned, errno is set to appropriate error. + * - On EOF, 0 is returned, errno is irrelevant. + * + * On partial transfers, i.e., if any data is transferred before + * timeout/error/EOF, <bytes_transferred> will contain the number of + * bytes transferred. + * Methods with <iovec> parameter are I/O vector variants of the I/O + * operations. + * Methods with the extra <flags> argument will always result in + * <send> getting called. Methods without the extra <flags> argument + * will result in <send> getting called on Win32 platforms, and + * <write> getting called on non-Win32 platforms. + */ + class HTBP_Export Stream + { + public: + // Initialization and termination methods. + /// Constructor. + Stream (Session *s = 0); + + /// Destructor. + ~Stream (void); + + // = I/O functions. + + /// The Stream is a sibling of the ACE_SOCK_IO class, rather + /// than a decendant. This is due to the requirement to wrap all + /// messages with an HTTP request or reply wrapper, and to send + /// application data in only one direction on one stream. + + /// Recv an <n> byte buffer from the connected socket. + ssize_t recv (void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout = 0) const; + + /// Recv an <n> byte buffer from the connected socket. + ssize_t recv (void *buf, + size_t n, + const ACE_Time_Value *timeout = 0) const; + + /// Recv an <iovec> of size <n> from the connected socket. + ssize_t recvv (iovec iov[], + int n, + const ACE_Time_Value *timeout = 0) const; + + /// Same as above. Deprecated. + ssize_t recv (iovec iov[], + size_t n, + const ACE_Time_Value *timeout = 0) const; + + /** + * Allows a client to read from a socket without having to + * provide a buffer to read. This method determines how much + * data is in the socket, allocates a buffer of this size, reads + * in the data, and returns the number of bytes read. The + * caller is responsible for deleting the member in the + * <iov_base> field of <io_vec> using delete [] + * io_vec->iov_base. + */ + ssize_t recvv (iovec *io_vec, + const ACE_Time_Value *timeout = 0) const; + + /// Recv <n> bytes via Win32 <ReadFile> using overlapped I/O. + ssize_t recv (void *buf, + size_t n, + ACE_OVERLAPPED *overlapped) const; + + /// Send an <n> byte buffer to the connected socket. + ssize_t send (const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout = 0) const; + + /// Send an <n> byte buffer to the connected socket. + ssize_t send (const void *buf, + size_t n, + const ACE_Time_Value *timeout = 0) const; + + /// Send an <iovec> of size <n> to the connected socket. + ssize_t sendv (const iovec iov[], + int n, + const ACE_Time_Value *timeout = 0) const; + + /// Send <n> bytes via Win32 <WriteFile> using overlapped I/O. + ssize_t send (const void *buf, + size_t n, + ACE_OVERLAPPED *overlapped) const; + + + /// Try to recv exactly <len> bytes into <buf> from the + /// connected socket. + ssize_t recv_n (void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Try to recv exactly <len> bytes into <buf> from the + /// connected socket. + ssize_t recv_n (void *buf, + size_t len, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Receive an <iovec> of size <iovcnt> from the connected + /// socket. + ssize_t recvv_n (iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Try to send exactly <len> bytes from <buf> to the connection + /// socket. + ssize_t send_n (const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Try to send exactly <len> bytes from <buf> to the connected + /// socket. + ssize_t send_n (const void *buf, + size_t len, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Send all the <message_block>s chained through their <next> + /// and <cont> pointers. This call uses the underlying OS + /// gather-write operation to reduce the domain-crossing + /// penalty. + ssize_t send_n (const ACE_Message_Block *message_block, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + /// Send an <iovec> of size <iovcnt> to the connected socket. + ssize_t sendv_n (const iovec iov[], + int iovcnt, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + + // = Selectively close endpoints. / Close down the reader. + int close_reader (void); + + /// Close down the writer. + int close_writer (void); + + /** + * Close down the socket (we need this to make things work correctly + * on Win32, which requires use to do a <close_writer> before doing + * the close to avoid losing data). + */ + int close (void); + + // = Meta-type info + typedef Addr PEER_ADDR; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + public: + ///@notes Added the following methods to continue with + /// current compilation of HTIOP. Might not be needed in + /// future. - Priyanka + /// {@ + void set_handle (ACE_HANDLE h); + ACE_HANDLE get_handle (void) const; + + Session *session (void) const; + void session (Session *s); + + /** + * Enable asynchronous I/O (ACE_SIGIO), urgent data (ACE_SIGURG), + * non-blocking I/O (ACE_NONBLOCK), or close-on-exec (ACE_CLOEXEC), + * which is passed as the <value>. + */ + int enable (int value) const; + + /** + * Disable asynchronous I/O (ACE_SIGIO), urgent data (ACE_SIGURG), + * non-blocking I/O (ACE_NONBLOCK), or close-on-exec (ACE_CLOEXEC), + * which is passed as the <value>. + */ + int disable (int value) const; + + /** + * Return the address of the remotely connected peer (if there is + * one), in the referenced <ACE_Addr>. Returns 0 if successful, else + * -1. + */ + int get_remote_addr (Addr &) const; + + /** + * Return the address of the remotely connected peer (if there is + * one), in the referenced <ACE_Addr>. Returns 0 if successful, else + * -1. + */ + int get_local_addr (Addr &) const; + + //@} + + private: + /// The session_ is a reference to the persistent session this stream is + /// associated with. On the inside, sessions are created by the Connector, + /// which then create streams on demand. + Session *session_; + + }; + } +} + +#if defined (__ACE_INLINE__) +#include "HTBP_Stream.inl" +#endif + +#include /**/ "ace/post.h" +#endif /* ACE_HTBP_STREAM_H */ diff --git a/protocols/ace/HTBP/HTBP_Stream.inl b/protocols/ace/HTBP/HTBP_Stream.inl new file mode 100644 index 00000000000..489ed1d91b5 --- /dev/null +++ b/protocols/ace/HTBP/HTBP_Stream.inl @@ -0,0 +1,4 @@ +/* -*- C++ -*- */ +// $Id$ + +// ACE_HTBP_Stream.i diff --git a/protocols/ace/HTBP/HTID_Generator.cgi b/protocols/ace/HTBP/HTID_Generator.cgi new file mode 100644 index 00000000000..0d57a552d6c --- /dev/null +++ b/protocols/ace/HTBP/HTID_Generator.cgi @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +# This is a sample script that may be used to create domain specific +# unique ID's rather than using UUID. In a typical scenario, this HTID +# generator would reside in the same domain as the target server, so +# that it could be used by any clients of the server. While use of UUID +# as a unique identifier is perfectly fine, use of a remote generator +# gives additional benefits, such as the ability to collect metrics on +# identity requestors. + +print "Content-type:text/html\n\n"; + +$htid = $ENV{'REMOTE_ADDR'}; + +open(IN,"counts.txt") or dienice("Can't open counts.txt for writing: $!"); + +flock(IN,2); # lock the file +seek(IN,0,0); # rewind it to the beginning + +$oldtimestamp = <IN>; # read only the first line. +$save_time = $oldtimestamp; + +close(IN); + + +$timestamp = time; + +if ($oldtimestamp == $timestamp) + { + open (IN2, "sec_id.txt") or + dienice ("Can't open sec_id.txt for writing: $!"); + + flock (IN2, 2); + seek (IN2, 0, 0); + + $secondary_id = <IN2>; + + # increment the secondary id + ++$secondary_id; + + + close (IN2); + } +else { + + $secondary_id = 0; +} + + open(OUT2,">sec_id.txt") or + dienice("Can't open outdata.txt for writing: $!"); + + flock(OUT2,2); # lock the file + seek(OUT2,0,0); # rewind it to the beginning + + print OUT2 "$secondary_id"; + + close(OUT2); + + +#save the timestamp for next time +$oldtimestamp = $timestamp; + + +open(OUT,">counts.txt") or dienice("Can't open outdata.txt for writing: $!"); + +flock(OUT,2); # lock the file +seek(OUT,0,0); # rewind it to the beginning +print OUT "$oldtimestamp\n"; +close(OUT); + + +$result_string = join (".$timestamp", $htid, ".$secondary_id"); + +print <<EndOfHTML; + +$result_string + +EndOfHTML diff --git a/protocols/ace/HTBP/README b/protocols/ace/HTBP/README new file mode 100644 index 00000000000..577aaf15866 --- /dev/null +++ b/protocols/ace/HTBP/README @@ -0,0 +1,186 @@ +// $Id$ + +This directory contains the HTTP Tunneling, Bidirectional, Protocol +implementation. This is a new streaming abstraction layered over an +HTTP document request/reply mechanism. It is designed to allow clients +that are inside a of a corporate firewall to communicate with servers +that are outside, hence HTTP Tunneling. Also, once a connection is +established, the outside peer is able to send asynchronous messages to +the inside peer, hence Bidirectional. + +HTBP provides Acceptor, Connector, and Stream classes that follow the +interface defined for the ACE_Acceptor and ACE_Connector +templates. This means that HTBP can be used right away with +applications designed to use these templates. + +Bidirectionality is achieved in the context of the proxy's restriction +by using two channels between the peers. One channel is defined for +data flow from the inside to the outside, data flow from the outside +in occurs on the other channel. In-to-out data is passed in the form +of a PUT command with the data payload marshalled into an +"application/gzip" buffer. On this channel, the outside peer always +responds with a simple document which serves as an ack. On the +out-to-in channel, the inside client must send a token request in the +form of a GET command. This request goes unfulfilled until the outside +peer has data to send, which it does by supplying an HTML document +that again encapsulates the data so that it may pass through the proxy +uncorrupted. + +The connections from the inside peer to the proxy, or from the proxy +to the outside peer may be closed by the proxy at any time. The inside +peer will automatically reconnect as needed when this happens. Since +the outside peer cannot actively connect to the proxy, it will queue +outbound messages as long as it can until a new out-to-in channel is +made available, at which time it will flush its queue. The sense of +channels may change over time, as the proxy may choose any local +connection to the server to send any request (GET or POST). + +The outside peer is identified using an ordinary INET addr, however +the inside peer uses a simple, transient unique ID to identify +itself. Inside peers will never have any type of persistent identity. +The unique ID used to identify the inside peer is usually a UUID value +as composed by ACE_UUID_Generator. However, a domain based unique ID +may also be obtainedusing HTBP::ID_Requestor::get_HTID(). If no domain +based ID generator is configured, get_HTID() will return a UUID value. + +As there are a variety of HTTP proxies available, HTBP uses a +pluggable filter class that defines the particular characteristics of +a proxy and is responsible for marshalling and unmarshalling binary +data. As of now there is a single filter available that works with a +defaulted Squid proxy and may also be used as a null filter, directly +connecting the inside and outside peers. This mode is useful for +testing. + +CONFIGURING HTBP +This is done through the ACE_Configuration framework. On windows +platforms, the Windows Registry may be used, whereas on non-windows, a +flat file is used to configure. Configuration data may also be +persisted in a memory mapped file. + +The configuration map contains a single section, HTBP, that contains +all the configurable parameters in name=value form. The following is +an example of a configuration file: + +[htbp] +proxy_host=<hostname> This is the hostname of the http + proxy through which all requests + will be sent. +proxy_port=<port> This is the proxy's port. +htid_url=<url> If a domain based unique id is + required, this is the URL of the + ID generator. +htid_via_proxy=<1|0> If the htid_url must be reached + via the proxy, set this to 1. + Default is 0, meaning the ID + generator is directly accessible. + +COMPANION DIRECTORIES: +$ACE_ROOT/tests/HTBP. These are the test drivers, which + also serve as example code. +$TAO_ROOT/orbsvcs/orbsvcs/HTIOP This is a TAO pluggable protocol + based on HTBP. +$TAO_ROOT/orbsvcs/tests/HTIOP The tests for HTIOP. + + +BACKGROUND INFORMATION + +HT Addresses + +The class HT_Addr is a subclass of ACE_INET_Addr class. The interface +for the HT_Addr is a common interface to be used with the inside and +outside peers. The inside peer is identified by a HTID while the +outside peer is identified with an ip address. Constructors are +provided to initialize the inside and outside peers in addition to the +default and copy constructors. addr_to_string and string_to_addr +methods from the base class are overridden to help convert the HT_Addr +to a string and vice versa. Finally, the class provides accessor +methods for the default local address and the default proxy addresses. + +The local address is the address of the inside peer and is obtained +using the singleton HTID_Requestor class. The HTID_Requestor class +sends a request to the web server that is running at the htid_url to +get the HTID unique to each inside peer. + +The proxy address is of ACE_INET_Addr type as it is no different to a +regular server. It is obtained using the singleton HT_Environment +class. The HT_Environment class helps read the HT configuration file +and provides acccessors to the proxy address, port and the htid url. + +The code below illustrates the initialization of a local or inside, +remote or outside and the proxy addresses using the classes +aforementioned. + + HT_Addr local(HTID_REQUESTOR::instance()->get_HTID()); + + char hostname [1000]; + if (ACE_OS::hostname (hostname, + 1000) == -1) + { + ACE_DEBUG ((LM_DEBUG, "Could not get the host name\n")); + return -1; + } + + HT_Addr remote (8088, hostname); + + char proxy_address [1000]; + HT_ENVIRONMENT::instance ()->get_proxy_address (proxy_address); + + unsigned int proxy_port; + HT_ENVIRONMENT::instance ()->get_proxy_port (proxy_port); + + ACE_INET_Addr proxy(port, proxy_address); + + +HT Streams + +The class HT_Stream is a sibling of the ACE_SOCK_IO class. It is used +to send and receive messages between two peers identified by their HT +addresses. It is made a sibling of the ACE_SOCK_IO class rather than +a decendant. This is due to the requirement in the HTBP protocol to +wrap all messages with an HTTP request or reply wrapper, and to send +application data in only one direction on one stream. + +HT Sessions + +A session is an entity that combines two HT_Streams that connect +directly to a proxy to manage communication with a remote peer. The +session may persist longer than either stream, assuming that the proxy +is libel to close a connection at any time. This means that the +session needs to be able to reconnect to the remote peer. This also +means that the session needs to be aware of its location. If it is +outside the proxy and looses a stream, nothing can really be done. If +it is inside, then the next time a stream is required, then it must +reconnect before returning the stream. The session does not queue +outbound messages. It will be the responsibility of the application or +a higher level protocol wrapper. + +Each session is identified by a special type, +HT_Session_Id_t. HT_Session_Id_t is a class with three members, the +local address, the peer address and an id of type ACE_UINT32. A +session map, .... + +Besides the default constructor and copy constructors, two other +constructors are provided to initialize a session and are shown below. + + + /// Constructor (sets the underlying session id with <sid>). + HT_Session (const HT_Addr& peer, + const HT_Addr& local = HT_Addr::default_local(), + ACE_UINT32 sid = 0, + ACE_INET_Addr *proxy = 0, + int take_proxy = 0); + + HT_Session (const HT_Session_Id_t &id, + ACE_INET_Addr *proxy = 0, + int take_proxy = 0); + + + +If a session id (sid) is not provided by the user, it is generated +using the static method HT_Session::next_session_id(). + +The following code illustrates the usage of HT_Stream and HT_Session +classes. + +HT_Filters +<TBD> |