]> git.stg.codes - stg.git/blobdiff - projects/stargazer/user.cpp
Merge branch 'master' of madf.dyndns.org:/var/git/stg
[stg.git] / projects / stargazer / user.cpp
index 6c3286026b1e5b6883e67b514834542867687adc..38bab82c2a2f3e2b47306dd1f822adaf6690740e 100644 (file)
@@ -110,14 +110,11 @@ ipIndex = ipIdx;
 password = "*_EMPTY_PASSWORD_*";
 tariffName = NO_TARIFF_NAME;
 connected = 0;
-traffStatInUse = 0;
-traffStat = &traffStatInternal[0];
 tariff = tariffs->GetNoTariff();
 ips = StrToIPS("*");
 deleted = false;
 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
 lastWriteDeatiledStat = stgTime;
-lastSwapDeatiledStat = stgTime;
 
 property.tariffName.AddBeforeNotifier(&tariffNotifier);
 property.passive.AddBeforeNotifier(&passiveNotifier);
@@ -126,8 +123,6 @@ currIP.AddAfterNotifier(&ipNotifier);
 
 lastScanMessages = 0;
 
-writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
-
 pthread_mutexattr_t attr;
 pthread_mutexattr_init(&attr);
 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
@@ -192,17 +187,13 @@ if (&u == this)
     return;
 
 connected = 0;
-traffStatInUse = 0;
 
 ipIndex = u.ipIndex;
 
 deleted = u.deleted;
-traffStat = &traffStatInternal[traffStatInUse % 2];
-traffStatToWrite = &traffStatInternal[(traffStatInUse +1) % 2];
 
 lastWriteStat = u.lastWriteStat;
 lastWriteDeatiledStat = u.lastWriteDeatiledStat;
-lastSwapDeatiledStat = u.lastSwapDeatiledStat;
 
 settings = u.settings;
 
@@ -213,7 +204,7 @@ currIP.AddAfterNotifier(&ipNotifier);
 
 lastScanMessages = 0;
 
-writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
+property.SetProperties(u.property);
 
 pthread_mutexattr_t attr;
 pthread_mutexattr_init(&attr);
@@ -239,9 +230,9 @@ id = userIDGenerator.GetNextID();
 int USER::ReadConf()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-USER_CONF uc;
+USER_CONF conf;
 
-if (store->RestoreUserConf(&uc, login))
+if (store->RestoreUserConf(&conf, login))
     {
     WriteServLog("Cannot read conf for user %s.", login.c_str());
     WriteServLog("%s", store->GetStrError().c_str());
@@ -250,33 +241,7 @@ if (store->RestoreUserConf(&uc, login))
     return -1;
     }
 
-password = uc.password;
-passive = uc.passive;
-disabled = uc.disabled;
-disabledDetailStat = uc.disabledDetailStat;
-alwaysOnline = uc.alwaysOnline;
-tariffName = uc.tariffName;
-address = uc.address;
-phone = uc.phone;
-email = uc.email;
-note = uc.note;
-realName = uc.realName;
-group = uc.group;
-credit = uc.credit;
-nextTariff = uc.nextTariff;
-userdata0 = uc.userdata[0];
-userdata1 = uc.userdata[1];
-userdata2 = uc.userdata[2];
-userdata3 = uc.userdata[3];
-userdata4 = uc.userdata[4];
-userdata5 = uc.userdata[5];
-userdata6 = uc.userdata[6];
-userdata7 = uc.userdata[7];
-userdata8 = uc.userdata[8];
-userdata9 = uc.userdata[9];
-
-creditExpire = uc.creditExpire;
-ips = uc.ips;
+property.SetConf(conf);
 
 tariff = tariffs->FindByName(tariffName);
 if (tariff == NULL)
@@ -286,15 +251,33 @@ if (tariff == NULL)
     return -1;
     }
 
+std::vector<STG_MSG_HDR> hdrsList;
+
+if (store->GetMessageHdrs(&hdrsList, login))
+    {
+    printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
+    return -1;
+    }
+
+std::vector<STG_MSG_HDR>::const_iterator it;
+for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
+    {
+    STG_MSG msg;
+    if (store->GetMessage(it->id, &msg, login) == 0)
+        {
+        messages.push_back(msg);
+        }
+    }
+
 return 0;
 }
 //-----------------------------------------------------------------------------
 int USER::ReadStat()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-USER_STAT us;
+USER_STAT stat;
 
-if (store->RestoreUserStat(&us, login))
+if (store->RestoreUserStat(&stat, login))
     {
     WriteServLog("Cannot read stat for user %s.", login.c_str());
     WriteServLog("%s", store->GetStrError().c_str());
@@ -303,14 +286,7 @@ if (store->RestoreUserStat(&us, login))
     return -1;
     }
 
-up = us.up;
-down = us.down;
-cash = us.cash;
-freeMb = us.freeMb;
-lastCashAdd = us.lastCashAdd;
-lastCashAddTime = us.lastCashAddTime;
-passiveTime = us.passiveTime;
-lastActivityTime = us.lastActivityTime;
+property.SetStat(stat);
 
 return 0;
 }
@@ -318,39 +294,11 @@ return 0;
 int USER::WriteConf()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-USER_CONF uc;
-
-uc.password = password;
-uc.passive = passive;
-uc.disabled = disabled;
-uc.disabledDetailStat = disabledDetailStat;
-uc.alwaysOnline = alwaysOnline;
-uc.tariffName = tariffName;
-uc.address = address;
-uc.phone = phone;
-uc.email = email;
-uc.note = note;
-uc.realName = realName;
-uc.group = group;
-uc.credit = credit;
-uc.nextTariff = nextTariff;
-uc.userdata[0] = userdata0;
-uc.userdata[1] = userdata1;
-uc.userdata[2] = userdata2;
-uc.userdata[3] = userdata3;
-uc.userdata[4] = userdata4;
-uc.userdata[5] = userdata5;
-uc.userdata[6] = userdata6;
-uc.userdata[7] = userdata7;
-uc.userdata[8] = userdata8;
-uc.userdata[9] = userdata9;
-
-uc.creditExpire = creditExpire;
-uc.ips = ips;
+USER_CONF conf(property.GetConf());
 
 printfd(__FILE__, "USER::WriteConf()\n");
 
-if (store->SaveUserConf(uc, login))
+if (store->SaveUserConf(conf, login))
     {
     WriteServLog("Cannot write conf for user %s.", login.c_str());
     WriteServLog("%s", store->GetStrError().c_str());
@@ -365,20 +313,11 @@ return 0;
 int USER::WriteStat()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-USER_STAT us;
-
-us.up = up;
-us.down = down;
-us.cash = cash;
-us.freeMb = freeMb;
-us.lastCashAdd = lastCashAdd;
-us.lastCashAddTime = lastCashAddTime;
-us.passiveTime = passiveTime;
-us.lastActivityTime = lastActivityTime;
+USER_STAT stat(property.GetStat());
 
 printfd(__FILE__, "USER::WriteStat()\n");
 
-if (store->SaveUserStat(us, login))
+if (store->SaveUserStat(stat, login))
     {
     WriteServLog("Cannot write stat for user %s.", login.c_str());
     WriteServLog("%s", store->GetStrError().c_str());
@@ -395,21 +334,11 @@ return 0;
 int USER::WriteMonthStat()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-USER_STAT us;
-struct tm * t1;
 time_t tt = stgTime - 3600;
-t1 = localtime(&tt);
-
-us.up = up;
-us.down = down;
-us.cash = cash;
-us.freeMb = freeMb;
-us.lastCashAdd = lastCashAdd;
-us.lastCashAddTime = lastCashAddTime;
-us.passiveTime = passiveTime;
-us.lastActivityTime = lastActivityTime;
-
-if (store->SaveMonthStat(us, t1->tm_mon, t1->tm_year, login))
+struct tm * t1 = localtime(&tt);
+
+USER_STAT stat(property.GetStat());
+if (store->SaveMonthStat(stat, t1->tm_mon, t1->tm_year, login))
     {
     WriteServLog("Cannot write month stat for user %s.", login.c_str());
     WriteServLog("%s", store->GetStrError().c_str());
@@ -567,10 +496,6 @@ if (store->WriteUserConnect(login, currIP))
 
 if (!fakeConnect)
     lastIPForDisconnect = currIP;
-
-//printfd(__FILE__, "Connect. user name \'%s\' ip=%s\n", login.c_str(), inet_ntostring(currIP).c_str());
-/*if (settings->GetLogUserConnectDisconnect())
-    WriteServLog("User \'%s\', %s: Connect.", login.c_str(), inet_ntostring(currIP).c_str());*/
 }
 //-----------------------------------------------------------------------------
 void USER::Disconnect(bool fakeDisconnect, const std::string & reason)
@@ -626,10 +551,6 @@ if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
     WriteServLog("%s", store->GetStrError().c_str());
     }
 
-//printfd(__FILE__, "Disconnect. User name \'%s\' ip=%s reason: '%s'\n", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str(), reason.c_str());
-/*if (settings->GetLogUserConnectDisconnect())
-    WriteServLog("User \'%s\', %s: Disconnect.", login.c_str(), inet_ntostring(lastIPForDisconnect).c_str());*/
-
 if (!fakeDisconnect)
     lastIPForDisconnect = 0;
 
@@ -680,7 +601,7 @@ void USER::Run()
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
-if (stgTime - lastWriteStat > settings->GetStatWritePeriod())
+if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
     {
     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
     WriteStat();
@@ -845,7 +766,8 @@ sessionUpload[dir] += len;
 
 //Add detailed stat
 
-if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
+if (!settings->GetWriteFreeMbTraffCost() &&
+     freeMb.ConstData() >= 0)
     cost = 0;
 
 #ifdef TRAFF_STAT_WITH_PORTS
@@ -855,25 +777,18 @@ IP_DIR_PAIR idp(ip, dir);
 #endif
 
 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
-lb = traffStat->lower_bound(idp);
-if (lb == traffStat->end())
+lb = traffStat.lower_bound(idp);
+if (lb == traffStat.end() || lb->first != idp)
     {
-    traffStat->insert(lb,
-                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
-                                                   STAT_NODE(len, 0, cost)));
+    traffStat.insert(lb,
+                     pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                  STAT_NODE(len, 0, cost)));
     }
 else
-    if (lb->first.dir == dir && lb->first.ip == ip)
-        {
-        lb->second.cash += cost;
-        lb->second.up += len;
-        }
-    else
-        {
-        traffStat->insert(lb,
-                          pair<IP_DIR_PAIR, STAT_NODE>(idp,
-                                                       STAT_NODE(len, 0, cost)));
-        }
+    {
+    lb->second.cash += cost;
+    lb->second.up += len;
+    }
 }
 //-----------------------------------------------------------------------------
 #ifdef TRAFF_STAT_WITH_PORTS
@@ -942,7 +857,8 @@ sessionDownload[dir] += len;
 
 //Add detailed stat
 
-if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
+if (!settings->GetWriteFreeMbTraffCost() &&
+     freeMb.ConstData() >= 0)
     cost = 0;
 
 #ifdef TRAFF_STAT_WITH_PORTS
@@ -952,25 +868,18 @@ IP_DIR_PAIR idp(ip, dir);
 #endif
 
 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
-lb = traffStat->lower_bound(idp);
-if (lb == traffStat->end())
+lb = traffStat.lower_bound(idp);
+if (lb == traffStat.end() || lb->first != idp)
     {
-    traffStat->insert(lb,
-                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
-                                                   STAT_NODE(0, len, cost)));
+    traffStat.insert(lb,
+                     pair<IP_DIR_PAIR, STAT_NODE>(idp,
+                                                  STAT_NODE(0, len, cost)));
     }
 else
-    if (lb->first.dir == dir && lb->first.ip == ip)
-        {
-        lb->second.cash += cost;
-        lb->second.down += len;
-        }
-    else
-        {
-        traffStat->insert(lb,
-                          pair<IP_DIR_PAIR, STAT_NODE>(idp,
-                                                       STAT_NODE(0, len, cost)));
-        }
+    {
+    lb->second.cash += cost;
+    lb->second.down += len;
+    }
 }
 //-----------------------------------------------------------------------------
 void USER::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
@@ -1043,39 +952,49 @@ else
 Run();
 }
 //-----------------------------------------------------------------------------
-void USER::ResetDetailStat()
+int USER::WriteDetailStat(bool hard)
 {
-STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
 
-traffStatToWrite->erase(traffStatToWrite->begin(), traffStatToWrite->end());
-}
-//-----------------------------------------------------------------------------
-int USER::WriteDetailStat()
-{
-STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+if (!traffStatSaved.second.empty())
+    {
+    if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
+        {
+        printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
+        WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
+        WriteServLog("%s", store->GetStrError().c_str());
+        return -1;
+        }
+    traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
+    }
+
+TRAFF_STAT ts;
+
+    {
+    STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+    ts.swap(traffStat);
+    }
 
-printfd(__FILE__, "USER::WriteDetailedStat(): size = %d\n", traffStatToWrite->size());
+printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
 
-if (traffStatToWrite->size() && !disabledDetailStat)
+if (ts.size() && !disabledDetailStat)
     {
-    if (store->WriteDetailedStat(traffStatToWrite, lastWriteDeatiledStat, login))
+    if (store->WriteDetailedStat(ts, lastWriteDeatiledStat, login))
         {
+        printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
         WriteServLog("%s", store->GetStrError().c_str());
+        if (!hard)
+            {
+            printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
+            STG_LOCKER lock(&mutex, __FILE__, __LINE__);
+            traffStatSaved.second.swap(ts);
+            traffStatSaved.first = lastWriteDeatiledStat;
+            }
+        return -1;
         }
     }
-lastWriteDeatiledStat = lastSwapDeatiledStat;
-return 0;
-}
-//-----------------------------------------------------------------------------
-int USER::SwapDetailStat()
-{
-STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-
-lastSwapDeatiledStat = stgTime;
-traffStatToWrite = &traffStatInternal[traffStatInUse % 2];
-traffStat = &traffStatInternal[++traffStatInUse % 2];
-
+lastWriteDeatiledStat = stgTime;
 return 0;
 }
 //-----------------------------------------------------------------------------
@@ -1232,7 +1151,18 @@ int USER::AddMessage(STG_MSG * msg)
 {
 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
 
-if (SendMessage(*msg) == 0)
+if (SendMessage(*msg))
+    {
+    if (store->AddMessage(msg, login))
+        {
+        errorStr = store->GetStrError();
+        WriteServLog("Error adding message: '%s'", errorStr.c_str());
+        printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
+        return -1;
+        }
+    messages.push_back(*msg);
+    }
+else
     {
     if (msg->header.repeat > 0)
         {
@@ -1246,100 +1176,87 @@ if (SendMessage(*msg) == 0)
         if (store->AddMessage(msg, login))
             {
             errorStr = store->GetStrError();
-            STG_LOGGER & WriteServLog = GetStgLogger();
-            WriteServLog("Error adding message %s", errorStr.c_str());
-            WriteServLog("%s", store->GetStrError().c_str());
+            WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
+            printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
             return -1;
             }
-        }
-    }
-else
-    {
-    if (store->AddMessage(msg, login))
-        {
-        errorStr = store->GetStrError();
-        STG_LOGGER & WriteServLog = GetStgLogger();
-        WriteServLog("Error adding message %s", errorStr.c_str());
-        WriteServLog("%s", store->GetStrError().c_str());
-        return -1;
+        messages.push_back(*msg);
         }
     }
 return 0;
 }
 //-----------------------------------------------------------------------------
-int USER::SendMessage(const STG_MSG & msg)
+int USER::SendMessage(STG_MSG & msg) const
 {
-STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-
-if (authorizedBy.empty())
-    {
-    return -1;
-    }
-
+// No lock `cause we are already locked from caller
 int ret = -1;
-set<const BASE_AUTH*>::iterator it;
-
-it = authorizedBy.begin();
+set<const BASE_AUTH*>::iterator it(authorizedBy.begin());
 while (it != authorizedBy.end())
     {
-    if ((*it)->SendMessage(msg, currIP) == 0)
+    if (!(*it++)->SendMessage(msg, currIP))
         ret = 0;
-    ++it;
+    }
+if (!ret)
+    {
+#ifndef DEBUG
+    //TODO: gcc v. 4.x generate ICE on x86_64
+    msg.header.lastSendTime = time(NULL);
+#else
+    msg.header.lastSendTime = stgTime;
+#endif
+    msg.header.repeat--;
     }
 return ret;
 }
 //-----------------------------------------------------------------------------
-int USER::ScanMessage()
+void USER::ScanMessage()
 {
-STG_LOCKER lock(&mutex, __FILE__, __LINE__);
-
-vector<STG_MSG_HDR> hdrsList;
-
-if (store->GetMessageHdrs(&hdrsList, login))
-    {
-    printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
-    return -1;
-    }
+// No lock `cause we are already locked from caller
+// We need not check for the authorizedBy `cause it has already checked by caller
 
-for (unsigned i = 0; i < hdrsList.size(); i++)
+std::list<STG_MSG>::iterator it(messages.begin());
+while (it != messages.end())
     {
-
-    if (hdrsList[i].lastSendTime + hdrsList[i].repeatPeriod * 60 < (unsigned)stgTime)
+    if (settings->GetMessageTimeout() > 0 &&
+        difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
         {
-        STG_MSG msg;
-        if (store->GetMessage(hdrsList[i].id, &msg, login) == 0)
+        // Timeout exceeded
+        if (store->DelMessage(it->header.id, login))
             {
-            if (SendMessage(msg) == 0)
+            WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
+            printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
+            }
+        messages.erase(it++);
+        continue;
+        }
+    if (it->GetNextSendTime() <= stgTime)
+        {
+        if (SendMessage(*it))
+            {
+            // We need to check all messages in queue for timeout
+            ++it;
+            continue;
+            }
+        if (it->header.repeat < 0)
+            {
+            if (store->DelMessage(it->header.id, login))
                 {
-                msg.header.repeat--;
-                if (msg.header.repeat < 0)
-                    {
-                    printfd(__FILE__, "DelMessage\n");
-                    store->DelMessage(hdrsList[i].id, login);
-                    }
-                else
-                    {
-                    #ifndef DEBUG
-                    //TODO: gcc v. 4.x generate ICE on x86_64
-                    msg.header.lastSendTime = time(NULL);
-                    #else
-                    msg.header.lastSendTime = stgTime;
-                    #endif
-                    if (store->EditMessage(msg, login))
-                        {
-                        printfd(__FILE__, "EditMessage Error %s\n", store->GetStrError().c_str());
-                        }
-                    }
+                WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
+                printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
                 }
+            messages.erase(it++);
             }
         else
             {
-            WriteServLog("Cannot get message for user %s.", login.c_str());
-            WriteServLog("%s", store->GetStrError().c_str());
+            if (store->EditMessage(*it, login))
+                {
+                WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
+                printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
+                }
+            ++it;
             }
         }
     }
-return 0;
 }
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1369,8 +1286,10 @@ void CHG_IP_NOTIFIER::Notify(const uint32_t & from, const uint32_t & to)
 {
     printfd(__FILE__, "Change IP from %s to %s\n", inet_ntostring(from).c_str(), inet_ntostring(to).c_str());
     if (from != 0)
-        user->Disconnect(false, "Change IP");
+        if (user->connected)
+            user->Disconnect(false, "Change IP");
     if (to != 0)
-        user->Connect(false);
+        if (user->IsInetable())
+            user->Connect(false);
 }
 //-----------------------------------------------------------------------------