00001
00002
00003 #include "ace/INet/FTP_ClientRequestHandler.h"
00004
00005 #if !defined (__ACE_INLINE__)
00006 #include "ace/INet/FTP_ClientRequestHandler.inl"
00007 #endif
00008
00009 #include "ace/INet/INet_Log.h"
00010 #include "ace/INet/String_IOStream.h"
00011 #include "ace/Auto_Ptr.h"
00012 #include "ace/OS_NS_ctype.h"
00013 #include "ace/Connector.h"
00014 #include "ace/Acceptor.h"
00015 #include "ace/SOCK_Acceptor.h"
00016
00017 ACE_RCSID(NET_CLIENT,ACE_FTP_ClientRequestHandler,"$Id: FTP_ClientRequestHandler.cpp 91118 2010-07-17 10:29:57Z mcorino $")
00018
00019 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00020
00021 namespace ACE
00022 {
00023 namespace FTP
00024 {
00025
00026 ClientRequestHandler::SessionHolder::SessionHolder ()
00027 : session_ ()
00028 {
00029 }
00030
00031 ClientRequestHandler::SessionHolder::~SessionHolder()
00032 {
00033 }
00034
00035 ClientRequestHandler::SessionFactory::SessionFactory ()
00036 {
00037 }
00038
00039 ClientRequestHandler::SessionFactory::~SessionFactory ()
00040 {
00041 }
00042
00043 ACE::INet::ConnectionHolder*
00044 ClientRequestHandler::SessionFactory::create_connection (
00045 const ACE::INet::ConnectionKey& key) const
00046 {
00047 INET_TRACE ("FTP::ClientRequestHandler::SessionFactory::create_connection");
00048
00049 const INetConnectionKey& ikey = dynamic_cast<const INetConnectionKey&> (key);
00050
00051 SessionHolder* session_holder = 0;
00052 ACE_NEW_RETURN (session_holder,
00053 SessionHolder (),
00054 0);
00055 ACE_Auto_Ptr<SessionHolder> session_safe_ref (session_holder);
00056
00057 (*session_holder)->set_host (ikey.host (), ikey.port ());
00058
00059 if ((*session_holder)->connect (true))
00060 {
00061 return session_safe_ref.release ();
00062 }
00063
00064 return 0;
00065 }
00066
00067 ClientRequestHandler::Authentication::Authentication (
00068 const ACE_CString& realm,
00069 ACE_CString& user,
00070 ACE_CString& pw)
00071 : AuthenticationBase (),
00072 realm_ (realm),
00073 user_ (user),
00074 password_ (pw)
00075 {
00076 }
00077
00078 ClientRequestHandler::Authentication::~Authentication () {}
00079
00080 const ACE_CString& ClientRequestHandler::Authentication::scheme () const
00081 {
00082 return URL::protocol ();
00083 }
00084
00085 const ACE_CString& ClientRequestHandler::Authentication::realm () const
00086 {
00087 return this->realm_;
00088 }
00089
00090 const ACE_CString& ClientRequestHandler::Authentication::user () const
00091 {
00092 return this->user_;
00093 }
00094
00095 void ClientRequestHandler::Authentication::user (const ACE_CString& usr)
00096 {
00097 this->user_ = usr;
00098 }
00099
00100 const ACE_CString& ClientRequestHandler::Authentication::password () const
00101 {
00102 return this->password_;
00103 }
00104
00105 void ClientRequestHandler::Authentication::password (const ACE_CString& pw)
00106 {
00107 this->password_ = pw;
00108 }
00109
00110 const ACE_CString ClientRequestHandler::anonymous_user_ = "anonymous";
00111 const ACE_CString ClientRequestHandler::empty_;
00112
00113 ClientRequestHandler::ClientRequestHandler (bool passive_mode)
00114 : session_ (0),
00115 use_passive_mode_ (passive_mode),
00116 active_port_ (0),
00117 out_data_stream_ (0),
00118 in_data_stream_ (0),
00119 transfer_active_ (false)
00120 {
00121 this->out_data_stream_.set_interceptor (*this);
00122 this->in_data_stream_.set_interceptor (*this);
00123 }
00124
00125 ClientRequestHandler::~ClientRequestHandler ()
00126 {
00127 this->release_connection ();
00128 }
00129
00130 bool ClientRequestHandler::is_response_ok () const
00131 {
00132 return this->response_.is_completed_ok () ||
00133 (this->response_.is_preliminary_ok () &&
00134 !this->in_data_stream_.bad ());
00135 }
00136
00137 std::istream& ClientRequestHandler::handle_open_request (
00138 const ACE::INet::URL_Base& url)
00139 {
00140 const URL& ftp_url = dynamic_cast<const URL&> (url);
00141 return this->handle_get_request (ftp_url);
00142 }
00143
00144 std::istream& ClientRequestHandler::handle_get_request (
00145 const URL& ftp_url,
00146 bool binary)
00147 {
00148 if (this->initialize_connection (ftp_url.get_host (),
00149 ftp_url.get_port ()))
00150 {
00151 bool rc = true;
00152 if (this->session ()->is_new_connection () ||
00153 (!ftp_url.get_user_info ().empty () &&
00154 ftp_url.get_user_info () != this->current_user_))
00155 {
00156 if (!this->session ()->is_new_connection ())
00157 rc = this->logout ();
00158
00159 if (rc)
00160 {
00161 ACE_CString user = ftp_url.get_user_info ().empty () ?
00162 anonymous_user_ : ftp_url.get_user_info ();
00163 ACE_CString password = user;
00164 rc = this->handle_credentials (ftp_url, user, password);
00165 if (rc) rc = this->login (user, password);
00166 }
00167 }
00168
00169 if (rc) rc = this->finish_transfer ();
00170
00171 if (rc)
00172 {
00173 stream_type* data_stream =
00174 this->start_download (ftp_url.get_path (), binary);
00175 if (data_stream)
00176 {
00177
00178
00179 this->in_data_stream_.set_stream (data_stream);
00180 }
00181 else
00182 {
00183 rc = false;
00184 }
00185 }
00186
00187 if (!rc)
00188 {
00189 this->close_connection ();
00190
00191 this->handle_request_error(ftp_url);
00192 }
00193 }
00194 else
00195 {
00196 this->handle_connection_error (ftp_url);
00197 }
00198
00199 return this->response_stream ();
00200 }
00201
00202 void ClientRequestHandler::on_eof ()
00203 {
00204 this->finish_transfer ();
00205 }
00206
00207 bool ClientRequestHandler::initialize_connection (const ACE_CString& host,
00208 u_short port)
00209 {
00210 static const SessionFactory session_factory;
00211
00212 ACE::INet::ConnectionHolder* pch = 0;
00213 if (this->connection_cache ().claim_connection (INetConnectionKey (host, port),
00214 pch,
00215 session_factory))
00216 {
00217 this->session (dynamic_cast<SessionHolder*> (pch));
00218 return true;
00219 }
00220 else
00221 return false;
00222 }
00223
00224 bool ClientRequestHandler::handle_credentials (const URL& url,
00225 ACE_CString& user,
00226 ACE_CString& password)
00227 {
00228 Authentication authentication (url.get_host(),
00229 user,
00230 password);
00231 return URL::authenticate (authentication);
00232 }
00233
00234 void ClientRequestHandler::handle_request_error (const URL& )
00235 {
00236 }
00237
00238 void ClientRequestHandler::handle_connection_error (const URL& )
00239 {
00240 }
00241
00242 void ClientRequestHandler::release_connection ()
00243 {
00244 if (this->session_)
00245 {
00246 this->connection_cache ().release_connection (
00247 INetConnectionKey (this->session ()->get_host (),
00248 this->session ()->get_port ()),
00249 this->session_);
00250 this->session_ = 0;
00251 }
00252 }
00253
00254 void ClientRequestHandler::close_connection ()
00255 {
00256 if (this->session_)
00257 {
00258 this->connection_cache ().close_connection (
00259 INetConnectionKey (this->session ()->get_host (),
00260 this->session ()->get_port ()),
00261 this->session_);
00262 this->session_ = 0;
00263 }
00264 }
00265
00266 void ClientRequestHandler::quit_connection ()
00267 {
00268 this->logout ();
00269 this->close_connection ();
00270 }
00271
00272 bool ClientRequestHandler::logout ()
00273 {
00274 bool rc = true;
00275 if (this->session ()->is_connected ())
00276 {
00277 try
00278 {
00279 this->finish_transfer ();
00280 }
00281 catch (...)
00282 {
00283 }
00284 this->process_command (Request::FTP_QUIT);
00285 rc = this->response_.is_completed_ok ();
00286 this->current_user_ = anonymous_user_;
00287 this->session ()->close ();
00288 }
00289 return rc;
00290 }
00291
00292 bool ClientRequestHandler::login (const ACE_CString& user,
00293 const ACE_CString& password)
00294 {
00295
00296 this->session ()->receive_response (this->response_);
00297 if (this->response_.is_completed_ok ())
00298 {
00299
00300 this->process_command (Request::FTP_USER, user);
00301 if (this->response_.is_intermediate_ok ())
00302 {
00303 this->process_command (Request::FTP_PASS, password);
00304 }
00305 }
00306 return this->response_.is_completed_ok ();
00307 }
00308
00309 bool ClientRequestHandler::is_valid_path (const ACE_CString& path)
00310 {
00311 return this->process_command (Request::FTP_STAT, path) == Response::COMPLETED_OK;
00312 }
00313
00314 bool ClientRequestHandler::is_file (const ACE_CString& path)
00315 {
00316 return (this->is_valid_path (path) &&
00317 this->process_command (Request::FTP_CWD, path) != Response::COMPLETED_OK);
00318 }
00319
00320 bool ClientRequestHandler::is_dir (const ACE_CString& path)
00321 {
00322 return (this->is_valid_path (path) &&
00323 this->process_command (Request::FTP_CWD, path) == Response::COMPLETED_OK);
00324 }
00325
00326 bool ClientRequestHandler::set_filetype (bool binary)
00327 {
00328 return this->process_command (Request::FTP_TYPE, binary ? "I" : "A") == Response::COMPLETED_OK;
00329 }
00330
00331 ClientRequestHandler::stream_type*
00332 ClientRequestHandler::start_download (const ACE_CString& path, bool binary)
00333 {
00334 if (path.empty () || this->is_dir (path))
00335 {
00336 if (this->set_filetype (false))
00337 {
00338 return this->open_data_connection (Request::FTP_LIST, path);
00339 }
00340 }
00341 else
00342 {
00343 if (this->set_filetype (binary))
00344 {
00345 return this->open_data_connection (Request::FTP_RETR, path);
00346 }
00347 }
00348 return 0;
00349 }
00350
00351 ClientRequestHandler::stream_type*
00352 ClientRequestHandler::start_upload (const ACE_CString& path, bool binary)
00353 {
00354 if (this->set_filetype (binary))
00355 {
00356 return this->open_data_connection (Request::FTP_STOR, path);
00357 }
00358 return 0;
00359 }
00360
00361 bool ClientRequestHandler::finish_transfer ()
00362 {
00363 if (transfer_active_)
00364 {
00365 stream_type* old_stream = dynamic_cast<stream_type*> (this->in_data_stream_.set_stream (0));
00366 if (old_stream)
00367 {
00368
00369 const_cast<connection_type&> (old_stream->stream ()).remove_reference ();
00370
00371 delete old_stream;
00372 }
00373 old_stream = dynamic_cast<stream_type*> (this->out_data_stream_.set_stream (0));
00374 {
00375
00376 const_cast<connection_type&> (old_stream->stream ()).remove_reference ();
00377
00378 delete old_stream;
00379 }
00380
00381 this->transfer_active_ = false;
00382
00383 this->session ()->receive_response (this->response_);
00384 return this->response_.is_completed_ok ();
00385 }
00386 return true;
00387 }
00388
00389 bool ClientRequestHandler::abort_transfer ()
00390 {
00391 if (transfer_active_)
00392 {
00393 this->session ()->send_interrupt ();
00394 this->process_command (Request::FTP_ABOR);
00395 if (this->response_.status () == 426)
00396 this->session ()->receive_response (this->response_);
00397
00398 stream_type* old_stream = dynamic_cast<stream_type*> (this->in_data_stream_.set_stream (0));
00399 {
00400
00401 const_cast<connection_type&> (old_stream->stream ()).remove_reference ();
00402
00403 delete old_stream;
00404 }
00405 old_stream = dynamic_cast<stream_type*> (this->out_data_stream_.set_stream (0));
00406 {
00407
00408 const_cast<connection_type&> (old_stream->stream ()).remove_reference ();
00409
00410 delete old_stream;
00411 }
00412
00413 this->transfer_active_ = false;
00414
00415 return this->response_.is_completed_ok ();
00416 }
00417 return true;
00418 }
00419
00420 Response::StatusType
00421 ClientRequestHandler::process_command (const ACE_CString& cmd,
00422 const ACE_CString& arg)
00423 {
00424 if (this->session ()->send_request (this->request_(cmd) << arg))
00425 {
00426 this->session ()->receive_response (this->response_);
00427 }
00428 else
00429 {
00430 this->response_(0);
00431 }
00432 return this->response_.status_type ();
00433 }
00434
00435 ClientRequestHandler::stream_type*
00436 ClientRequestHandler::open_data_connection (const ACE_CString& cmd,
00437 const ACE_CString& arg)
00438 {
00439 if (this->use_passive_mode_)
00440 {
00441
00442 ACE_INET_Addr data_addr;
00443 if (this->get_passive_address (data_addr))
00444 {
00445
00446
00447
00448 unsigned long f_reactor =
00449 this->session ()->is_reactive() ? ACE_Synch_Options::USE_REACTOR : 0;
00450 ACE_Synch_Options sync_opt (ACE_Synch_Options::USE_TIMEOUT | f_reactor,
00451 this->session ()->timeout ());
00452
00453 typedef ACE_Connector<SessionHolder::session_type::connection_type,
00454 ACE_SOCK_CONNECTOR> connector_type;
00455 connector_type connector;
00456
00457
00458 SessionHolder::session_type::connection_type* data_connection = 0;
00459 ACE_NEW_NORETURN (data_connection,
00460 SessionHolder::session_type::connection_type(sync_opt));
00461 if (data_connection == 0)
00462 {
00463 return 0;
00464 }
00465
00466
00467 if (connector.connect (data_connection,
00468 data_addr,
00469 ACE_Synch_Options (0,
00470 this->session ()->timeout ())) == -1)
00471 {
00472 INET_ERROR (1, (LM_ERROR, DLINFO
00473 ACE_TEXT ("(%d) ACE_FTP_ClientRequestHandler::open_data_connection - ")
00474 ACE_TEXT ("failed to connect to %C:%d\n"),
00475 ACE_OS::last_error (),
00476 data_addr.get_host_name (),
00477 data_addr.get_port_number ()));
00478
00479
00480
00481 return 0;
00482 }
00483
00484
00485 data_connection->reference_counting_policy ().value (
00486 ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
00487
00488
00489 stream_type* data_stream = 0;
00490 ACE_NEW_NORETURN (data_stream,
00491 stream_type (data_connection));
00492 if (data_stream)
00493 {
00494 if (this->process_command (cmd, arg) == Response::PRELIM_OK)
00495 return data_stream;
00496
00497 delete data_stream;
00498 }
00499
00500 data_connection->remove_reference ();
00501 }
00502 }
00503 else
00504 {
00505
00506 ACE_INET_Addr data_addr;
00507 this->session ()->get_local_addr (data_addr);
00508 data_addr.set_port_number (this->active_port_);
00509
00510
00511 unsigned long f_reactor =
00512 this->session ()->is_reactive() ? ACE_Synch_Options::USE_REACTOR : 0;
00513 ACE_Synch_Options sync_opt (ACE_Synch_Options::USE_TIMEOUT | f_reactor,
00514 this->session ()->timeout ());
00515
00516 typedef ACE_Oneshot_Acceptor<SessionHolder::session_type::connection_type,
00517 ACE_SOCK_ACCEPTOR> acceptor_type;
00518 acceptor_type acceptor;
00519
00520
00521 if (acceptor.open (data_addr) == 0 &&
00522 acceptor.acceptor ().get_local_addr (data_addr) == 0)
00523 {
00524
00525 if (this->send_active_address (data_addr) &&
00526 this->process_command (cmd, arg) == Response::PRELIM_OK)
00527 {
00528
00529 SessionHolder::session_type::connection_type* data_connection = 0;
00530 ACE_NEW_NORETURN (data_connection,
00531 SessionHolder::session_type::connection_type(sync_opt));
00532 if (data_connection == 0)
00533 {
00534 return 0;
00535 }
00536
00537
00538 if (acceptor.accept (data_connection,
00539 0,
00540 ACE_Synch_Options (ACE_Synch_Options::USE_TIMEOUT,
00541 this->session ()->timeout ())) == -1)
00542 {
00543 INET_ERROR (1, (LM_ERROR, DLINFO
00544 ACE_TEXT ("(%d) ACE_FTP_ClientRequestHandler::open_data_connection - ")
00545 ACE_TEXT ("failed to accept connection to %C:%d\n"),
00546 ACE_OS::last_error (),
00547 data_addr.get_host_name (),
00548 data_addr.get_port_number ()));
00549
00550
00551
00552
00553 return 0;
00554 }
00555
00556
00557 data_connection->reference_counting_policy ().value (
00558 ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
00559
00560
00561 stream_type* data_stream = 0;
00562 ACE_NEW_NORETURN (data_stream,
00563 stream_type (data_connection));
00564 if (data_stream)
00565 {
00566 return data_stream;
00567 }
00568
00569 data_connection->remove_reference ();
00570 }
00571 }
00572 }
00573 return 0;
00574 }
00575
00576
00577 bool
00578 ClientRequestHandler::get_passive_address (ACE_INET_Addr& addr)
00579 {
00580
00581 if (this->session ()->supports_ftp_extensions ())
00582 {
00583 if (this->process_command (Request::FTP_EPSV) == Response::COMPLETED_OK)
00584 {
00585 return this->parse_ext_address (this->response_.response ()[0],
00586 addr);
00587 }
00588
00589 this->session ()->set_ftp_extension_support (false);
00590 }
00591
00592 if (this->process_command (Request::FTP_PASV) == Response::COMPLETED_OK)
00593 {
00594 return this->parse_address (this->response_.response ()[0],
00595 addr);
00596 }
00597 return false;
00598 }
00599
00600 bool
00601 ClientRequestHandler::parse_address (const ACE_CString& str, ACE_INET_Addr& addr)
00602 {
00603 static const int eof_ = std::char_traits<char>::eof ();
00604
00605 ACE::IOS::CString_OStream sos_host;
00606 u_short port_hi = 0, port_lo = 0;
00607
00608 ACE::IOS::CString_IStream sis (str);
00609 sis.ignore (str.length (), '(');
00610 int ch = sis.get ();
00611 if (ACE_OS::ace_isdigit (ch))
00612 {
00613 for (int i=0; i<4 ;++i)
00614 {
00615 if (ch == ',')
00616 {
00617 sos_host.put ('.');
00618 ch = sis.get ();
00619 }
00620 while (ch != eof_ && ACE_OS::ace_isdigit (ch))
00621 {
00622 sos_host.put (ch);
00623 ch = sis.get ();
00624 }
00625 }
00626 if (ch == ',')
00627 {
00628 sis >> port_hi;
00629 ch = sis.get ();
00630 if (ch == ',')
00631 {
00632 sis >> port_lo;
00633
00634 u_short port = port_hi*256 + port_lo;
00635 addr.set (port, sos_host.str ().c_str ());
00636 return true;
00637 }
00638 }
00639 }
00640 return false;
00641 }
00642
00643 bool
00644 ClientRequestHandler::parse_ext_address (const ACE_CString& str, ACE_INET_Addr& addr)
00645 {
00646 static const int eof_ = std::char_traits<char>::eof ();
00647
00648 ACE::IOS::CString_IStream sis (str);
00649 sis.ignore (str.length (), '(');
00650 int ch = sis.get ();
00651 if (ch != eof_)
00652 {
00653 int delim = ch;
00654 sis.ignore (str.length (), delim);
00655 sis.ignore (str.length (), delim);
00656 if (sis.peek () != eof_)
00657 {
00658 u_short port = 0;
00659 sis >> port;
00660 addr.set (port, this->session ()->get_host ().c_str ());
00661 return true;
00662 }
00663 }
00664 return false;
00665 }
00666
00667 bool
00668 ClientRequestHandler::send_active_address (const ACE_INET_Addr& addr)
00669 {
00670 ACE::IOS::CString_OStream arg;
00671 char ip_buf[128];
00672 if (addr.get_host_addr (ip_buf, sizeof(ip_buf)) == 0)
00673 {
00674 return false;
00675 }
00676 u_short port = addr.get_port_number ();
00677
00678 if (this->session ()->supports_ftp_extensions ())
00679 {
00680 arg << '|'
00681 << (addr.get_type () == AF_INET ? '1' : '2')
00682 << '|'
00683 << (&ip_buf[0])
00684 << '|'
00685 << port
00686 << '|';
00687 if (this->process_command (Request::FTP_EPRT, arg.str ()) == Response::COMPLETED_OK)
00688 {
00689 return true;
00690 }
00691
00692 this->session ()->set_ftp_extension_support (false);
00693
00694 arg.clear ();
00695 }
00696
00697 ACE_CString ip_addr = addr.get_host_addr (ip_buf, sizeof(ip_buf));
00698 ACE_CString::size_type pos;
00699 while ((pos = ip_addr.find ('.')) != ACE_CString::npos)
00700 {
00701 ip_addr[pos] = ',';
00702 }
00703 arg << ip_addr << ','
00704 << (port / 256)
00705 << ','
00706 << (port % 256);
00707 return (this->process_command (Request::FTP_PORT, arg.str ()) == Response::COMPLETED_OK);
00708 }
00709
00710 }
00711 }
00712
00713 ACE_END_VERSIONED_NAMESPACE_DECL