NewNet/nnratelimiter.cpp

00001 /*  NewNet - A networking framework in C++
00002     Copyright (C) 2006 Ingmar K. Steen (iksteen@gmail.com)
00003 
00004     This program is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018  */
00019 
00020 #include "nnratelimiter.h"
00021 #include "platform.h"
00022 #include "util.h"
00023 
00024 #include <vector>
00025 #include <queue>
00026 #include <algorithm>
00027 #include <iostream>
00028 
00029 /* Keep at most x seconds of data in the rate buffer */
00030 #define MAX_HISTORY 5
00031 
00032 #ifndef DOXYGEN_UNDOCUMENTED
00033 typedef std::pair<struct timeval, ssize_t> RateData;
00034 struct NewNet::RateLimiter::Data
00035 {
00036   std::vector<RateData> rateData;
00037 };
00038 #endif // DOXYGEN_UNDOCUMENTED
00039 
00040 NewNet::RateLimiter::RateLimiter()
00041 {
00042   m_Limit = -1;
00043   m_Data = new NewNet::RateLimiter::Data;
00044 }
00045 
00046 #ifndef DOXYGEN_UNDOCUMENTED
00047 NewNet::RateLimiter::~RateLimiter()
00048 {
00049   delete m_Data;
00050 }
00051 #endif // DOXYGEN_UNDOCUMENTED
00052 
00053 void
00054 NewNet::RateLimiter::transferred(ssize_t n)
00055 {
00056   struct timeval now;
00057   gettimeofday(&now, 0);
00058   m_Data->rateData.push_back(RateData(now, n));
00059 }
00060 
00061 #ifndef timercmp
00062 #define timercmp(tvp, uvp, cmp)\
00063   ((tvp)->tv_sec cmp (uvp)->tv_sec ||\
00064   (tvp)->tv_sec == (uvp)->tv_sec &&\
00065   (tvp)->tv_usec cmp (uvp)->tv_usec)
00066 #endif
00067 
00068 void
00069 NewNet::RateLimiter::flush()
00070 {
00071   /* Flush all entries that are older than MAX_HISTORY second(s) */
00072   struct timeval tv;
00073   gettimeofday(&tv, 0);
00074   tv.tv_sec -= MAX_HISTORY;
00075   while((! m_Data->rateData.empty()) && timercmp(&tv, &m_Data->rateData.front().first, >))
00076     m_Data->rateData.erase(m_Data->rateData.begin());
00077 }
00078 
00079 long
00080 NewNet::RateLimiter::nextWindow()
00081 {
00082   flush();
00083 
00084   if(m_Limit == -1)
00085     return 0;
00086   else if(m_Limit == 0)
00087     return 60000;
00088 
00089   ssize_t total = 0;
00090   std::vector<RateData>::reverse_iterator it, end = m_Data->rateData.rend();
00091   for(it = m_Data->rateData.rbegin(); it != end; ++it)
00092   {
00093     total += (*it).second;
00094     if(total >= m_Limit)
00095     {
00096       /* Rate limit will be 'unbreached' one second after this frame. */
00097 
00098       struct timeval now;
00099       gettimeofday(&now, 0);
00100 
00101       struct timeval tv((*it).first);
00102       tv.tv_sec += 1;
00103 
00104       long d = difftime(tv, now);
00105       if(d <= 0)
00106         return 0;
00107       else
00108         return d + 50; /* Make sure we don't wake up too early */
00109     }
00110   }
00111 
00112   return 0;
00113 }

Generated on Sun Jan 7 14:00:01 2007 for NewNet by  doxygen 1.5.1