ACE_SSL_Asynch_Stream Class Reference

This class is a factory for initiating asynchronous reads and writes on an SSL stream. More...

#include <SSL_Asynch_Stream.h>

Collaboration diagram for ACE_SSL_Asynch_Stream:

Collaboration graph
[legend]
List of all members.

Public Types

enum  Stream_Type { ST_CLIENT = 0x0001, ST_SERVER = 0x0002 }

Public Member Functions

 ACE_SSL_Asynch_Stream (Stream_Type s_type=ST_SERVER, ACE_SSL_Context *context=0)
 Constructor.

virtual ~ACE_SSL_Asynch_Stream (void)
 Destructor.

int cancel (void)
int close (void)
int open (ACE_Handler &handler, ACE_HANDLE handle=ACE_INVALID_HANDLE, const void *completion_key=0, ACE_Proactor *proactor=0)
int read (ACE_Message_Block &message_block, size_t num_bytes_to_read, const void *act=0, int priority=0, int signal_number=ACE_SIGRTMIN)
int write (ACE_Message_Block &message_block, size_t bytes_to_write, const void *act=0, int priority=0, int signal_number=ACE_SIGRTMIN)

Protected Types

enum  Stream_Flag {
  SF_STREAM_OPEN = 0x0001, SF_REQ_SHUTDOWN = 0x0002, SF_SHUTDOWN_DONE = 0x0004, SF_CLOSE_NTF_SENT = 0x0008,
  SF_DELETE_ENABLE = 0x0010
}
 Stream state/flags. More...

enum  BIO_Flag { BF_EOS = 0x01, BF_AIO = 0x02 }

Protected Member Functions

virtual ACE_Asynch_Operation_Impl * implementation (void) const
virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
 virtual from ACE_Handler

virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
virtual void handle_wakeup (void)
void print_error (int err_ssl, const ACE_TCHAR *pText)
int pending_BIO_count (void)
int notify_read (int bytes_transferred, int error)
int notify_write (int bytes_transferred, int error)
int notify_close (void)
SSL State Machine
int do_SSL_state_machine (void)
int do_SSL_handshake (void)
int do_SSL_read (void)
int do_SSL_write (void)
int do_SSL_shutdown (void)
BIO Helpers
int ssl_bio_read (char *buf, size_t len, int &errval)
int ssl_bio_write (const char *buf, size_t len, int &errval)

Protected Attributes

Stream_Type type_
 Stream Type ST_CLIENT/ST_SERVER.

ACE_HANDLE handle_
 The real file/socket handle.

ACE_Proactorproactor_
 The proactor.

ACE_Handler * ext_handler_
 External,i.e user handler.

ACE_SSL_Asynch_Read_Stream_Resultext_read_result_
 External, i.e. read result faked for user.

ACE_SSL_Asynch_Write_Stream_Resultext_write_result_
 External, i.e. write result faked for user.

int flags_
SSL * ssl_
 The SSL session.

BIO * bio_
 The BIO implementation.

ACE_SYNCH_MUTEX mutex_
 Mutex to protect work.

Internal stream, buffer and info for BIO read
ACE_Asynch_Read_Stream bio_istream_
ACE_Message_Block bio_inp_msg_
int bio_inp_errno_
int bio_inp_flag_
Internal stream, buffer and info for BIO write
ACE_Asynch_Write_Stream bio_ostream_
ACE_Message_Block bio_out_msg_
int bio_out_errno_
int bio_out_flag_

Private Member Functions

 ACE_SSL_Asynch_Stream (ACE_SSL_Asynch_Stream const &)
ACE_SSL_Asynch_Streamoperator= (ACE_SSL_Asynch_Stream const &)

Friends

struct ACE_SSL_Asynch_Stream_Accessor

Detailed Description

This class is a factory for initiating asynchronous reads and writes on an SSL stream.

Once open() is called, multiple asynchronous read and write operations can be started using this class. The handler object (derived from ACE_Handler) specified in open() will receive completion events for the operations initiated via this class.

Definition at line 144 of file SSL_Asynch_Stream.h.


Member Enumeration Documentation

enum ACE_SSL_Asynch_Stream::BIO_Flag [protected]
 

The real streams which work under the ssl connection. BIO performs I/O via this streams

Enumeration values:
BF_EOS  End of stream.
BF_AIO  Real AIO in progress.

Definition at line 385 of file SSL_Asynch_Stream.h.

00386     {
00387       /// End of stream
00388       BF_EOS   = 0x01,
00389       /// Real AIO in progress
00390       BF_AIO   = 0x02
00391     };

enum ACE_SSL_Asynch_Stream::Stream_Flag [protected]
 

Stream state/flags.

Enumeration values:
SF_STREAM_OPEN  istream_ open OK
SF_REQ_SHUTDOWN  request to SSL shutdown
SF_SHUTDOWN_DONE  SSL shutdown finished.
SF_CLOSE_NTF_SENT  Close notification sent.
SF_DELETE_ENABLE  Stream can be safely destroyed.

Definition at line 361 of file SSL_Asynch_Stream.h.

00362     {
00363       /// istream_ open OK
00364       SF_STREAM_OPEN    = 0x0001,
00365       /// request to SSL shutdown
00366       SF_REQ_SHUTDOWN   = 0x0002,
00367       /// SSL shutdown finished
00368       SF_SHUTDOWN_DONE  = 0x0004,
00369       /// Close notification sent
00370       SF_CLOSE_NTF_SENT = 0x0008,
00371       /// Stream can be safely destroyed
00372       SF_DELETE_ENABLE  = 0x0010
00373     };

enum ACE_SSL_Asynch_Stream::Stream_Type
 

Enumeration values:
ST_CLIENT 
ST_SERVER 

Definition at line 162 of file SSL_Asynch_Stream.h.

00163     {
00164       ST_CLIENT = 0x0001,
00165       ST_SERVER = 0x0002
00166     };


Constructor & Destructor Documentation

ACE_SSL_Asynch_Stream::ACE_SSL_Asynch_Stream Stream_Type  s_type = ST_SERVER,
ACE_SSL_Context context = 0
 

Constructor.

  • context Pointer to an ACE_SSL_Context instance containing the OpenSSL information to be associated with this ACE_SSL_Asynch_Stream. The needed SSL data will be copied before return. Therefore, this object can be reused, modified, or deleted upon return. If a 0 pointer is passed, the ACE_SSL_Context::instance() method will be called to get access to a singleton.

Definition at line 91 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR, ACE_TEXT, ACE_TRACE, ACE_SSL_Context::context(), ACE_SSL_Context::instance(), LM_ERROR, and ssl_.

00094   : type_         (s_type),
00095     handle_       (ACE_INVALID_HANDLE),
00096     proactor_     (0),
00097     ext_handler_  (0),
00098     ext_read_result_ (0),
00099     ext_write_result_(0),
00100     flags_        (0),
00101     ssl_          (0),
00102     bio_          (0),
00103     bio_istream_  (),
00104     bio_inp_msg_  (),
00105     bio_inp_errno_(0),
00106     bio_inp_flag_ (0),
00107     bio_ostream_  (),
00108     bio_out_msg_  (),
00109     bio_out_errno_(0),
00110     bio_out_flag_ (0),
00111     mutex_ ()
00112 {
00113   ACE_TRACE ("ACE_SSL_Asynch_Stream::ACE_SSL_Asynch_Stream");
00114   // was honestly copied from ACE_SSL_SOCK_Stream :)
00115 
00116   ACE_SSL_Context * ctx =
00117     (context == 0 ? ACE_SSL_Context::instance () : context);
00118 
00119   this->ssl_ = ::SSL_new (ctx->context ());
00120 
00121   if (this->ssl_ == 0)
00122     ACE_ERROR
00123       ((LM_ERROR,
00124         ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00125         ACE_TEXT ("- cannot allocate new SSL structure")
00126      ));
00127 
00128 }

ACE_SSL_Asynch_Stream::~ACE_SSL_Asynch_Stream void   )  [virtual]
 

Destructor.

Definition at line 130 of file SSL_Asynch_Stream.cpp.

References ACE_DEBUG, ACE_TEXT, ACE_TRACE, LM_DEBUG, SF_DELETE_ENABLE, SF_STREAM_OPEN, and ssl_.

00131 {
00132   ACE_TRACE ("ACE_SSL_Asynch_Stream::~ACE_SSL_Asynch_Stream");
00133 
00134 
00135   // It is safe to delete stream if all notifications are received,
00136   // i.e., state is SF_DELETE_ENABLE or if proactor event loop is
00137   // done.
00138   if (this->flags_ & SF_STREAM_OPEN)             // open
00139     if ((this->flags_ & SF_DELETE_ENABLE) == 0)  // but ..
00140       ACE_DEBUG ((LM_DEBUG,
00141                   ACE_TEXT("ACE_SSL_Asynch_Stream::DTOR-")
00142                   ACE_TEXT("possible access violation ")
00143                   ACE_TEXT("if proactor still handles events\n")));
00144 
00145   ::SSL_free (this->ssl_);
00146 
00147   // Was honestly copied from ACE_SSL_SOCK_Stream :)
00148 
00149   // @@ Question: should we reference count the Context object or
00150   // leave that to the application developer? We do not reference
00151   // count reactors (for example) and following some simple rules
00152   // seems to work fine!
00153 }

ACE_SSL_Asynch_Stream::ACE_SSL_Asynch_Stream ACE_SSL_Asynch_Stream const &   )  [private]
 


Member Function Documentation

int ACE_SSL_Asynch_Stream::cancel void   ) 
 

Definition at line 187 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD_RETURN, ACE_SYNCH_MUTEX, bio_istream_, bio_ostream_, ERR_CANCELED, notify_read(), notify_write(), and SF_STREAM_OPEN.

00188 {
00189   ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1));
00190 
00191   if ((flags_ & SF_STREAM_OPEN) == 0) // not open
00192     return 1;   //   AIO_ALLDONE
00193 
00194   // attempt to cancel internal, i.e. user's read/write
00195   int rc_r_int = bio_istream_.cancel();
00196   int rc_w_int = bio_ostream_.cancel();
00197 
00198   // attempt to cancel external, i.e. bio_ssl read/write
00199   int rc_r_ext = notify_read (0, ERR_CANCELED);
00200   int rc_w_ext = notify_write (0, ERR_CANCELED);
00201 
00202   if (rc_r_int < 0  || rc_w_int < 0
00203       && rc_r_ext < 0  || rc_w_ext < 0)
00204     return -1;  // at least one error
00205 
00206   if (rc_r_int == 1 && rc_w_int == 1
00207       && rc_r_ext == 1 && rc_w_ext == 1)
00208     return 1;  // AIO_ALLDONE
00209 
00210   if (rc_r_int == 2 || rc_w_int == 2
00211       && rc_r_ext == 2 || rc_w_ext == 2)
00212     return 2;  // AIO_NOT_CANCELED , at least one not canceled
00213 
00214   return 0;    // AIO_CANCELED, at least will be one notification
00215 }

int ACE_SSL_Asynch_Stream::close void   ) 
 

Definition at line 165 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD_RETURN, ACE_SYNCH_MUTEX, do_SSL_state_machine(), SF_DELETE_ENABLE, SF_REQ_SHUTDOWN, and SF_STREAM_OPEN.

00166 {
00167   ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1));
00168 
00169   if ((flags_ & SF_STREAM_OPEN) == 0) // not open
00170     flags_ |= SF_DELETE_ENABLE;
00171 
00172   if (flags_ & SF_DELETE_ENABLE)
00173     return 0;
00174 
00175   flags_ |= SF_REQ_SHUTDOWN;
00176 
00177   this->do_SSL_state_machine ();
00178 
00179   return -1;
00180 }

int ACE_SSL_Asynch_Stream::do_SSL_handshake void   )  [protected]
 

Definition at line 482 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR_RETURN, ACE_TEXT, LM_ERROR, print_error(), SF_REQ_SHUTDOWN, ssl_, ST_CLIENT, and ST_SERVER.

Referenced by do_SSL_state_machine().

00483 {
00484   if (SSL_is_init_finished (this->ssl_))
00485     return 1;
00486 
00487   if (this->flags_ & SF_REQ_SHUTDOWN)
00488     return -1;
00489 
00490   int retval = -1;
00491 
00492   switch (this->type_)
00493     {
00494     case ST_CLIENT:
00495       retval = ::SSL_connect (this->ssl_);
00496       break;
00497 
00498     case ST_SERVER:
00499       retval = ::SSL_accept (this->ssl_);
00500       break;
00501 
00502     default:
00503       ACE_ERROR_RETURN
00504         ((LM_ERROR,
00505           ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00506           ACE_TEXT ("- invalid stream type")),
00507          -1);
00508     }
00509 
00510   int status = ::SSL_get_error (this->ssl_, retval);
00511 
00512   switch (status)
00513     {
00514     case SSL_ERROR_NONE:
00515       break;
00516 
00517     case SSL_ERROR_WANT_READ:
00518     case SSL_ERROR_WANT_WRITE:
00519     case SSL_ERROR_WANT_CONNECT:
00520     //case SSL_ERROR_WANT_ACCEPT:
00521     case SSL_ERROR_WANT_X509_LOOKUP:
00522       return 0;
00523 
00524     case SSL_ERROR_ZERO_RETURN:
00525     case SSL_ERROR_SYSCALL:
00526     default:
00527       this->print_error (status,
00528                          ACE_TEXT ("Handshake error"));
00529       return -1;
00530     }
00531 
00532   return 1;
00533 }

int ACE_SSL_Asynch_Stream::do_SSL_read void   )  [protected]
 

Definition at line 539 of file SSL_Asynch_Stream.cpp.

References ACE_TEXT, ERR_CANCELED, ext_read_result_, notify_read(), print_error(), SF_REQ_SHUTDOWN, ssl_, and ACE_Message_Block::wr_ptr().

Referenced by do_SSL_state_machine().

00540 {
00541   if (this->ext_read_result_ == 0)  // nothing to do
00542     return 0;
00543 
00544   if (this->flags_ & SF_REQ_SHUTDOWN)
00545     {
00546       this->notify_read (0, ERR_CANCELED);
00547       return -1;
00548     }
00549 
00550   ACE_Message_Block & mb = this->ext_read_result_->message_block ();
00551   size_t bytes_req = this->ext_read_result_->bytes_to_read ();
00552 
00553   ERR_clear_error();
00554 
00555   const int bytes_trn = ::SSL_read (this->ssl_,
00556                                     mb.wr_ptr (),
00557                                     bytes_req);
00558 
00559   int const status = ::SSL_get_error (this->ssl_, bytes_trn);
00560 
00561   switch (status)
00562     {
00563     case SSL_ERROR_NONE:
00564       this->notify_read (bytes_trn, 0);
00565       return 1;
00566 
00567     case SSL_ERROR_WANT_READ:
00568     case SSL_ERROR_WANT_WRITE:
00569       return 0;
00570 
00571     case SSL_ERROR_ZERO_RETURN:
00572       this->notify_read (0, 0);
00573       return 1;
00574 
00575     case SSL_ERROR_SYSCALL:
00576       if (bytes_trn == 0)
00577         {
00578           this->notify_read (0, 0);
00579           return 1;
00580         }
00581       // If not an EOF, then fall through to "default" case.
00582 
00583     default:
00584       break;
00585     }
00586 
00587  this->notify_read (0, EFAULT);
00588  this->print_error (status,
00589                     ACE_TEXT ("SSL_read error"));
00590 
00591  return -1;
00592 }

int ACE_SSL_Asynch_Stream::do_SSL_shutdown void   )  [protected]
 

Definition at line 431 of file SSL_Asynch_Stream.cpp.

References ACE_TEXT, ERR_CANCELED, notify_read(), notify_write(), print_error(), SF_REQ_SHUTDOWN, SF_SHUTDOWN_DONE, and ssl_.

Referenced by do_SSL_state_machine().

00432 {
00433   if (this->flags_ & SF_SHUTDOWN_DONE) // already done
00434     return 1;
00435 
00436   this->flags_ |= SF_REQ_SHUTDOWN;
00437 
00438   // if we have any uncompleted user requests
00439   // than cancel its
00440   this->notify_read  (0, ERR_CANCELED);
00441   this->notify_write (0, ERR_CANCELED);
00442 
00443   int retval = ::SSL_shutdown (this->ssl_);
00444 
00445   int status = ::SSL_get_error (this->ssl_, retval);
00446 
00447   switch (status)
00448     {
00449     case SSL_ERROR_NONE:
00450     case SSL_ERROR_ZERO_RETURN:
00451     case SSL_ERROR_SYSCALL:
00452       retval = 1;
00453       break;
00454 
00455     case SSL_ERROR_WANT_READ:
00456     case SSL_ERROR_WANT_WRITE:
00457     case SSL_ERROR_WANT_CONNECT:
00458     //   case SSL_ERROR_WANT_ACCEPT:
00459     case SSL_ERROR_WANT_X509_LOOKUP:
00460       return 0;
00461 
00462     default:
00463       this->print_error (status,
00464                          ACE_TEXT ("Shutdown error"));
00465       retval = -1;
00466       break;
00467     }
00468 
00469   this->flags_ |= SF_SHUTDOWN_DONE;
00470 
00471   return retval;
00472 }

int ACE_SSL_Asynch_Stream::do_SSL_state_machine void   )  [protected]
 

Definition at line 397 of file SSL_Asynch_Stream.cpp.

References do_SSL_handshake(), do_SSL_read(), do_SSL_shutdown(), do_SSL_write(), notify_close(), and SF_REQ_SHUTDOWN.

Referenced by close(), handle_read_stream(), handle_write_stream(), open(), read(), and write().

00398 {
00399   // this protected member should be called
00400   // with locked mutex_
00401 
00402   int retval = this->do_SSL_handshake ();
00403 
00404   if (retval == 0)          // handshake in progress ?
00405     return 0;
00406 
00407   if (retval < 0)
00408     this->flags_ |= SF_REQ_SHUTDOWN;
00409 
00410   this->do_SSL_read ();  // execute user read request
00411   this->do_SSL_write (); // execute user write request
00412 
00413   if ((this->flags_ & SF_REQ_SHUTDOWN) == 0)     // Do we have any errors
00414     return 0;
00415 
00416   this->do_SSL_shutdown ();
00417 
00418   this->notify_close ();
00419 
00420   return 0;
00421 }

int ACE_SSL_Asynch_Stream::do_SSL_write void   )  [protected]
 

Definition at line 598 of file SSL_Asynch_Stream.cpp.

References ACE_TEXT, ERR_CANCELED, ext_write_result_, notify_write(), print_error(), ACE_Message_Block::rd_ptr(), SF_REQ_SHUTDOWN, and ssl_.

Referenced by do_SSL_state_machine().

00599 {
00600   if (this->ext_write_result_ == 0)  // nothing to do
00601     return 0;
00602 
00603   if (this->flags_ & SF_REQ_SHUTDOWN)
00604     {
00605       this->notify_write (0, ERR_CANCELED);
00606       return -1;
00607     }
00608 
00609   ACE_Message_Block & mb = this->ext_write_result_->message_block ();
00610   size_t       bytes_req = this->ext_write_result_->bytes_to_write ();
00611 
00612   ERR_clear_error();
00613 
00614   const int bytes_trn = ::SSL_write (this->ssl_,
00615                                      mb.rd_ptr (),
00616                                      bytes_req);
00617 
00618   int const status = ::SSL_get_error (this->ssl_, bytes_trn);
00619 
00620   switch (status)
00621     {
00622     case SSL_ERROR_NONE:
00623       this->notify_write (bytes_trn, 0);
00624       return 1;
00625 
00626     case SSL_ERROR_WANT_READ:
00627     case SSL_ERROR_WANT_WRITE:
00628       return 0;
00629 
00630     case SSL_ERROR_ZERO_RETURN:
00631       this->notify_write (bytes_trn, 0);
00632       return 1;
00633 
00634     case SSL_ERROR_SYSCALL:
00635     default:
00636       break;
00637     }
00638 
00639  this->notify_write(0, EFAULT);
00640  this->print_error (status,
00641                     ACE_TEXT ("SSL_write error"));
00642 
00643  return -1;
00644 }

void ACE_SSL_Asynch_Stream::handle_read_stream const ACE_Asynch_Read_Stream::Result &  result  )  [protected, virtual]
 

This method is called when BIO read request is completed. It processes the IO completion and calls do_SSL_state_machine().

Definition at line 988 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD, ACE_SYNCH_MUTEX, BF_AIO, BF_EOS, bio_inp_errno_, bio_inp_flag_, and do_SSL_state_machine().

00990 {
00991   ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->mutex_));
00992 
00993   this->bio_inp_flag_ &= ~BF_AIO;
00994 
00995   size_t bytes_trn = result.bytes_transferred ();
00996   u_long errval    = result.error ();
00997 
00998   if (errval != 0)                     // error ?
00999      this->bio_inp_errno_ = errval;    // save err code
01000   else if (bytes_trn == 0)             // end of stream ?
01001      this->bio_inp_flag_ |= BF_EOS;    // set flag EOS
01002 
01003   this->do_SSL_state_machine ();
01004 
01005   return;
01006 }

void ACE_SSL_Asynch_Stream::handle_wakeup void   )  [protected, virtual]
 

This method is called when all SSL sessions are closed and no more pending AIOs exist. It also calls users handle_wakeup().

Definition at line 1009 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD, ACE_SYNCH_MUTEX, ext_handler_, and SF_DELETE_ENABLE.

01010 {
01011   ACE_Handler * user_handler = 0;
01012 
01013   {
01014     ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->mutex_));
01015 
01016     this->flags_ |= SF_DELETE_ENABLE;
01017 
01018     user_handler = this->ext_handler_;
01019   }
01020 
01021   if (user_handler != 0)
01022     user_handler->handle_wakeup();
01023 }

void ACE_SSL_Asynch_Stream::handle_write_stream const ACE_Asynch_Write_Stream::Result &  result  )  [protected, virtual]
 

virtual from ACE_Handler

This method is called when BIO write request is completed. It processes the IO completion and calls do_SSL_state_machine().

Definition at line 943 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR, ACE_GUARD, ACE_SIGRTMIN, ACE_SYNCH_MUTEX, ACE_TEXT, BF_AIO, bio_ostream_, bio_out_errno_, bio_out_flag_, do_SSL_state_machine(), and LM_ERROR.

00945 {
00946   ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->mutex_));
00947 
00948   this->bio_out_flag_ &= ~BF_AIO;
00949 
00950   ACE_Message_Block & mb = result.message_block ();
00951 
00952   size_t bytes_req = result.bytes_to_write ();
00953   size_t bytes_trn = result.bytes_transferred ();
00954   u_long errval    = result.error ();
00955   size_t len       = bytes_req - bytes_trn;
00956 
00957   if (errval != 0)                    // error ?
00958     this->bio_out_errno_ = errval;    // save err code
00959   else if (len > 0)                   // TCP/IP overloaded ?
00960     {                                 // continue, rd_ptr at right place
00961       if (this->bio_ostream_.write (
00962             mb,          // message block
00963             len,         // priority
00964             0,           // act
00965             0,           // priority
00966             ACE_SIGRTMIN // default signal
00967             ) == 0)
00968         {
00969           this->bio_out_flag_ |= BF_AIO;
00970           return;
00971         }
00972 
00973       ACE_ERROR
00974         ((LM_ERROR,
00975           ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00976           ACE_TEXT ("attempt write failed")
00977           ));
00978 
00979       this->bio_out_errno_ = EINVAL;
00980     }
00981 
00982   this->do_SSL_state_machine ();
00983 
00984   return;
00985 }

virtual ACE_Asynch_Operation_Impl* ACE_SSL_Asynch_Stream::implementation void   )  const [inline, protected, virtual]
 

Virtual from ACE_Asynch_Operation. Since this class is essentially an implementation class, simply return 0.

Definition at line 279 of file SSL_Asynch_Stream.h.

00279 { return 0; }

int ACE_SSL_Asynch_Stream::notify_close void   )  [protected]
 

This method is called to notify ourself that SSL session is shutdown and that there is no more I/O activity now and in the future.

Definition at line 655 of file SSL_Asynch_Stream.cpp.

References ACE_NEW_RETURN, pending_BIO_count(), SF_CLOSE_NTF_SENT, and SF_SHUTDOWN_DONE.

Referenced by do_SSL_state_machine().

00656 {
00657   if (this->flags_ & SF_CLOSE_NTF_SENT)  // already sent
00658     return 1;
00659 
00660   if ((this->flags_ & SF_SHUTDOWN_DONE) == 0)  // only after shutdown
00661     return 2;    // too early , we will do later
00662 
00663   if (this->pending_BIO_count () != 0)   // wait for all internal IO
00664     return 2;   // too early , we will do later
00665 
00666   // create result for future notification
00667   ACE_SSL_Asynch_Result * close_result = 0;
00668 
00669   ACE_NEW_RETURN (close_result,
00670                   ACE_SSL_Asynch_Result (*this),
00671                   2);
00672   //@@ Not exception safe!
00673 
00674  int retval =
00675    close_result->post_completion (this->proactor_->implementation ());
00676 
00677  if (retval == 0)
00678    {
00679      this->flags_ |= SF_CLOSE_NTF_SENT;
00680      return 0;
00681    }
00682 
00683  delete close_result;
00684  return 2;
00685 }

int ACE_SSL_Asynch_Stream::notify_read int  bytes_transferred,
int  error
[protected]
 

This method is called to notify user handler when user's read in done.

Definition at line 696 of file SSL_Asynch_Stream.cpp.

References ext_read_result_.

Referenced by cancel(), do_SSL_read(), and do_SSL_shutdown().

00698 {
00699   if (ext_read_result_ == 0) //nothing to notify
00700     return 1;
00701 
00702   this->ext_read_result_->set_bytes_transferred (bytes_transferred);
00703   this->ext_read_result_->set_error (error);
00704 
00705   int retval =
00706     this->ext_read_result_->post_completion (proactor_->implementation ());
00707 
00708   if (retval == 0)
00709     {
00710       this->ext_read_result_ = 0;
00711       return 0;  // success
00712     }
00713 
00714   return 2; // unable to notify
00715 }

int ACE_SSL_Asynch_Stream::notify_write int  bytes_transferred,
int  error
[protected]
 

This method is called to notify user handler when user's write in done.

Definition at line 726 of file SSL_Asynch_Stream.cpp.

References ext_write_result_.

Referenced by cancel(), do_SSL_shutdown(), and do_SSL_write().

00728 {
00729   if (this->ext_write_result_ == 0) //nothing to notify
00730     return 1;
00731 
00732   this->ext_write_result_->set_bytes_transferred (bytes_transferred);
00733   this->ext_write_result_->set_error (error);
00734 
00735   int retval =
00736     this->ext_write_result_->post_completion (
00737       this->proactor_->implementation ());
00738 
00739   if (retval == 0)
00740     {
00741       this->ext_write_result_ = 0;
00742       return 0;  // success
00743     }
00744 
00745   return 2; // unable to notify
00746 }

int ACE_SSL_Asynch_Stream::open ACE_Handler &  handler,
ACE_HANDLE  handle = ACE_INVALID_HANDLE,
const void *  completion_key = 0,
ACE_Proactor proactor = 0
 

Initializes the factory with information which will be used with each asynchronous call.

  • handler The ACE_Handler that will be called to handle completions for operations initiated using this factory.
  • handle The handle that future read/write operations will use.
Return values:
0 for success.
-1 for failure; consult errno for further information.

Definition at line 222 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR_RETURN, ACE_GUARD_RETURN, ACE_SSL_make_BIO(), ACE_SYNCH_MUTEX, ACE_TEXT, bio_, bio_istream_, bio_ostream_, do_SSL_state_machine(), ext_handler_, LM_ERROR, SF_STREAM_OPEN, ssl_, ST_CLIENT, and ST_SERVER.

00226 {
00227   ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1));
00228 
00229   if (this->flags_ & SF_STREAM_OPEN)
00230     ACE_ERROR_RETURN
00231       ((LM_ERROR,
00232         ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream::open() %p\n"),
00233         ACE_TEXT ("- already opened")),
00234        -1);
00235 
00236   if (this->ssl_ == 0)
00237     ACE_ERROR_RETURN
00238       ((LM_ERROR,
00239         ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream::open() %p\n"),
00240         ACE_TEXT ("- SSL structure is absent")),
00241        -1);
00242 
00243   if (handle == ACE_INVALID_HANDLE)
00244     ACE_ERROR_RETURN
00245       ((LM_ERROR,
00246         ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream::open() %p\n"),
00247         ACE_TEXT ("- invalid handle")),
00248        -1);
00249 
00250 
00251   // Get a proactor for/from the user.
00252   this->proactor_    = this->get_proactor (proactor, handler);
00253   this->ext_handler_ = & handler;
00254   this->handle_      = handle;
00255 
00256   // Open internal input stream
00257   if (this->bio_istream_.open (*this,   // real callbacks to this
00258                                handle,
00259                                completion_key,
00260                                this->proactor_) != 0)
00261     return -1;
00262 
00263   // Open internal output stream
00264   if (this->bio_ostream_.open (*this,  // real callbacks to this
00265                                handle,
00266                                completion_key,
00267                                this->proactor_) != 0)
00268     return -1;
00269 
00270   this->bio_ = ACE_SSL_make_BIO (this);
00271 
00272   if (this->bio_ == 0)
00273     ACE_ERROR_RETURN
00274       ((LM_ERROR,
00275         ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream::open() %p\n"),
00276         ACE_TEXT ("- cannot allocate new BIO structure")),
00277        -1);
00278 
00279   ::SSL_set_bio (this->ssl_ , this->bio_ , this->bio_);
00280 
00281   switch (this->type_)
00282     {
00283     case ST_CLIENT:
00284       ::SSL_set_connect_state (this->ssl_);
00285       break;
00286 
00287     case ST_SERVER:
00288       ::SSL_set_accept_state (this->ssl_);
00289       break;
00290 
00291     default:
00292       ACE_ERROR_RETURN
00293         ((LM_ERROR,
00294           ACE_TEXT ("(%P|%t) ACE_SSL_Asynch_Stream::open() %p\n"),
00295           ACE_TEXT ("- invalid stream type")),
00296          -1);
00297     }
00298 
00299   this->flags_ |= SF_STREAM_OPEN;
00300 
00301   this->do_SSL_state_machine ();
00302 
00303   return 0;
00304 }

ACE_SSL_Asynch_Stream& ACE_SSL_Asynch_Stream::operator= ACE_SSL_Asynch_Stream const &   )  [private]
 

int ACE_SSL_Asynch_Stream::pending_BIO_count void   )  [protected]
 

Definition at line 1026 of file SSL_Asynch_Stream.cpp.

References BF_AIO, bio_inp_flag_, and bio_out_flag_.

Referenced by notify_close().

01027 {
01028   int ret = 0;
01029 
01030   if (this->bio_inp_flag_ & BF_AIO)
01031     ++ret;
01032 
01033   if (this->bio_out_flag_ & BF_AIO)
01034     ++ret;
01035 
01036   return ret;
01037 }

void ACE_SSL_Asynch_Stream::print_error int  err_ssl,
const ACE_TCHAR pText
[protected]
 

Definition at line 752 of file SSL_Asynch_Stream.cpp.

References ACE_DEBUG, and LM_DEBUG.

Referenced by do_SSL_handshake(), do_SSL_read(), do_SSL_shutdown(), and do_SSL_write().

00754 {
00755   ACE_DEBUG ((LM_DEBUG,
00756               "SSL-error:%d %s\n" ,
00757               err_ssl,
00758               pText));
00759 
00760 #if OPENSSL_VERSION_NUMBER >= 0x0090601fL
00761   // OpenSSL < 0.9.6a doesn't have ERR_error_string_n() function.
00762   unsigned long lerr = 0;
00763   char buf[1024];
00764 
00765   while ((lerr = ERR_get_error()) != 0)
00766     {
00767       ERR_error_string_n (lerr, buf, sizeof buf);
00768 
00769       ACE_DEBUG ((LM_DEBUG, "%s\n", buf));
00770     }
00771 #endif  /* OPENSSL_VERSION_NUMBER */
00772 }

int ACE_SSL_Asynch_Stream::read ACE_Message_Block message_block,
size_t  num_bytes_to_read,
const void *  act = 0,
int  priority = 0,
int  signal_number = ACE_SIGRTMIN
 

Initiates an asynchronous read. If the operation is successfully initiated, the handle_read_stream() method will be called on the ACE_Handler object passed to open() when the operation completes. Data is read into the specified ACE_Message_Block beginning at its write pointer; the block's write pointer is updated to reflect any added data when the operation completes.

  • message_block The specified ACE_Message_Block will receive any data that is read. Data will be read into the block beginning at the block's write pointer.
  • num_bytes_to_read The maximum number of bytes to read. The actual amount read may be less.
  • act ACT which is passed to the completion handler in the result object.
  • priority Specifies the operation priority. This has an affect on POSIX only. Works like nice in Unix. Negative values are not allowed. 0 means priority of the operation same as the process priority. 1 means priority of the operation is one less than process, and so forth. This parameter has no affect on Win32.
  • signal_number The POSIX4 real-time signal number to be used for the operation. signal_number ranges from ACE_SIGRTMIN to ACE_SIGRTMAX. This argument is unused on non-POSIX4 systems.
Return values:
0 for success.
-1 for failure; consult errno for further information.

Definition at line 312 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD_RETURN, ACE_NEW_RETURN, ACE_SYNCH_MUTEX, do_SSL_state_machine(), ext_read_result_, SF_REQ_SHUTDOWN, and SF_STREAM_OPEN.

00317 {
00318   ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1));
00319 
00320   if ((this->flags_ & SF_STREAM_OPEN) == 0)  // not open
00321     return -1;
00322 
00323   if (this->flags_ & SF_REQ_SHUTDOWN)
00324     return -1;
00325 
00326   // only one read operation is allowed now
00327   // later it will be possible to make a queue
00328 
00329   if (this->ext_read_result_ != 0)
00330     return -1;
00331 
00332   // create result for future notification
00333   ACE_NEW_RETURN (this->ext_read_result_,
00334                   ACE_SSL_Asynch_Read_Stream_Result (
00335                     *this->ext_handler_,
00336                     this->handle_,
00337                     message_block,
00338                     bytes_to_read,
00339                     act,
00340                     this->proactor_->get_handle(),
00341                     priority,
00342                     signal_number),
00343                   -1);
00344 
00345   this->do_SSL_state_machine (); // ignore return code
00346 
00347   return 0;
00348 }

int ACE_SSL_Asynch_Stream::ssl_bio_read char *  buf,
size_t  len,
int &  errval
[protected]
 

Definition at line 780 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR, ACE_SIGRTMIN, ACE_TEXT, ACE_Message_Block::base(), BF_AIO, BF_EOS, bio_inp_errno_, bio_inp_flag_, bio_inp_msg_, bio_istream_, EINPROGRESS, ACE_Message_Block::length(), LM_ERROR, ACE_OS::memcpy(), ACE_Message_Block::rd_ptr(), ACE_Message_Block::size(), and ACE_Message_Block::wr_ptr().

Referenced by ACE_SSL_Asynch_Stream_Accessor::read().

00783 {
00784   // We do not have to acquire mutex
00785   // as we called already with locked mutex
00786   // from do_SSL_state_machine()
00787 
00788   errval = 0;
00789 
00790   size_t cur_len = this->bio_inp_msg_.length ();
00791 
00792   if (cur_len > 0) // there are more data buffered
00793     {
00794       const char * rd_ptr = this->bio_inp_msg_.rd_ptr ();
00795 
00796       if (cur_len > len)
00797         cur_len = len;
00798 
00799       ACE_OS::memcpy (buf, rd_ptr, cur_len);
00800 
00801       this->bio_inp_msg_.rd_ptr (cur_len); // go ahead
00802 
00803       return cur_len;
00804     }
00805 
00806   if (this->bio_inp_errno_ != 0)     // if was error - it is permanent !
00807     {
00808       errval = this->bio_inp_errno_;
00809       return -1;
00810     }
00811 
00812   if (this->bio_inp_flag_ & BF_EOS)  // End of stream
00813     return 0;
00814 
00815   errval = EINPROGRESS;          // SSL will try later
00816 
00817   if (this->bio_inp_flag_ & BF_AIO)  // we are busy
00818     return -1;
00819 
00820   if (this->bio_inp_msg_.size (len) != 0)
00821     {
00822       ACE_ERROR
00823         ((LM_ERROR,
00824           ACE_TEXT ("%N:%l ((%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00825           ACE_TEXT ("error in ACE_Message_Block::size() ")
00826           ));
00827 
00828       errval = EINVAL;
00829       return -1;
00830     }
00831 
00832   char * base = this->bio_inp_msg_.base ();
00833 
00834   this->bio_inp_msg_.rd_ptr (base);
00835   this->bio_inp_msg_.wr_ptr (base);
00836 
00837   if (this->bio_istream_.read (
00838         bio_inp_msg_,  // message block
00839         len,           // priority
00840         0,             // act
00841         0,             // priority
00842         ACE_SIGRTMIN   // default signal
00843         ) == -1)
00844     {
00845       ACE_ERROR
00846         ((LM_ERROR,
00847           ACE_TEXT ("%N:%l (%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00848           ACE_TEXT ("attempt read failed")
00849           ));
00850 
00851       errval = EINVAL;  // may be leave EINPROGRESS ??
00852       return -1;        // to try later
00853     }
00854 
00855   this->bio_inp_flag_ |= BF_AIO;  // AIO is active
00856 
00857   return -1;
00858 }

int ACE_SSL_Asynch_Stream::ssl_bio_write const char *  buf,
size_t  len,
int &  errval
[protected]
 

Definition at line 862 of file SSL_Asynch_Stream.cpp.

References ACE_ERROR, ACE_SIGRTMIN, ACE_TEXT, ACE_Message_Block::base(), BF_AIO, bio_ostream_, bio_out_errno_, bio_out_flag_, bio_out_msg_, ACE_Message_Block::copy(), EINPROGRESS, LM_ERROR, ACE_Message_Block::rd_ptr(), ACE_Message_Block::size(), and ACE_Message_Block::wr_ptr().

Referenced by ACE_SSL_Asynch_Stream_Accessor::write().

00865 {
00866   // We do not have to acquire mutex
00867   // as we called already with locked mutex
00868   // from do_SSL_state_machine
00869 
00870   errval = 0;
00871 
00872   if (this->bio_out_flag_ & BF_AIO)  // sorry, we are busy
00873     {
00874       errval = EINPROGRESS;   // try later
00875       return -1;
00876     }
00877 
00878   if (this->bio_out_errno_ != 0)      // no recovery
00879     {
00880       errval = this->bio_out_errno_;
00881       return -1;
00882     }
00883 
00884   if (this->bio_out_msg_.size (len) != 0)
00885     {
00886       ACE_ERROR
00887         ((LM_ERROR,
00888           ACE_TEXT ("%N:%l ((%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00889           ACE_TEXT ("error in ACE_Message_Block::size() ")
00890           ));
00891 
00892       errval = EINVAL;
00893       return -1;
00894     }
00895 
00896   char * base = this->bio_out_msg_.base ();
00897 
00898   this->bio_out_msg_.rd_ptr (base);
00899   this->bio_out_msg_.wr_ptr (base);
00900 
00901   if (this->bio_out_msg_.copy (buf, len) == -1)
00902     {
00903       ACE_ERROR
00904         ((LM_ERROR,
00905           ACE_TEXT ("%N:%l ((%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00906           ACE_TEXT ("error in ACE_Message_Block::copy() ")
00907           ));
00908 
00909       errval = EINVAL;
00910       return -1;
00911     }
00912 
00913 
00914   if (this->bio_ostream_.write (
00915         this->bio_out_msg_, // message block
00916         len,          // priority
00917         0,            // act
00918         0,            // priority
00919         ACE_SIGRTMIN  // default signal
00920         ) == -1)
00921     {
00922       ACE_ERROR
00923         ((LM_ERROR,
00924           ACE_TEXT ("%N:%l ((%P|%t) ACE_SSL_Asynch_Stream %p\n"),
00925           ACE_TEXT ("attempt write failed")
00926           ));
00927 
00928       errval = EINVAL;  // may be leave EINPROGRESS ??
00929       return -1;        // to try later
00930     }
00931 
00932   this->bio_out_flag_ |= BF_AIO;  // AIO is active
00933   errval = 0;               // Ok, go ahead
00934 
00935   return len;
00936 }

int ACE_SSL_Asynch_Stream::write ACE_Message_Block message_block,
size_t  bytes_to_write,
const void *  act = 0,
int  priority = 0,
int  signal_number = ACE_SIGRTMIN
 

Initiates an asynchronous write. If the operation is successfully initiated, the handle_write_stream() method will be called on the ACE_Handler object passed to open() when the operation completes. Data is taken from the specified ACE_Message_Block beginning at its read pointer; the block's read pointer is updated to reflect any data successfully sent when the operation completes.

  • message_block The specified ACE_Message_Block is the source of data that is written. Data will be taken from the block beginning at the block's read pointer.
  • bytes_to_write The maximum number of bytes to write. The actual amount written may be less.
  • act ACT which is passed to the completion handler in the result object.
  • priority Specifies the operation priority. This has an affect on POSIX only. Works like nice in Unix. Negative values are not allowed. 0 means priority of the operation same as the process priority. 1 means priority of the operation is one less than process, and so forth. This parameter has no affect on Win32.
  • signal_number The POSIX4 real-time signal number to be used for the operation. signal_number ranges from ACE_SIGRTMIN to ACE_SIGRTMAX. This argument is unused on non-POSIX4 systems.
Return values:
0 for success.
-1 for failure; consult errno for further information.

Definition at line 355 of file SSL_Asynch_Stream.cpp.

References ACE_GUARD_RETURN, ACE_NEW_RETURN, ACE_SYNCH_MUTEX, do_SSL_state_machine(), ext_write_result_, SF_REQ_SHUTDOWN, and SF_STREAM_OPEN.

00360 {
00361   ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1));
00362 
00363   if ((this->flags_ & SF_STREAM_OPEN) == 0)  // not open
00364     return -1;
00365 
00366   if (this->flags_ & SF_REQ_SHUTDOWN)
00367     return -1;
00368 
00369   // only one read operation is allowed now
00370   // later it will be possible to make a queue
00371 
00372   if (this->ext_write_result_ != 0)
00373     return -1;
00374 
00375   // create result for future notification
00376   ACE_NEW_RETURN (this->ext_write_result_,
00377                   ACE_SSL_Asynch_Write_Stream_Result (
00378                     *this->ext_handler_,
00379                     this->handle_,
00380                     message_block,
00381                     bytes_to_write,
00382                     act,
00383                     this->proactor_->get_handle(),
00384                     priority,
00385                     signal_number),
00386                   -1);
00387 
00388   this->do_SSL_state_machine ();
00389 
00390   return 0;
00391 }


Friends And Related Function Documentation

friend struct ACE_SSL_Asynch_Stream_Accessor [friend]
 

Definition at line 160 of file SSL_Asynch_Stream.h.


Member Data Documentation

BIO* ACE_SSL_Asynch_Stream::bio_ [protected]
 

The BIO implementation.

Definition at line 381 of file SSL_Asynch_Stream.h.

Referenced by open().

int ACE_SSL_Asynch_Stream::bio_inp_errno_ [protected]
 

Definition at line 399 of file SSL_Asynch_Stream.h.

Referenced by handle_read_stream(), and ssl_bio_read().

int ACE_SSL_Asynch_Stream::bio_inp_flag_ [protected]
 

Definition at line 400 of file SSL_Asynch_Stream.h.

Referenced by handle_read_stream(), pending_BIO_count(), and ssl_bio_read().

ACE_Message_Block ACE_SSL_Asynch_Stream::bio_inp_msg_ [protected]
 

Definition at line 398 of file SSL_Asynch_Stream.h.

Referenced by ssl_bio_read().

ACE_Asynch_Read_Stream ACE_SSL_Asynch_Stream::bio_istream_ [protected]
 

Definition at line 397 of file SSL_Asynch_Stream.h.

Referenced by cancel(), open(), and ssl_bio_read().

ACE_Asynch_Write_Stream ACE_SSL_Asynch_Stream::bio_ostream_ [protected]
 

Definition at line 407 of file SSL_Asynch_Stream.h.

Referenced by cancel(), handle_write_stream(), open(), and ssl_bio_write().

int ACE_SSL_Asynch_Stream::bio_out_errno_ [protected]
 

Definition at line 409 of file SSL_Asynch_Stream.h.

Referenced by handle_write_stream(), and ssl_bio_write().

int ACE_SSL_Asynch_Stream::bio_out_flag_ [protected]
 

Definition at line 410 of file SSL_Asynch_Stream.h.

Referenced by handle_write_stream(), pending_BIO_count(), and ssl_bio_write().

ACE_Message_Block ACE_SSL_Asynch_Stream::bio_out_msg_ [protected]
 

Definition at line 408 of file SSL_Asynch_Stream.h.

Referenced by ssl_bio_write().

ACE_Handler* ACE_SSL_Asynch_Stream::ext_handler_ [protected]
 

External,i.e user handler.

Definition at line 352 of file SSL_Asynch_Stream.h.

Referenced by handle_wakeup(), and open().

ACE_SSL_Asynch_Read_Stream_Result* ACE_SSL_Asynch_Stream::ext_read_result_ [protected]
 

External, i.e. read result faked for user.

Definition at line 355 of file SSL_Asynch_Stream.h.

Referenced by do_SSL_read(), notify_read(), and read().

ACE_SSL_Asynch_Write_Stream_Result* ACE_SSL_Asynch_Stream::ext_write_result_ [protected]
 

External, i.e. write result faked for user.

Definition at line 358 of file SSL_Asynch_Stream.h.

Referenced by do_SSL_write(), notify_write(), and write().

int ACE_SSL_Asynch_Stream::flags_ [protected]
 

Definition at line 375 of file SSL_Asynch_Stream.h.

ACE_HANDLE ACE_SSL_Asynch_Stream::handle_ [protected]
 

The real file/socket handle.

Definition at line 346 of file SSL_Asynch_Stream.h.

ACE_SYNCH_MUTEX ACE_SSL_Asynch_Stream::mutex_ [protected]
 

Mutex to protect work.

Definition at line 414 of file SSL_Asynch_Stream.h.

ACE_Proactor* ACE_SSL_Asynch_Stream::proactor_ [protected]
 

The proactor.

Definition at line 349 of file SSL_Asynch_Stream.h.

SSL* ACE_SSL_Asynch_Stream::ssl_ [protected]
 

The SSL session.

Definition at line 378 of file SSL_Asynch_Stream.h.

Referenced by ACE_SSL_Asynch_Stream(), do_SSL_handshake(), do_SSL_read(), do_SSL_shutdown(), do_SSL_write(), open(), and ~ACE_SSL_Asynch_Stream().

Stream_Type ACE_SSL_Asynch_Stream::type_ [protected]
 

Stream Type ST_CLIENT/ST_SERVER.

Definition at line 343 of file SSL_Asynch_Stream.h.


The documentation for this class was generated from the following files:
Generated on Sun Jan 27 13:03:28 2008 for ACE_SSL by doxygen 1.3.6