Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

SSL_SOCK_Connector.cpp

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // $Id: SSL_SOCK_Connector.cpp,v 1.1.1.2 2003/02/21 18:36:32 chad Exp $
00003 
00004 #include "SSL_SOCK_Connector.h"
00005 
00006 #include "ace/Handle_Set.h"
00007 #include "ace/INET_Addr.h"
00008 #include "ace/Synch_T.h"
00009 #include "ace/Log_Msg.h"
00010 
00011 #include <openssl/err.h>
00012 
00013 #if defined (ACE_LACKS_INLINE_FUNCTIONS)
00014 #include "SSL_SOCK_Connector.i"
00015 #endif /* ACE_LACKS_INLINE_FUNCTIONS */
00016 
00017 ACE_RCSID (ACE_SSL,
00018            SSL_SOCK_Connector,
00019            "$Id: SSL_SOCK_Connector.cpp,v 1.1.1.2 2003/02/21 18:36:32 chad Exp $")
00020 
00021 ACE_ALLOC_HOOK_DEFINE(ACE_SSL_SOCK_Connector)
00022 
00023 
00024 ACE_SSL_SOCK_Connector::~ACE_SSL_SOCK_Connector (void)
00025 {
00026   ACE_TRACE ("ACE_SSL_SOCK_Connector::~ACE_SSL_SOCK_Connector");
00027 }
00028 
00029 int
00030 ACE_SSL_SOCK_Connector::ssl_connect (ACE_SSL_SOCK_Stream &new_stream,
00031                                      const ACE_Time_Value *timeout)
00032 {
00033   SSL *ssl = new_stream.ssl ();
00034 
00035   if (SSL_is_init_finished (ssl))
00036     return 0;
00037 
00038   // Check if a connection is already pending for the given SSL
00039   // structure.
00040   if (!SSL_in_connect_init (ssl))
00041     ::SSL_set_connect_state (ssl);
00042 
00043   ACE_HANDLE handle = new_stream.get_handle ();
00044 
00045   // We're going to call SSL_connect, optionally doing ACE::select and
00046   // retrying the SSL_connect, until the SSL handshake is done or
00047   // it fails.
00048   // To get the timeout affect, set the socket to nonblocking mode
00049   // before beginning if there is a timeout specified. If the timeout
00050   // is 0 (wait as long as it takes) then don't worry about the blocking
00051   // status; we'll block in SSL_connect if the socket is blocking, and
00052   // block in ACE::select if not.
00053   int reset_blocking_mode = 0;
00054   if (timeout != 0)
00055     {
00056       reset_blocking_mode = ACE_BIT_DISABLED (ACE::get_flags (handle),
00057                                               ACE_NONBLOCK);
00058           // Set the handle into non-blocking mode if it's not already
00059           // in it.
00060           if (reset_blocking_mode
00061               && ACE::set_flags (handle,
00062                                  ACE_NONBLOCK) == -1)
00063             return -1;
00064     }
00065 
00066   int status;
00067   do
00068     {
00069       // These handle sets are used to set up for whatever SSL_connect
00070       // says it wants next. They're reset on each pass around the loop.
00071       ACE_Handle_Set rd_handle;
00072       ACE_Handle_Set wr_handle;
00073 
00074       status = ::SSL_connect (ssl);
00075       switch (::SSL_get_error (ssl, status))
00076         {
00077         case SSL_ERROR_NONE:
00078           // Start out with non-blocking disabled on the SSL stream.
00079           new_stream.disable (ACE_NONBLOCK);
00080           status = 0;               // To tell caller about success
00081           break;                    // Done
00082 
00083         case SSL_ERROR_WANT_WRITE:
00084           wr_handle.set_bit (handle);
00085           status = 1;               // Wait for more activity
00086           break;
00087 
00088         case SSL_ERROR_WANT_READ:
00089           rd_handle.set_bit (handle);
00090           status = 1;               // Wait for more activity
00091           break;
00092 
00093         case SSL_ERROR_ZERO_RETURN:
00094           // The peer has notified us that it is shutting down via
00095           // the SSL "close_notify" message so we need to
00096           // shutdown, too.
00097           status = -1;
00098           break;
00099 
00100         case SSL_ERROR_SYSCALL:
00101           // On some platforms (e.g. MS Windows) OpenSSL does not
00102           // store the last error in errno so explicitly do so.
00103           //
00104           // Explicitly check for EWOULDBLOCK since it doesn't get
00105           // converted to an SSL_ERROR_WANT_{READ,WRITE} on some
00106           // platforms. If SSL_connect failed outright, though, don't
00107           // bother checking more. This can happen if the socket gets
00108           // closed during the handshake.
00109           if (ACE_OS::set_errno_to_last_error () == EWOULDBLOCK &&
00110               status == -1)
00111             {
00112               // Although the SSL_ERROR_WANT_READ/WRITE isn't getting
00113               // set correctly, the read/write state should be valid.
00114               // Use that to decide what to do.
00115               status = 1;               // Wait for more activity
00116               if (SSL_want_write (ssl))
00117                 wr_handle.set_bit (handle);
00118               else if (SSL_want_read (ssl))
00119                 rd_handle.set_bit (handle);
00120               else
00121                 status = -1;            // Doesn't want anything - bail out
00122             }
00123           else
00124             status = -1;
00125           break;
00126 
00127         default:
00128           ACE_SSL_Context::report_error ();
00129           status = -1;
00130           break;
00131         }
00132 
00133       if (status == 1)
00134         {
00135           // Must have at least one handle to wait for at this point.
00136           ACE_ASSERT (rd_handle.num_set() == 1 || wr_handle.num_set () == 1);
00137           status = ACE::select (int (handle) + 1,
00138                                 &rd_handle,
00139                                 &wr_handle,
00140                                 0,
00141                                 timeout);
00142           // 0 is timeout, so we're done.
00143           // -1 is error, so we're done.
00144           // Could be both handles set (same handle in both masks) so set to 1.
00145           if (status >= 1)
00146             status = 1;
00147           else                 // Timeout or socket failure
00148             status = -1;
00149         }
00150 
00151     } while (status == 1 && !SSL_is_init_finished (ssl));
00152 
00153   if (reset_blocking_mode)
00154     {
00155       ACE_Errno_Guard eguard (errno);
00156       ACE::clr_flags (handle, ACE_NONBLOCK);
00157     }
00158 
00159   return (status == -1 ? -1 : 0);
00160 
00161 }
00162 
00163 int
00164 ACE_SSL_SOCK_Connector::connect (ACE_SSL_SOCK_Stream &new_stream,
00165                                  const ACE_Addr &remote_sap,
00166                                  const ACE_Time_Value *timeout,
00167                                  const ACE_Addr &local_sap,
00168                                  int reuse_addr,
00169                                  int flags,
00170                                  int perms)
00171 {
00172   ACE_TRACE ("ACE_SSL_SOCK_Connector::connect");
00173 
00174   // Take into account the time to complete the basic TCP handshake
00175   // and the SSL handshake.
00176   ACE_Time_Value time_copy;
00177   ACE_Countdown_Time countdown (&time_copy);
00178   if (timeout != 0)
00179     {
00180       time_copy += *timeout;
00181       countdown.start ();
00182     }
00183 
00184   int result =
00185     this->connector_.connect (new_stream.peer (),
00186                               remote_sap,
00187                               timeout,
00188                               local_sap,
00189                               reuse_addr,
00190                               flags,
00191                               perms);
00192 
00193   int error = 0;
00194   if (result == -1)
00195     error = errno;  // Save us some TSS accesses.
00196 
00197   // Obtain the handle from the underlying SOCK_Stream and set it in
00198   // the SSL_SOCK_Stream.  Note that the case where a connection is in
00199   // progress is also handled.  In that case, the handle must also be
00200   // set in the SSL_SOCK_Stream so that the correct handle is returned
00201   // when performing non-blocking connect()s.
00202   if (new_stream.get_handle () == ACE_INVALID_HANDLE
00203       && (result == 0
00204           || (result == -1 && (error == EWOULDBLOCK
00205                                || error == EINPROGRESS))))
00206     new_stream.set_handle (new_stream.peer ().get_handle ());
00207 
00208   if (result == -1)
00209     return result;
00210 
00211   // If using a timeout, update the countdown timer to reflect the time
00212   // spent on the connect itself, then pass the remaining time to
00213   // ssl_connect to bound the time on the handshake.
00214   if (timeout != 0)
00215     {
00216       countdown.update ();
00217       timeout = &time_copy;
00218     }
00219 
00220   result = this->ssl_connect (new_stream, timeout);
00221 
00222   if (result == -1)
00223     new_stream.close ();
00224 
00225   return result;
00226 }
00227 
00228 int
00229 ACE_SSL_SOCK_Connector::connect (ACE_SSL_SOCK_Stream &new_stream,
00230                                  const ACE_Addr &remote_sap,
00231                                  ACE_QoS_Params qos_params,
00232                                  const ACE_Time_Value *timeout,
00233                                  const ACE_Addr &local_sap,
00234                                  ACE_Protocol_Info *protocolinfo,
00235                                  ACE_SOCK_GROUP g,
00236                                  u_long flags,
00237                                  int reuse_addr,
00238                                  int perms)
00239 {
00240   ACE_TRACE ("ACE_SSL_SOCK_Connector::connect");
00241 
00242   // Take into account the time to complete the basic TCP handshake
00243   // and the SSL handshake.
00244   ACE_Time_Value time_copy;
00245   ACE_Countdown_Time countdown (&time_copy);
00246   if (timeout != 0)
00247     {
00248       time_copy += *timeout;
00249       countdown.start ();
00250     }
00251 
00252   int result = this->connector_.connect (new_stream.peer (),
00253                                          remote_sap,
00254                                          qos_params,
00255                                          timeout,
00256                                          local_sap,
00257                                          protocolinfo,
00258                                          g,
00259                                          flags,
00260                                          reuse_addr,
00261                                          perms);
00262 
00263   int error = 0;
00264   if (result == -1)
00265     error = errno;  // Save us some TSS accesses.
00266 
00267   // Obtain the handle from the underlying SOCK_Stream and set it in
00268   // the SSL_SOCK_Stream.  Note that the case where a connection is in
00269   // progress is also handled.  In that case, the handle must also be
00270   // set in the SSL_SOCK_Stream so that the correct handle is returned
00271   // when performing non-blocking connect()s.
00272   if (new_stream.get_handle () == ACE_INVALID_HANDLE
00273       && (result == 0
00274           || (result == -1 && (error == EWOULDBLOCK
00275                                || error == EINPROGRESS))))
00276     new_stream.set_handle (new_stream.peer ().get_handle ());
00277 
00278   if (result == -1)
00279     return result;
00280 
00281   // If using a timeout, update the countdown timer to reflect the time
00282   // spent on the connect itself, then pass the remaining time to
00283   // ssl_connect to bound the time on the handshake.
00284   if (timeout != 0)
00285     {
00286       countdown.update ();
00287       timeout = &time_copy;
00288     }
00289 
00290   result = this->ssl_connect (new_stream, timeout);
00291 
00292   if (result == -1)
00293     new_stream.close ();
00294 
00295   return result;
00296 }
00297 
00298 // Try to complete a non-blocking connection.
00299 
00300 int
00301 ACE_SSL_SOCK_Connector::complete (ACE_SSL_SOCK_Stream &new_stream,
00302                                   ACE_Addr *remote_sap,
00303                                   const ACE_Time_Value *tv)
00304 {
00305   ACE_TRACE ("ACE_SSL_SOCK_Connector::complete");
00306 
00307   // Take into account the time to complete the basic TCP handshake
00308   // and the SSL handshake.
00309   ACE_Time_Value time_copy;
00310   ACE_Countdown_Time countdown (&time_copy);
00311   if (tv != 0)
00312     {
00313       time_copy += *tv;
00314       countdown.start ();
00315     }
00316 
00317   // Only attempt to complete the TCP connection if it that hasn't
00318   // already been done.
00319   ACE_INET_Addr raddr;
00320   if (new_stream.peer ().get_remote_addr (raddr) != 0
00321       && this->connector_.complete (new_stream.peer (),
00322                                     remote_sap,
00323                                     tv) == -1)
00324     return -1;
00325 
00326   // The handle in the SSL_SOCK_Stream should have already been set in
00327   // the connect() method.
00328 
00329   // If using a timeout, update the countdown timer to reflect the time
00330   // spent on the connect itself, then pass the remaining time to
00331   // ssl_connect to bound the time on the handshake.
00332   if (tv != 0)
00333     {
00334       countdown.update ();
00335       tv = &time_copy;
00336     }
00337 
00338   if (this->ssl_connect (new_stream, tv) == -1)
00339     {
00340       new_stream.close ();
00341       return -1;
00342     }
00343 
00344   return 0;
00345 
00346 }
00347 
00348 
00349 ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector (
00350   ACE_SSL_SOCK_Stream &new_stream,
00351   const ACE_Addr &remote_sap,
00352   const ACE_Time_Value *timeout,
00353   const ACE_Addr &local_sap,
00354   int reuse_addr,
00355   int flags,
00356   int perms)
00357   : connector_ ()
00358 {
00359   ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
00360   this->connect (new_stream,
00361                  remote_sap,
00362                  timeout,
00363                  local_sap,
00364                  reuse_addr,
00365                  flags,
00366                  perms);
00367 }
00368 
00369 ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector (
00370   ACE_SSL_SOCK_Stream &new_stream,
00371   const ACE_Addr &remote_sap,
00372   ACE_QoS_Params qos_params,
00373   const ACE_Time_Value *timeout,
00374   const ACE_Addr &local_sap,
00375   ACE_Protocol_Info *protocolinfo,
00376   ACE_SOCK_GROUP g,
00377   u_long flags,
00378   int reuse_addr,
00379   int perms)
00380   : connector_ ()
00381 {
00382   ACE_TRACE ("ACE_SSL_SOCK_Connector::ACE_SSL_SOCK_Connector");
00383 
00384   this->connect (new_stream,
00385                  remote_sap,
00386                  qos_params,
00387                  timeout,
00388                  local_sap,
00389                  protocolinfo,
00390                  g,
00391                  flags,
00392                  reuse_addr,
00393                  perms);
00394 }

Generated on Mon Jun 16 13:15:55 2003 for ACE_SSL by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002