1 // IdleLogManager.cc
2 //
3 // Copyright (C) 2003, 2004, 2005, 2007, 2009, 2010, 2011 Rob Caelers <robc@krandor.org>
4 // All rights reserved.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #ifdef PLATFORM_OS_OSX
24 #include "OSXHelpers.hh"
25 #endif
26 
27 #include "nls.h"
28 
29 #include "debug.hh"
30 #include <fstream>
31 #include <sstream>
32 #include <assert.h>
33 
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 
38 #include "Util.hh"
39 #include "IdleLogManager.hh"
40 #include "TimeSource.hh"
41 #include "PacketBuffer.hh"
42 
43 #define IDLELOG_MAXSIZE     (4000)
44 #define IDLELOG_MAXAGE    (12 * 60 * 60)
45 #define IDLELOG_INTERVAL    (30 * 60)
46 #define IDLELOG_VERSION   (3)
47 #define IDLELOG_INTERVAL_SIZE (17)
48 
49 
50 //! Constructs a new idlelog manager.
IdleLogManager(string myid,const TimeSource * time_source)51 IdleLogManager::IdleLogManager(string myid, const TimeSource *time_source)
52 {
53   this->myid = myid;
54   this->time_source = time_source;
55   this->last_expiration_time = 0;
56 }
57 
58 
59 //! Update the idlelogs of all clients.
60 void
update_all_idlelogs(string master_id,ActivityState current_state)61 IdleLogManager::update_all_idlelogs(string master_id, ActivityState current_state)
62 {
63   TRACE_ENTER_MSG("IdleLogManager::update_all_idlelogs", master_id << " " << current_state);
64 
65   if (current_state == ACTIVITY_NOISE)
66     {
67       // Not interested in noise.
68       current_state = ACTIVITY_IDLE;
69     }
70 
71   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
72     {
73       ClientInfo &info = i->second;
74 
75       // Default: remote client is idle and not master
76       ActivityState state = ACTIVITY_IDLE;
77       bool master = false;
78 
79       // Only the master can be active.
80       if (i->first == master_id)
81         {
82           // This client is master, sets its state.
83           state = current_state;
84           master = true;
85         }
86 
87       // Update history.
88       update_idlelog(info, state, master);
89 
90       // Remember current state/master status.
91       info.master = master;
92       info.state = state;
93     }
94 
95   expire();
96 
97   TRACE_EXIT();
98 }
99 
100 
101 //! Resets the total active time of all clients.
102 void
reset()103 IdleLogManager::reset()
104 {
105   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
106     {
107       ClientInfo &info = (*i).second;
108       info.update_active_time(time_source->get_time());
109       info.total_active_time = 0;
110     }
111 }
112 
113 
114 //! Initializes the idlelog manager.
115 void
init()116 IdleLogManager::init()
117 {
118   TRACE_ENTER("IdleLogManager::init()");
119 
120   load();
121 
122   if (clients.find(myid) == clients.end())
123     {
124       TRACE_MSG("Didn't find myself");
125 
126       ClientInfo &myinfo = clients[myid];
127       myinfo.current_interval = IdleInterval(1, time_source->get_time());
128       myinfo.client_id = myid;
129 
130       save();
131     }
132   else
133     {
134       ClientInfo &myinfo = clients[myid];
135       myinfo.current_interval = IdleInterval(time_source->get_time(), time_source->get_time());
136     }
137 
138   TRACE_EXIT();
139 }
140 
141 
142 //! Terminates the idlelog manager.
143 void
terminate()144 IdleLogManager::terminate()
145 {
146   save();
147 }
148 
149 
150 //! Expire entries that are too old.
151 void
expire()152 IdleLogManager::expire()
153 {
154   time_t current_time = time_source->get_time();
155   if (last_expiration_time == 0)
156     {
157       last_expiration_time = current_time +  IDLELOG_INTERVAL;
158     }
159   else if (current_time <= last_expiration_time)
160     {
161       last_expiration_time = current_time +  IDLELOG_INTERVAL;
162       for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
163         {
164           ClientInfo &info = (*i).second;
165           expire(info);
166         }
167     }
168 }
169 
170 
171 //! Expire entries that are too old.
172 void
expire(ClientInfo & info)173 IdleLogManager::expire(ClientInfo &info)
174 {
175   if (info.idlelog.size() > IDLELOG_MAXSIZE)
176     {
177       info.idlelog.resize(IDLELOG_MAXSIZE);
178     }
179 
180   time_t current_time = time_source->get_time();
181   int count = 0;
182   for (IdleLogRIter i = info.idlelog.rbegin(); i != info.idlelog.rend(); i++)
183     {
184       IdleInterval &idle = info.idlelog.back();
185       if (idle.end_idle_time < current_time - IDLELOG_MAXAGE)
186         {
187           count++;
188         }
189       else
190         {
191           break;
192         }
193     }
194 
195   if (count != 0)
196     {
197       if (info.idlelog.size() > (size_t)count)
198         {
199           info.idlelog.resize(info.idlelog.size() - count);
200         }
201       else
202         {
203           info.idlelog.clear();
204         }
205     }
206 }
207 
208 
209 //! Update the idle log of a single client.
210 void
update_idlelog(ClientInfo & info,ActivityState state,bool master)211 IdleLogManager::update_idlelog(ClientInfo &info, ActivityState state, bool master)
212 {
213   (void) master;
214   TRACE_ENTER_MSG("IdleLogManager::update_idlelog", ((int)state) << " " << master);
215 
216   // Did the state/master status change?
217   bool changed = state != info.state; // RC: removed... || master != info.master;
218 
219   time_t current_time = time_source->get_time();
220   IdleInterval *idle = &(info.current_interval);
221   idle->end_time = current_time;
222 
223   if (state == ACTIVITY_IDLE)
224     {
225       if (changed)
226         {
227           // State changed from active to idle:
228 
229           // update active time of last interval.
230           info.update_active_time(current_time);
231 
232           // save front.
233           if (info.idlelog.size() > 0)
234             {
235               IdleInterval *save_interval = &(info.idlelog.front());
236               if (save_interval->to_be_saved)
237                 {
238                   update_idlelog(info, *save_interval);
239                   save_interval->to_be_saved = false;
240                 }
241             }
242 
243           // Push current
244           info.current_interval.to_be_saved = true;
245           info.idlelog.push_front(info.current_interval);
246 
247           // create a new (empty) idle interval.
248           info.current_interval = IdleInterval(current_time, current_time);
249           idle = &(info.current_interval);
250         }
251       else
252         {
253           // State remained idle. Update end time of idle interval.
254           idle->end_idle_time = current_time;
255 
256           if (info.idlelog.size() > 0)
257             {
258               time_t total_idle = idle->end_idle_time - idle->begin_time;
259               if (total_idle >= 10)
260                 {
261                   IdleInterval *save_interval = &(info.idlelog.front());
262                   if (save_interval->to_be_saved)
263                     {
264                       TRACE_MSG("Saving");
265                       update_idlelog(info, *save_interval);
266                       save_interval->to_be_saved = false;
267                     }
268                 }
269             }
270         }
271     }
272   else if (state == ACTIVITY_ACTIVE)
273     {
274       if (changed)
275         {
276           // State changed from idle to active:
277 
278           idle->end_idle_time = current_time;
279 
280           time_t total_idle = idle->end_idle_time - idle->begin_time;
281           if (total_idle < 10 && info.idlelog.size() > 1)
282             {
283               // Idle period too short. remove it. and reuse previous
284               IdleInterval &oldidle = info.idlelog.front();
285 
286               if (oldidle.to_be_saved)
287                 {
288                   info.current_interval = oldidle;
289                   info.idlelog.pop_front();
290                   idle = &(info.current_interval);
291                 }
292             }
293 
294           // Update start time of last active period.
295           info.last_active_time = 0;
296           info.last_active_begin_time = current_time;
297         }
298       else if (info.last_active_begin_time != 0)
299         {
300           // State remained active.
301           info.last_active_time = current_time - info.last_active_begin_time;
302         }
303     }
304 
305   info.last_update_time = current_time;
306   dump_idlelog(info);
307   TRACE_EXIT();
308 }
309 
310 
311 
312 //! Returns the total active time of all clients.
313 time_t
compute_total_active_time()314 IdleLogManager::compute_total_active_time()
315 {
316   TRACE_ENTER("IdleLogManager::compute_total_active_time");
317   time_t current_time = time_source->get_time();
318   time_t active_time = 0;
319   for (ClientMapIter it = clients.begin(); it != clients.end(); it++)
320     {
321       ClientInfo &info = (*it).second;
322       info.update_active_time(current_time);
323       active_time += info.total_active_time;
324     }
325   TRACE_EXIT();
326   return active_time;
327 }
328 
329 
330 //! Returns the active time since an idle period of a least the specified amount of time.
331 time_t
compute_active_time(int length)332 IdleLogManager::compute_active_time(int length)
333 {
334   TRACE_ENTER("IdleLogManager::compute_active_time");
335 
336   time_t current_time = time_source->get_time();
337 
338   // Number of client.
339   int size = clients.size();
340 
341   // Data for each client.
342   IdleLogIter *iterators = new IdleLogIter[size];
343   IdleLogIter *end_iterators = new IdleLogIter[size];
344   bool *at_end = new bool[size];
345   time_t *active_time = new time_t[size];
346 
347   // Init data for all clients.
348   int count = 0;
349   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
350     {
351       ClientInfo &info = (*i).second;
352 
353       iterators[count] = info.idlelog.begin();
354       end_iterators[count] = info.idlelog.end();
355       active_time[count] = 0;
356       at_end[count] = true;
357 
358       info.update_active_time(current_time);
359       count++;
360     }
361 
362 
363   // Number of simultaneous idle periods.
364   int idle_count = 0;
365 
366   // Time of last unprocessed event.
367   time_t last_time = -1;
368 
369   // Iterator of last unprocessed event.
370   int last_iter = -1;
371 
372   // Stop criterium
373   bool stop = false;
374 
375   // Begin and End time of idle perdiod.
376   time_t end_idle_time = -1;
377 
378   while (!stop)
379     {
380       // Find latest event.
381       last_time = -1;
382       for (int i = 0; i < size; i ++)
383         {
384           if (iterators[i] != end_iterators[i])
385             {
386               IdleInterval &ii = *(iterators[i]);
387               time_t t = at_end[i] ? ii.end_idle_time : ii.begin_time;
388 
389               if (last_time == -1 || t > last_time)
390                 {
391                   last_time = t;
392                   last_iter = i;
393                 }
394             }
395         }
396 
397       // Did we found one?
398       if (last_time != -1)
399         {
400           IdleInterval &ii = *(iterators[last_iter]);
401           if (at_end[last_iter])
402             {
403               TRACE_MSG("End time " << ii.end_idle_time << " active " << ii.active_time);
404               idle_count++;
405 
406               at_end[last_iter] = false;
407               active_time[last_iter] += ii.active_time;
408               end_idle_time = ii.end_idle_time;
409             }
410           else
411             {
412               TRACE_MSG("Begin time " << ii.begin_time);
413 
414               at_end[last_iter] = true;
415               iterators[last_iter]++;
416 
417               if (idle_count == size)
418                 {
419                   TRACE_MSG("Common idle period of " << (end_idle_time - ii.begin_time));
420                   if ((end_idle_time - ii.begin_time) > length)
421                     {
422                       stop = true;
423                     }
424                 }
425 
426               idle_count--;
427             }
428         }
429       else
430         {
431           stop = true;
432         }
433     }
434 
435   time_t total_active_time = 0;
436   for (int i = 0; i < size; i++)
437     {
438       TRACE_MSG("active time of " << i << " = " << active_time[i]);
439       total_active_time += active_time[i];
440     }
441 
442   TRACE_MSG("total = " << total_active_time);
443 
444   delete [] iterators;
445   delete [] end_iterators;
446   delete [] at_end;
447   delete [] active_time;
448 
449   TRACE_EXIT();
450   return total_active_time;
451 }
452 
453 
454 //! Computes the current idle time.
455 time_t
compute_idle_time()456 IdleLogManager::compute_idle_time()
457 {
458   TRACE_ENTER("IdleLogManager::compute_idle_time");
459 
460   time_t current_time = time_source->get_time();
461 
462   int count = 0;
463   time_t latest_start_time = 0;
464 
465   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
466     {
467       ClientInfo &info = (*i).second;
468       info.update_active_time(current_time);
469 
470       IdleInterval &idle = info.idlelog.front();
471       if (idle.active_time == 0)
472         {
473           count++;
474         }
475       if (idle.begin_time > latest_start_time)
476         {
477           latest_start_time = idle.begin_time;
478           TRACE_MSG(current_time - latest_start_time);
479         }
480     }
481 
482   TRACE_MSG("count = " << count);
483   if ((unsigned int)count != clients.size() + 1)
484     {
485       latest_start_time = current_time;
486     }
487 
488   TRACE_MSG((current_time - latest_start_time));
489   TRACE_EXIT();
490 
491   return current_time - latest_start_time;
492 }
493 
494 
495 
496 //! Packs the idle interval to the buffer.
497 void
pack_idle_interval(PacketBuffer & buffer,const IdleInterval & idle) const498 IdleLogManager::pack_idle_interval(PacketBuffer &buffer, const IdleInterval &idle) const
499 {
500   int pos = 0;
501 
502   buffer.reserve_size(pos);
503   buffer.pack_byte(IDLELOG_VERSION);
504   buffer.pack_ulong((guint32)idle.begin_time);
505   buffer.pack_ulong((guint32)idle.end_idle_time);
506   buffer.pack_ulong((guint32)idle.end_time);
507   buffer.pack_ushort((guint32)idle.active_time);
508   buffer.update_size(pos);
509 }
510 
511 
512 //! Unpacks the idle interval from the buffer.
513 void
unpack_idle_interval(PacketBuffer & buffer,IdleInterval & idle,time_t delta_time) const514 IdleLogManager::unpack_idle_interval(PacketBuffer &buffer, IdleInterval &idle, time_t delta_time) const
515 {
516   int pos = 0;
517   int size = buffer.read_size(pos);
518 
519   if (size > 0 && buffer.bytes_available() >= size)
520     {
521       /*int version = */ buffer.unpack_byte();
522 
523       idle.begin_time = buffer.unpack_ulong() - delta_time;
524       idle.end_idle_time = buffer.unpack_ulong() - delta_time;
525       idle.end_time = buffer.unpack_ulong() - delta_time;
526       idle.active_time = buffer.unpack_ushort();
527 
528       buffer.skip_size(pos);
529     }
530   else
531     {
532       buffer.clear();
533     }
534 }
535 
536 
537 //! Packs the idlelog header to the buffer.
538 void
pack_idlelog(PacketBuffer & buffer,const ClientInfo & ci) const539 IdleLogManager::pack_idlelog(PacketBuffer &buffer, const ClientInfo &ci) const
540 {
541   time_t current_time = time_source->get_time();
542 
543   // Add size.
544   int pos = 0;
545   buffer.reserve_size(pos);
546 
547   // Pack
548   buffer.pack_ulong((guint32)current_time);
549   buffer.pack_string(ci.client_id.c_str());
550   buffer.pack_ulong((guint32)ci.total_active_time);
551   buffer.pack_byte(ci.master);
552   buffer.pack_byte(ci.state);
553   buffer.pack_ushort(ci.idlelog.size());
554 
555   buffer.update_size(pos);
556 }
557 
558 
559 //! Unpacks the idlelog header from the buffer.
560 void
unpack_idlelog(PacketBuffer & buffer,ClientInfo & ci,time_t & pack_time,int & num_intervals) const561 IdleLogManager::unpack_idlelog(PacketBuffer &buffer, ClientInfo &ci,
562                                time_t &pack_time, int &num_intervals) const
563 {
564   int pos = 0;
565   int size = buffer.read_size(pos);
566 
567   if (size > 0 && buffer.bytes_available() >= size)
568     {
569       pack_time = buffer.unpack_ulong();
570 
571       char *id = buffer.unpack_string();
572 
573       if (id != NULL)
574         {
575           ci.client_id = id;
576         }
577 
578       ci.total_active_time = buffer.unpack_ulong();
579       ci.master = buffer.unpack_byte() != 0;
580       ci.state = (ActivityState) buffer.unpack_byte();
581 
582       num_intervals = buffer.unpack_ushort();
583 
584       g_free(id);
585 
586       buffer.skip_size(pos);
587     }
588   else
589     {
590       buffer.clear();
591     }
592 }
593 
594 
595 //! Removes the idlelog specified in the buffer.
596 void
unlink_idlelog(PacketBuffer & buffer) const597 IdleLogManager::unlink_idlelog(PacketBuffer &buffer) const
598 {
599   TRACE_ENTER("IdleLogManager::unlink_idlelog()");
600 
601   int pos = 0;
602   int size = buffer.read_size(pos);
603 
604   if (size > 0 && buffer.bytes_available() >= size)
605     {
606       buffer.unpack_ulong(); // skip pack time.
607       char *id = buffer.unpack_string();
608 
609       if (id != NULL)
610         {
611           stringstream ss;
612           ss << Util::get_home_directory();
613           ss << "idlelog." << id << ".log" << ends;
614 
615 #ifdef PLATFORM_OS_WIN32
616           _unlink(ss.str().c_str());
617 #else
618           unlink(ss.str().c_str());
619 #endif
620 
621           g_free(id);
622         }
623 
624       buffer.skip_size(pos);
625     }
626   else
627     {
628       buffer.clear();
629     }
630   TRACE_EXIT();
631 }
632 
633 
634 //! Saves the idlelog index.
635 void
save_index()636 IdleLogManager::save_index()
637 {
638   TRACE_ENTER("IdleLogManager::save_index()");
639 
640   PacketBuffer buffer;
641   buffer.create();
642 
643   buffer.pack_ushort(IDLELOG_VERSION);
644   buffer.pack_string(myid.c_str());
645 
646   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
647     {
648       ClientInfo &info = (*i).second;
649       info.update_active_time(time_source->get_time());
650       TRACE_MSG("Saving " << i->first << " " << info.client_id);
651 
652       pack_idlelog(buffer, info);
653     }
654 
655   stringstream ss;
656   ss << Util::get_home_directory();
657   ss << "idlelog.idx" << ends;
658 
659   ofstream file(ss.str().c_str(), ios::binary);
660   file.write(buffer.get_buffer(), buffer.bytes_written());
661   file.close();
662 
663   TRACE_EXIT();
664 }
665 
666 
667 
668 //! Loads the idlelog index.
669 void
load_index()670 IdleLogManager::load_index()
671 {
672   TRACE_ENTER("IdleLogManager::load()");
673 
674   stringstream ss;
675   ss << Util::get_home_directory();
676   ss << "idlelog.idx" << ends;
677 
678   bool exists = Util::file_exists(ss.str());
679 
680   if (exists)
681     {
682       TRACE_MSG("File exists - ok");
683 
684       // Open file
685       ifstream file(ss.str().c_str(), ios::binary);
686 
687       // get file size using buffer's members
688       filebuf *pbuf=file.rdbuf();
689       int size=pbuf->pubseekoff (0,ios::end,ios::in);
690       pbuf->pubseekpos (0,ios::in);
691 
692       TRACE_MSG("Size - " << size);
693 
694       PacketBuffer buffer;
695       buffer.create(size);
696 
697       file.read(buffer.get_buffer(), size);
698       file.close();
699       buffer.write_ptr += size;
700 
701       // Read
702       int version = buffer.unpack_ushort();
703       TRACE_MSG("Version - " << version);
704 
705       if (version == IDLELOG_VERSION)
706         {
707           TRACE_MSG("Version - ok");
708 
709           char *id = buffer.unpack_string();
710           if (id != NULL)
711             {
712               TRACE_MSG("id = " << id);
713             }
714 
715           while (buffer.bytes_available() > 0)
716             {
717               ClientInfo info;
718 
719               int num_intervals;
720               time_t pack_time;
721 
722               unpack_idlelog(buffer, info, pack_time, num_intervals);
723               info.master = false;
724               info.state = ACTIVITY_IDLE;
725               info.last_update_time = pack_time;
726               TRACE_MSG("Add client " << info.client_id);
727 
728               clients[info.client_id] = info;
729             }
730 
731           g_free(id);
732         }
733       else
734         {
735           TRACE_MSG("Old version - deleting logs of old version");
736 
737           char *id = buffer.unpack_string();
738           if (id != NULL)
739             {
740               TRACE_MSG("id = " << id);
741             }
742 
743           while (buffer.bytes_available() > 0)
744             {
745               unlink_idlelog(buffer);
746             }
747 
748           g_free(id);
749         }
750     }
751   TRACE_EXIT();
752 }
753 
754 
755 
756 //! Saves the idlelog for the specified client.
757 void
save_idlelog(ClientInfo & info)758 IdleLogManager::save_idlelog(ClientInfo &info)
759 {
760   info.update_active_time(time_source->get_time());
761 
762   PacketBuffer buffer;
763   buffer.create();
764 
765   for (IdleLogRIter i = info.idlelog.rbegin(); i != info.idlelog.rend(); i++)
766     {
767       IdleInterval &idle = *i;
768 
769       pack_idle_interval(buffer, idle);
770     }
771 
772   stringstream ss;
773   ss << Util::get_home_directory();
774   ss << "idlelog." << info.client_id << ".log" << ends;
775 
776   ofstream file(ss.str().c_str(), ios::binary);
777   file.write(buffer.get_buffer(), buffer.bytes_written());
778   file.close();
779 }
780 
781 
782 //! Loads the idlelog for the specified client.
783 void
load_idlelog(ClientInfo & info)784 IdleLogManager::load_idlelog(ClientInfo &info)
785 {
786   TRACE_ENTER("IdleLogManager::load_idlelog()");
787 
788   time_t current_time = time_source->get_time();
789 
790   stringstream ss;
791   ss << Util::get_home_directory();
792   ss << "idlelog." << info.client_id << ".log" << ends;
793 
794   // Open file
795   ifstream file(ss.str().c_str(), ios::binary);
796 
797   // get file size using buffer's members
798   filebuf *pbuf=file.rdbuf();
799   int size=pbuf->pubseekoff (0,ios::end,ios::in);
800   pbuf->pubseekpos (0,ios::in);
801 
802   // Process it.
803   int num_intervals = size / IDLELOG_INTERVAL_SIZE;
804   if (num_intervals * IDLELOG_INTERVAL_SIZE == size)
805     {
806       if (num_intervals > IDLELOG_MAXSIZE)
807         {
808           TRACE_MSG("Skipping " << (num_intervals - IDLELOG_MAXSIZE) << " intervals");
809           int skip = (num_intervals - IDLELOG_MAXSIZE) * IDLELOG_INTERVAL_SIZE;
810           file.seekg(skip);
811           size -= skip;
812           num_intervals = IDLELOG_MAXSIZE;
813         }
814 
815       // Create buffer and load data.
816       PacketBuffer buffer;
817       buffer.create(size);
818       file.read(buffer.get_buffer(), size);
819       file.close();
820       buffer.write_ptr += size;
821 
822       TRACE_MSG("loading " << num_intervals << " intervals");
823       for (int i = 0; i < num_intervals; i++)
824         {
825           IdleInterval idle;
826           unpack_idle_interval(buffer, idle, 0);
827 
828           if (idle.end_idle_time >= current_time - IDLELOG_MAXAGE)
829             {
830               info.idlelog.push_front(idle);
831             }
832         }
833 
834 	  if (info.idlelog.size() > 0)
835 	    {
836            IdleInterval &idle = info.idlelog.back();
837            idle.begin_time = 1;
838 	    }
839     }
840 
841   dump_idlelog(info);
842   fix_idlelog(info);
843   dump_idlelog(info);
844   TRACE_EXIT();
845 }
846 
847 
848 //! Loads the entire idlelog.
849 void
load()850 IdleLogManager::load()
851 {
852   load_index();
853 
854   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
855     {
856       ClientInfo &info = (*i).second;
857       load_idlelog(info);
858     }
859 }
860 
861 
862 
863 //! Saves the entire idlelog.
864 void
save()865 IdleLogManager::save()
866 {
867   save_index();
868 
869   for (ClientMapIter i = clients.begin(); i != clients.end(); i++)
870     {
871       ClientInfo &info = (*i).second;
872       save_idlelog(info);
873     }
874 }
875 
876 
877 //! Adds the specified idle interval to persistent storage.
878 void
update_idlelog(ClientInfo & info,const IdleInterval & idle)879 IdleLogManager::update_idlelog(ClientInfo &info, const IdleInterval &idle)
880 {
881   info.update_active_time(time_source->get_time());
882 
883   PacketBuffer buffer;
884   buffer.create();
885 
886   pack_idle_interval(buffer, idle);
887 
888   stringstream ss;
889   ss << Util::get_home_directory();
890   ss << "idlelog." << info.client_id << ".log" << ends;
891 
892   ofstream file(ss.str().c_str(), ios::app | ios::binary);
893   file.write(buffer.get_buffer(), buffer.bytes_written());
894   file.close();
895 
896   save_index();
897 }
898 
899 
900 
901 void
get_idlelog(PacketBuffer & buffer)902 IdleLogManager::get_idlelog(PacketBuffer &buffer)
903 {
904   TRACE_ENTER("IdleLogManager::get_idlelog");
905 
906   // Information about me.
907   ClientInfo &myinfo = clients[myid];
908 
909   // First make sure that all data is up-to-date.
910   myinfo.update_active_time(time_source->get_time());
911 
912   // Pack header.
913   pack_idlelog(buffer, myinfo);
914 
915   for (IdleLogIter i = myinfo.idlelog.begin(); i != myinfo.idlelog.end(); i++)
916     {
917       pack_idle_interval(buffer, *i);
918     }
919 
920   TRACE_EXIT();
921 }
922 
923 
924 void
set_idlelog(PacketBuffer & buffer)925 IdleLogManager::set_idlelog(PacketBuffer &buffer)
926 {
927   TRACE_ENTER("IdleLogManager::set_idlelog");
928 
929   time_t delta_time = 0;
930   time_t pack_time = 0;
931   int num_intervals = 0;
932 
933   ClientInfo info;
934   unpack_idlelog(buffer, info, pack_time, num_intervals);
935 
936   delta_time = pack_time - time_source->get_time();
937   clients[info.client_id] = info;
938   info.last_update_time = 0;
939 
940   for (int i = 0; i < num_intervals; i++)
941     {
942       IdleInterval idle;
943       unpack_idle_interval(buffer, idle, delta_time);
944 
945       TRACE_MSG(info.client_id << " " << idle.begin_time << " " << idle.end_idle_time << " " << idle.active_time);
946       clients[info.client_id].idlelog.push_back(idle);
947     }
948 
949   fix_idlelog(info);
950   save_index();
951   save_idlelog(clients[info.client_id]);
952 
953   TRACE_EXIT();
954 }
955 
956 
957 //! A remote client has signed on.
958 void
signon_remote_client(string client_id)959 IdleLogManager::signon_remote_client(string client_id)
960 {
961   TRACE_ENTER_MSG("signon_remote_client", client_id);
962 
963   time_t current_time = time_source->get_time();
964 
965   ClientInfo &info = clients[client_id];
966   info.idlelog.push_front(IdleInterval(1, current_time));
967   info.client_id = client_id;
968 
969   save_index();
970   save_idlelog(info);
971 
972   TRACE_EXIT();
973 }
974 
975 
976 //! A remote client has signed off.
977 void
signoff_remote_client(string client_id)978 IdleLogManager::signoff_remote_client(string client_id)
979 {
980   TRACE_ENTER_MSG("signoff_remote_client", client_id);
981 
982   clients[client_id].state = ACTIVITY_IDLE;
983   clients[client_id].master = false;
984 
985   TRACE_EXIT();
986 }
987 
988 
989 //! Dumps the idle log of the specified client.
990 void
dump_idlelog(ClientInfo & info)991 IdleLogManager::dump_idlelog(ClientInfo &info)
992 {
993   (void) info;
994 #if 0
995 #ifndef PLATFORM_OS_WIN32
996   TRACE_ENTER("IdleLogManager::dump_idlelog");
997 
998   TRACE_MSG("id = " << info.client_id);
999   TRACE_MSG("last_active_time = " << info.last_active_time);
1000   TRACE_MSG("total_active_time = " << info.total_active_time);
1001 
1002   {
1003       IdleInterval &idle = info.current_interval;
1004       struct tm begin_time;
1005       localtime_r(&idle.begin_time, &begin_time);
1006       struct tm end_idle_time;
1007       localtime_r(&idle.end_idle_time, &end_idle_time);
1008       struct tm end_time;
1009       localtime_r(&idle.end_time, &end_time);
1010 
1011       TRACE_MSG(   begin_time.tm_hour << ":"
1012                    << begin_time.tm_min << ":"
1013                    << begin_time.tm_sec << " - "
1014                    << end_idle_time.tm_hour << ":"
1015                    << end_idle_time.tm_min << ":"
1016                    << end_idle_time.tm_sec << " "
1017                    << idle.active_time << " "
1018                    << end_time.tm_hour << ":"
1019                    << end_time.tm_min << ":"
1020                    << end_time.tm_sec
1021                    );
1022   }
1023 
1024   IdleLogIter i = info.idlelog.begin();
1025   while (i != info.idlelog.end())
1026     {
1027       IdleInterval &idle = *i;
1028 
1029       struct tm begin_time;
1030       localtime_r(&idle.begin_time, &begin_time);
1031       struct tm end_idle_time;
1032       localtime_r(&idle.end_idle_time, &end_idle_time);
1033       struct tm end_time;
1034       localtime_r(&idle.end_time, &end_time);
1035 
1036       TRACE_MSG(   begin_time.tm_hour << ":"
1037                    << begin_time.tm_min << ":"
1038                    << begin_time.tm_sec << " - "
1039                    << end_idle_time.tm_hour << ":"
1040                    << end_idle_time.tm_min << ":"
1041                    << end_idle_time.tm_sec << " "
1042                    << idle.active_time << " "
1043                    << end_time.tm_hour << ":"
1044                    << end_time.tm_min << ":"
1045                    << end_time.tm_sec
1046                    );
1047       i++;
1048     }
1049   TRACE_EXIT();
1050 #endif
1051 #endif
1052 }
1053 
1054 void
fix_idlelog(ClientInfo & info)1055 IdleLogManager::fix_idlelog(ClientInfo &info)
1056 {
1057   TRACE_ENTER("IdleLogManager::fix_idlelog");
1058 
1059   time_t current_time = time_source->get_time();
1060   info.update_active_time(current_time);
1061 
1062   time_t next_time = -1;
1063 
1064   for (IdleLogRIter i = info.idlelog.rbegin(); i != info.idlelog.rend(); i++)
1065     {
1066       IdleInterval &idle = *i;
1067 
1068       TRACE_MSG(idle.begin_time << " "
1069                 << idle.end_time << " "
1070                 << idle.end_idle_time << " "
1071                 << idle.active_time);
1072 
1073       if (next_time == -1)
1074         {
1075           if (idle.begin_time != 1)
1076             {
1077               TRACE_MSG("Fixing first start time. setting to 1");
1078               idle.begin_time = 1;
1079             }
1080         }
1081       else
1082         {
1083           if (idle.begin_time < next_time)
1084             {
1085               TRACE_MSG("Fixing start time. setting from "
1086                         << idle.begin_time << " to "
1087                         << next_time);
1088               idle.begin_time = next_time;
1089             }
1090         }
1091 
1092       if (idle.end_time != 0)
1093         {
1094           next_time = idle.end_time;
1095         }
1096       else
1097         {
1098           next_time = idle.end_idle_time;
1099         }
1100     }
1101 
1102   info.idlelog.push_front(IdleInterval(next_time, current_time));
1103 
1104   TRACE_EXIT();
1105 }
1106