smtpthread/SMTPConnectionPool.cc

00001 // DOCUMENT:  SMTPConnectionPool-Class
00002 // VERSION:   $Revision: 1.5 $
00003 // DATE:      $Date: 2007-10-26 23:09:19 $
00004 // AUTHOR:    M.Beranek
00005 // COPYRIGHT: M.Beranek
00006 
00007 #include <iostream>
00008 #include <string>
00009 #include <unistd.h>
00010 #include <vector>
00011 #include <math.h>
00012 #include "SMTPConnectionPool.h"
00013 
00014 using namespace std;
00015 
00016 namespace SmtpThread
00017 {
00018 // --------------------------------------------------------------------------
00019     /**
00020      * Default-Constructor:
00021      */
00022     SMTPConnectionPool::SMTPConnectionPool()
00023     {
00024         init();
00025     }
00026     
00027     
00028 // --------------------------------------------------------------------------
00029     /**
00030      * Destructor. Clean up all connections.
00031      */
00032     SMTPConnectionPool::~SMTPConnectionPool()
00033     {
00034         if( _optimzePoolSize )
00035         {
00036             cout << "last pool-size: " << pool.size() << endl;
00037             cout << "avg. number of parallel connections: " << _avgNumOfTries << " +-" << _rms << endl;;
00038         }
00039         close();
00040     }
00041     
00042     
00043 // --------------------------------------------------------------------------
00044     /**
00045      * Initializes an SMTP-Connection-Pool with a default
00046      * pool-size of 30 connections.
00047      */
00048     void SMTPConnectionPool::init()
00049     {
00050         
00051         _minPoolSize = 1;
00052         _maxPoolSize = 100;
00053         _optimzePoolSize = true;
00054         
00055         _statsTotalMails    = 0;
00056         _statsTotalErrors   = 0;
00057         _statsMailsAfterOpt = 0;
00058         _avgNumOfTries      = 0;
00059         _rms                = 0;
00060         
00061         _myHostname = "localhost";
00062         _smtpHost   = "127.0.0.1";
00063         _smtpPort   = 25;
00064         
00065         setPoolSize( 1 );
00066         
00067     }
00068     
00069     
00070 // --------------------------------------------------------------------------
00071     /**
00072      * Closes all opened connections. Mails, wich are submitted
00073      * to theses connections, are sent before the connection is
00074      * actually closed.
00075      */
00076     void SMTPConnectionPool::close()
00077     {
00078         // for all pooled connections:
00079         for( unsigned long idx = 0; idx < pool.size(); idx++ )
00080         {
00081             // stop threading:
00082             pool[ idx ]->Stop();
00083         }
00084     }
00085     
00086     
00087 // --------------------------------------------------------------------------
00088     /**
00089      * Accepts a message and delegates it to one of the opened
00090      * connections in the connection-pool.
00091      * @param string from Sender-Email
00092      * @param string to Receiver-Email
00093      * @param string msg Email-Body, containing headers like subject, from, to etc.
00094      */
00095     int SMTPConnectionPool::sendMail( string& from, string& to, string& msg )
00096     {
00097         // success or not:
00098         bool found = false;
00099         
00100         // the connection, which is currentlx checked:
00101         unsigned long conNumber = 0;
00102         
00103         // conter for the number pool-runs:
00104         int numCheck = 0;
00105         
00106         // maximum number of pool-runs to find a ready connection:
00107         int maxTries = 100;
00108         
00109         // the currently checked connection:
00110         ThreadedSMTPConnection *smtp;
00111         
00112         // count messages:
00113         _statsTotalMails ++;
00114         _statsMailsAfterOpt ++;
00115         
00116         // try finding a free connection:
00117         while( ! found )
00118         {
00119             //cout << "trying connection " << conNumber << endl;
00120             
00121             // get connection from pool, increment connetion-counter:
00122             smtp = pool[ conNumber++ ];
00123             
00124             // if connection is ready:
00125             if( smtp->isReady() )
00126             {
00127                 
00128                 // set while-condition:
00129                 found = true;
00130                 
00131                 // delegate message to a connection:
00132                 smtp->sendMail( from, to, msg );
00133                 
00134                 // cout << "connection: " << conNumber -1 << endl;
00135                 
00136                 // If we should optimze the pool-size:
00137                 if( _optimzePoolSize )
00138                 {
00139                     
00140                     // Calculate RMS (Root-Mean-Square):
00141                     double d = _avgNumOfTries - 1.0 * ( numCheck +1 ) * ( conNumber );
00142                     double dSquare = d * d;
00143                     double curremtRMS = sqrt( dSquare );
00144                     
00145                     // Average number of tries / Average RMS:
00146                     if( (_statsTotalMails - _statsTotalErrors) > 0 )
00147                     {
00148                         // _avgNumOfTries, weight: number of all successfull mails till now (i.e without current mail).
00149                         // current number of tries: (i.e. pool-runs * conNumber, weight: 1.
00150                         // pool-runs: numCheck +1 (numCheck starts with 0)
00151                         // normalized by all successfull sent mails.
00152                         _avgNumOfTries = (
00153                                 ( 1.0 * (
00154                                 ( _statsTotalMails - _statsTotalErrors -1 ) * _avgNumOfTries
00155                                 +
00156                                 ( numCheck +1 ) * ( conNumber ) )
00157                                 )
00158                                 /
00159                                 (
00160                                 1.0 * ( _statsTotalMails - _statsTotalErrors )
00161                                 )
00162                                 );
00163                         
00164                         // _rms, weight: number of all successfull mails till now (i.e without current mail).
00165                         // currentRMS, weight: 1.
00166                         _rms = (
00167                                 ( 1.0 * (
00168                                 ( _statsTotalMails - _statsTotalErrors -1 ) * _rms
00169                                 +
00170                                 curremtRMS )
00171                                 )
00172                                 /
00173                                 (
00174                                 1.0 * ( _statsTotalMails - _statsTotalErrors )
00175                                 )
00176                                 );
00177                         
00178                         // cout << "avg. RMS: " << _rms << endl;
00179                     }
00180                     
00181                     
00182                     // only if we have more mails sent than our current pool-size:
00183                     //if( _statsTotalMails > pool.size() )
00184                     if( _statsMailsAfterOpt > pool.size() )
00185                     {
00186                         // for now: opt. poolsize = avg-num-of-tries + 2 * RMS.
00187                         unsigned long optPoolSize = (unsigned long) ceil( _avgNumOfTries + 2.0 * _rms );
00188                         
00189                         // if pool-size differs:
00190                         if( ( pool.size() < optPoolSize ) || ( pool.size() > optPoolSize +1 ) )
00191                         {
00192                             // if new pool-size within our limits:
00193                             if( ( optPoolSize < _maxPoolSize ) && ( optPoolSize > _minPoolSize ) )
00194                             {
00195                                 // set the poolsize:
00196                                 setPoolSize( optPoolSize );
00197                                 
00198                                 // reset counter:
00199                                 _statsMailsAfterOpt = 0;
00200                             }
00201                         }
00202                     }
00203                 }
00204                 
00205                 // return success:
00206                 return 0;
00207             }
00208             
00209             // after the last connection is checked
00210             // (i.e. after a complete pool-run):
00211             if( conNumber >= pool.size() )
00212             {;
00213              
00214              // start again:
00215              conNumber = 0;
00216              
00217              // increment the number of pool-runs:
00218              numCheck++;
00219              
00220              // wait a few micro-seconds:
00221              // 1s    = 1000000
00222              // 0.5s  =  500000
00223              // 0.25s =  250000
00224              usleep( 250000 );
00225              
00226              // if maximum of pool-runs reached:
00227              if( numCheck > maxTries )
00228              {
00229                  
00230                  // count errors:
00231                  _statsTotalErrors ++;
00232                  
00233                  // fail:
00234                  return -1;
00235                  
00236              }
00237             }
00238         }
00239         // just to avoid compiler-warning:
00240         return -1;
00241     }
00242     
00243     
00244 // --------------------------------------------------------------------------
00245     /**
00246      * Sets the pool-size.
00247      *
00248      * If pool-size is enlarged, the missing connection are set up automatically.
00249      * If pool-size is decreased, the opend connections will be closed and
00250      * destroyed. If mail is unsent in a connection, these mails are sent before
00251      * closing.
00252      *
00253      * @param unsigned long poolSize number of connections in pool
00254      */
00255     void SMTPConnectionPool::setPoolSize( unsigned long poolSize )
00256     {
00257         // Debug-Ouptut:
00258         cout << "adjusting pool-size to " << poolSize << endl;
00259         
00260         // current pool-size:
00261         unsigned long pSize = pool.size();
00262         
00263         // enlarge pool-size:
00264         if( poolSize > pSize )
00265         {
00266             
00267             // create new connections until pool-size is reached:
00268             while( pool.size() < poolSize )
00269             {
00270                 // initialize connections:
00271                 ThreadedSMTPConnection* con = new ThreadedSMTPConnection();
00272                 
00273                 // set mailhost:
00274                 con->setSMTPHost( _smtpHost );
00275                 con->setSMTPPort( _smtpPort );
00276                 con->setMyHostname( _myHostname );
00277                 
00278                 // init connection:
00279                 // con->openConnection();
00280                 
00281                 // start threading:
00282                 con->Start( (void*) 0 );
00283                 
00284                 // push into vector:
00285                 pool.push_back( con );
00286             }
00287         }
00288         
00289         // decrease pool-size:
00290         if( poolSize < pSize )
00291         {
00292             
00293             // destroy connections until pool-size is reached:
00294             while( pool.size() > poolSize )
00295             {
00296                 
00297                 // The destructor of the "SMTPConnection"-object
00298                 // gets called automatically by "pop_back", so there
00299                 // is no need to call "delete" on the object.
00300                 
00301                 // remove last connection from vector:
00302                 pool.pop_back();
00303                 
00304             }
00305         }
00306     }
00307     
00308     
00309 // --------------------------------------------------------------------------
00310     /**
00311      * Returns the current size of the connection-pool.
00312      *
00313      * @return unsigned long pool-size
00314      */
00315     unsigned long SMTPConnectionPool::getPoolSize()
00316     {
00317         // return pool-size:
00318         return pool.size();
00319     }
00320     
00321     
00322 // --------------------------------------------------------------------------
00323     void SMTPConnectionPool::setSMTPHost( string host )
00324     {
00325         _smtpHost = host;
00326         
00327         ThreadedSMTPConnection* smtp;
00328         for( unsigned long idx = 0; idx < pool.size(); idx++  )
00329         {
00330             smtp = pool[ idx ];
00331             smtp->setSMTPHost( host );
00332         }
00333     }
00334     
00335     
00336 // --------------------------------------------------------------------------
00337     void SMTPConnectionPool::setSMTPPort( int port )
00338     {
00339         _smtpPort = port;
00340         
00341         ThreadedSMTPConnection* smtp;
00342         for( unsigned long idx = 0; idx < pool.size(); idx++  )
00343         {
00344             smtp = pool[ idx ];
00345             smtp->setSMTPPort( port );
00346         }
00347     }
00348     
00349     
00350 // --------------------------------------------------------------------------
00351     void SMTPConnectionPool::setMyHostname( string myname )
00352     {
00353         _myHostname = myname;
00354         
00355         ThreadedSMTPConnection* smtp;
00356         for( unsigned long idx = 0; idx < pool.size(); idx++  )
00357         {
00358             smtp = pool[ idx ];
00359             smtp->setMyHostname( myname );
00360         }
00361     }
00362     
00363     
00364 // --------------------------------------------------------------------------
00365     void SMTPConnectionPool::setOptimizePool( bool opt )
00366     {
00367         _optimzePoolSize = opt;
00368     }
00369     
00370     
00371 // --------------------------------------------------------------------------
00372     void SMTPConnectionPool::setMinPoolSize( long minimum )
00373     {
00374         _minPoolSize = minimum;
00375         
00376         // Adjust Poolsize:
00377         if( pool.size() < _minPoolSize )
00378         {
00379             setPoolSize( _minPoolSize );
00380         }
00381     }
00382     
00383     
00384 // --------------------------------------------------------------------------
00385     void SMTPConnectionPool::setMaxPoolSize( long maximum )
00386     {
00387         _maxPoolSize = maximum;
00388         
00389         // Adjust Poolsize:
00390         if( pool.size() > _maxPoolSize )
00391         {
00392             setPoolSize( _maxPoolSize );
00393         }
00394     }
00395     
00396 }

Generated on Thu Nov 1 09:51:21 2007 for libSmtpThread by  doxygen 1.5.1