www.pudn.com > net_oss.rar > collection.cc


#include "collection.h"
using namespace std;
collection::collection()
{ 
	last.ut_type = -1; 
	key = ftok("/dev/null",0);
	if((msgid = msgget(key,0))== -1){
		msgid = msgget(key,IPC_CREAT | IPC_EXCL | 0600);
		if(msgid < 0) exit(-1);
	}
}
	
collection::~collection()
{
		dump_lastposition();
		dump_unfinished();
		multimap::iterator it;
		for(it = login.begin(); it!=login.end();it++)
			delete it->second;
		for(it = logoff.begin(); it!=logoff.end();it++)
			delete it->second;
		list::iterator it2;
		for(it2 = data.begin(); it2 != data.end();it2++)
			delete *it2;	
			
}

void collection::setdefault()
{
	backup_file = BACKUP;
	position_file = POSITION;
	system_file = SYSTEM;
}

string collection::localIP()
{
	static string ip = NOT_ASSIGNED;
	if(ip == NOT_ASSIGNED)
	{
		char* name = new char[255];
		gethostname(name,255);
		hostent* h = gethostbyname(name);
		inet_ntop(AF_INET,h->h_addr_list[0],name,16);
		ip = name;
		delete name;
	}
	return ip;
}
void collection::loadconfiguration(const char* file)
{
	if(file == NULL)
	{
		setdefault();
	}
	else
	{
		if(access(file,F_OK)<0){
  		setdefault();
		}
		else
		{
			ifstream fin(file);
			if(!fin)
			{
				setdefault();
			}
			else
			{
				while(!fin.eof())
				{
					char buf[MAX_BUF];
					memset(buf,0x00,MAX_BUF);
					fin.getline(buf,MAX_BUF);
					string input = buf;
					if(input.find(COMMENT_TAG,0) != input.npos) continue;
					if(input.find(BACKUP_TAG,0) != input.npos){
						backup_file = input.erase(0,input.find(DELIMITER_TAG,0)+1);
					}
					if(input.find(POSITION_TAG,0) != input.npos){
						position_file = input.erase(0,input.find(DELIMITER_TAG,0)+1);
					}
					if(input.find(SYSTEM_TAG,0) != input.npos){
						system_file = input.erase(0,input.find(DELIMITER_TAG,0)+1);
					}
				}//end of while(!fin.eof())
				fin.close();
			}//end of else [if(!fin)]
		}//end of else [if(access(file,F_OK)<0)]
	}//end of else [if(file == NULL)]
	#ifdef __DEBUG
	cout << " BACKUP =" << backup_file << endl;
	cout << " POSITION =" << position_file << endl;
	cout << " SYSTEM =" << system_file << endl;
	#endif
}//end of function

void collection::retrieve()
{
	utmpx* tmp;
	
	#ifdef __TIMER
	_timer.start("collection::retrieve");
	#endif
	
	//check backup
	if(access(backup_file.c_str(),F_OK)==0){
		ifstream ifs(backup_file.c_str(),ios::in | ios::binary);
		while(1)
		{
			utmpx* p;
			p = new utmpx;
			ifs.read((char*)p,sizeof(utmpx));
			if(ifs.eof()) break;
			login.insert(pair(p->ut_pid,p));	
		}
		ifs.close();
	}
	//load system file
	//set position
	if(access(position_file.c_str(),F_OK)==0)
	{
		utmpxname(position_file.c_str());
		setutxent();
		utmpx* pos = new utmpx;
		tmp = getutxent();
		memcpy(pos,tmp,sizeof(utmpx));
	  #ifdef __DEBUG
	  show(pos);
	  #endif
		endutxent();
		utmpxname(system_file.c_str());
		setutxent();
		tmp = getutxline(pos);
		#ifdef __DEBUG
		cout << endl << endl;
	  show(tmp);
	  #endif
		
		while(1)
		{
			if(tmp == NULL) {
				setutxent();
				break; 
			}
			else if(tmp->ut_tv.tv_sec != pos->ut_tv.tv_sec)
			{
				getutxent();
				tmp = getutxline(pos);
			}
			else break;
		}
		#ifdef __DEBUG
		cout << " ------------ " << endl;
	  show(tmp);
	  #endif
		
		delete pos;
	}
	else
	{
		utmpxname(system_file.c_str());
		setutxent();
	}
	while((tmp = getutxent()) != NULL)
	{
		if(tmp->ut_type == USER_PROCESS)
		{
			utmpx* t = new utmpx;
			memcpy(t,tmp,sizeof(utmpx));
			login.insert(pair(tmp->ut_pid,t));
			memcpy(&last,tmp,sizeof(last));
		}
		if(tmp->ut_type == DEAD_PROCESS)
		{
			utmpx* t = new utmpx;
			memcpy(t,tmp,sizeof(utmpx));
			logoff.insert(pair(tmp->ut_pid,t));
		}
		
		#ifdef __DEBUG
		printf("\x0d\tLogin: %d\tLogoff: %d",login.size(), logoff.size());
		#endif
	}
	#ifdef __DEBUG
	utmpx* u = &last;
	show(u);
	cout << endl;
	#endif
	endutxent();
	#ifdef __TIMER
	_timer.end();
	_timer.show();
	#endif
}

int collection::processing()
{
	#ifdef __DEBUG
	int s = login.size();
	int count = 0;
	#endif
	multimap::iterator it = login.begin();
	#ifdef __TIMER
	_timer.start("collection::processing");
	#endif
	for(it = login.begin();it != login.end();it++)
	{
		time_t min = -1;
		multimap::iterator start,end,matched;
		start = logoff.lower_bound(it->first);		
		end = logoff.upper_bound(it->first);
		matched = logoff.end();
		if(start == end && start == logoff.end()) continue;
		while(start != end)
		{
			if(start->second->ut_tv.tv_sec > it->second->ut_tv.tv_sec
			  && !strcmp(start->second->ut_name,it->second->ut_name)) 
			{
				if(min == -1) {
					matched = start;
					min = start->second->ut_tv.tv_sec - it->second->ut_tv.tv_sec;
				}
				else
				{
					if(start->second->ut_tv.tv_sec - it->second->ut_tv.tv_sec < min &&
					start->second->ut_tv.tv_sec - it->second->ut_tv.tv_sec > 0) {
						min = start->second->ut_tv.tv_sec - it->second->ut_tv.tv_sec;
						matched = start;
					}
				}
			}
			start++;
		}
		if(matched != logoff.end())
		{
			store(it->second,min);
			#ifdef __DEBUG
			count++;
			#endif
			login.erase(it);
			it--;
			logoff.erase(matched);
		}
	}
	#ifdef __DEBUG
	printf("\nThere are %d matched. \n", count);
	#endif
	////sending finish
	/*
	msg _msg;
	_msg.mtype = END;
	while(msgsnd(msgid,&_msg,sizeof(_msg),0)) sleep(1);
	*/
	#ifdef __TIMER
	_timer.end();
	_timer.show();
	cout << " there are still " << login.size() << " login no matched." << endl;
	#endif
	return 0;
}

void collection::store(const utmpx* u, const time_t& t)
{
		info inf;
		memset(&inf,0x00,sizeof(inf));
		strcpy(inf.user_name,u->ut_name);
		inf.start_time = u->ut_tv.tv_sec;
		inf.duration = t;
		strcpy(inf.IP,localIP().c_str());
		//data.push_back(inf);
		
		msg _msg;
		_msg.mtype = 1;
		memcpy(&_msg.inf,&inf,sizeof(info));
		#ifdef __DEBUG
		/*cout << " ***************** " << endl;
		cout << inf.user_name << "\t" <<	inf.duration << "\t";
		cout << inf.IP << endl; 
		cout << " ***************** " << endl;
		*/
		#endif
		while(msgsnd(msgid,&_msg,sizeof(_msg),IPC_NOWAIT)) sleep(1);
		
}
void collection::dump_unfinished()
{
	remove(backup_file.c_str());
	string cmd = "touch " + string(backup_file);
	system(cmd.c_str());
	int fd = open(backup_file.c_str(),O_WRONLY);
	if(fd < 0) {
		#ifdef __DEBUG
		cout << " cannot open file for output." << endl;
		#endif
		return;
	}
	for(multimap::iterator it = login.begin(); it != login.end(); it++)
	{
			
			if(write(fd,(char*)(it->second),sizeof(utmpx))<0)
			{
				#ifdef __DEBUG
				perror("write");
				#endif
			}
	}
	close(fd);
	
}
void collection::dump_lastposition()
{
	if(last.ut_type == -1) return;
	remove(position_file.c_str());
	string cmd = "touch " + string(position_file);
	system(cmd.c_str());
	utmpxname(position_file.c_str());
	setutxent();
	pututxline(&last);
	endutxent();	
	
}
void collection::show(struct utmpx*& tmp)
{
	cout << tmp->ut_user << endl;
	cout << tmp->ut_id << endl;
	cout << tmp->ut_line << endl;
	cout << tmp->ut_pid << endl;
	cout << tmp->ut_type << endl;
	cout << tmp->ut_tv.tv_sec << endl;	
}

void collection::start_cllection(){
	retrieve();
	processing();
}

void collection::receive()
{
	msg _msg;
	while(msgrcv(msgid,&_msg,sizeof(msg),0,0)>0)
	{
		info * _inf;
		_inf = new info;
		if(_msg.mtype == END) break;
		memcpy(_inf,&_msg.inf,sizeof(info));
		#ifdef __DEBUG
		//cout << _inf->user_name << "\t" <<	_inf->duration << "\t";
		//cout << _inf->IP << endl; 
		#endif
		data.push_back(_inf);
	}
	
	#ifdef __DEBUG
	cout << " Threre are " << data.size() << " records matched" << endl;
	ofstream fout("result.txt");
	fout << " Threre are " << data.size() << " records matched" << endl;
	for(list::iterator it = data.begin(); it!= data.end(); it++)
	{
		fout << (*it)->user_name << "\t" <<	(*it)->duration << "\t";
		fout << (*it)->IP << endl;
	}
	fout.close();
	#endif
}