Documentation

Generated on Thu Aug 31 00:02:28 2006

 

Data.cpp

Go to the documentation of this file.
00001 
00002 // $Id: Data.cpp,v 1.13 2005/08/23 19:32:31 klas Exp $
00003 //
00004 // Usage: Data class. inherited from Connection, everything pertaining to
00005 //        data connection goes here.
00006 //
00007 //  A part of babyftpd, licensed under the GNU GPL, see the file
00008 //    LICENSE for complete information.
00010 
00011 #define DATA_CPP
00012 #define NETINCLS
00013 #define BABY_CORE
00014 #include "Data.h"
00015 
00016 Data::Data(User *user, int file_id, string file_name, int trans_type)
00017   : Connection()
00018 {
00019   this->thread_id(0); // data_wrapper sets this to it's own.
00020   this->_file_id = file_id;
00021   this->_file_name = file_name;
00022   this->user = user;
00023   this->_settings = user->settings();
00024   this->addr(user->data_addr());
00025   struct timeval tv = {1, 0};
00026   this->timeout(tv);
00027   if(trans_type == 1)
00028     this->settings(RETR_TRANS, B_SET);
00029 
00030   this->settings(DATA_OPEN, B_SET);
00031 #ifdef USE_TLS
00032   this->settings(TLS_INITED, B_RESET);
00033   this->settings(TLS_ENABLED, B_RESET);
00034 #endif // USE_TLS
00035 
00036   if(this->settings(PASSIVE))
00037     this->open_passive();
00038   else // ACTIVE
00039     this->open_active();
00040 
00041   // if the data connection comes from another host than the
00042   // ctrl connection we drop it.. unless the user is tls protected.
00043   if(this->addr().sin_addr.s_addr != user->addr().sin_addr.s_addr)
00044   {
00045 #ifdef USE_TLS
00046     if(!user->settings(TLS_ENABLED))
00047     {
00048 #endif // USE_TLS
00049       close(this->socket_id());
00050       this->settings(DATA_OPEN, B_RESET);
00051     }
00052 #ifdef USE_TLS
00053   }
00054 #endif //USE_TLS
00055 }
00056 
00057 void Data::open_passive()
00058 {
00059   socklen_t len = sizeof(this->addr());
00060   struct sockaddr_in temp_addr = this->addr();
00061 
00062   fd_set acc_set;
00063   FD_ZERO(&acc_set);
00064   FD_SET(user->data_id(), &acc_set);
00065   struct timeval tv = this->timeout();
00066 
00067   if(select(user->data_id() + 1, &acc_set, NULL, NULL, &tv) > 0)
00068   {
00069     int ret = accept(user->data_id(),
00070         reinterpret_cast<struct sockaddr*>(&temp_addr), &len);
00071     this->socket_id(ret);
00072     this->addr(temp_addr);
00073   }
00074   else
00075     this->settings(DATA_OPEN, B_RESET);
00076 
00077   close(user->data_id());
00078 }
00079 
00080 void Data::open_active()
00081 {
00082   this->socket_id(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
00083 
00084   int on = 1;
00085   setsockopt(this->socket_id(), SOL_SOCKET, SO_REUSEADDR,
00086       (static_cast<void*>(&on)), sizeof(on));
00087   struct sockaddr_in my_addr;
00088   my_addr.sin_port = htons(config->general.data_port);
00089   my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
00090 
00091   uid_t old_uid = 0;
00092   // if dataport is below 1024 we need root.
00093   if(config->general.data_port <= 1024)
00094   {
00095     old_uid = geteuid();
00096     seteuid(0);
00097   }
00098   int ret = bind(this->socket_id(), reinterpret_cast<struct sockaddr*>
00099       (&my_addr), sizeof(my_addr));
00100   if(config->general.data_port <= 1024)
00101     seteuid(old_uid);
00102 
00103   if(ret != 0)
00104     logging->log_this(3, TYPE_INFO,
00105         "Failed to bind to data port " + util.itos(config->general.data_port)
00106         + ", falling back to arbitrary port.");
00107 
00108   struct sockaddr_in tmp_addr = this->addr();
00109 
00110   // go into nonblocking
00111   long sock_arg = fcntl(this->socket_id(), F_GETFL, NULL);
00112   sock_arg |= O_NONBLOCK;
00113   fcntl(this->socket_id(), F_SETFL, sock_arg);
00114 
00115   int sock_err = connect(this->socket_id(), reinterpret_cast<struct sockaddr*>
00116         (&tmp_addr), sizeof(tmp_addr));
00117   this->addr(tmp_addr);
00118 
00119   if(sock_err < 0)
00120     if(errno == EINPROGRESS)
00121     {
00122       struct timeval tv = this->timeout();
00123       fd_set con_set;
00124       FD_ZERO(&con_set);
00125       FD_SET(this->socket_id(), &con_set);
00126       if(select(this->socket_id() + 1, NULL, &con_set, NULL, &tv) < 0)
00127         this->settings(DATA_OPEN, B_RESET);
00128     }
00129     else
00130       this->settings(DATA_OPEN, B_RESET);
00131 
00132   // leave non blocking
00133   long sock_arg2 = fcntl(this->socket_id(), F_GETFL, NULL);
00134   sock_arg2 &= (~O_NONBLOCK);
00135   fcntl(this->socket_id(), F_SETFL, sock_arg2);
00136 }
00137 
00138 Data::~Data()
00139 {
00140   if(this->_file_id != -1)
00141     close(this->_file_id);
00142 
00143   this->user->transfered(
00144       this->user->transfered() + this->transfered());
00145 
00146   if(this->thread_id())
00147   {
00148     BABY_WRLOCK(user->lock);
00149     user->data_vec.erase(user->get_data_it(this->thread_id()));
00150     BABY_UNLOCK(user->lock);
00151     logging->log_this(4, TYPE_INFO, "data thread " +
00152         util.itos(this->thread_id()) +
00153         " exiting. Remaining data connections for " + user->user_name() +
00154         " is: " + util.itos(user->data_vec.size()));
00155   }
00156 }
00157 
00158 void kill_data(void *data)
00159 {
00160   delete static_cast<Data*>(data);
00161 }