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