// Copyright (C) 2001,2002,2003,2004,2005 Federico Montesino <fedemp@altern.org>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// 
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however    
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.    
//
// This exception applies only to the code released under the name GNU
// ccRTP.  If you copy code from other releases into a copy of GNU
// ccRTP, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccRTP, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

/**
 * @file control.cpp
 *
 * @short SDESItemsHolder, RTPSource and Participant classes implementation.
 **/

#include "private.h"
#include <ccrtp/sources.h>

#ifdef	CCXX_NAMESPACES
namespace ost {
#endif

#ifndef	HAVE_GETTIMEOFDAY
#ifdef WIN32
int gettimeofday(struct timeval *tv_,  void *tz_)
{
	// We could use _ftime(), but it is not available on WinCE.
	// (WinCE also lacks time.h)
	// Note also that the average error of _ftime is around 20 ms :)
	DWORD ms = GetTickCount();
	tv_->tv_sec = ms / 1000;
	tv_->tv_usec = ms * 1000;
	return 0;
}
#endif //WIN32
#endif

static void
findusername(std::string &username);

#ifndef WIN32
static void
findusername(std::string &username)
{
	// LOGNAME environment var has two advantages:
	// 1) avoids problems of getlogin(3) and cuserid(3)
	// 2) unlike getpwuid, takes into account user
	//    customization of the environment.
	// Try both LOGNAME and USER env. var.
	const char *user = Process::getEnv("LOGNAME");
	if ( !user || !strcmp(user,"") )
		user = Process::getEnv("USER");
	if ( !user || !strcmp(user,"") )
		username = Process::getUser();

	if ( user )
		username = user;
	else
		username = "";
}

#else

static void
findusername(std::string &username)
{
	unsigned long len = 0;
	if ( GetUserName(NULL,&len) && (len > 0) ) {
		char *n = new char[len];	 
		GetUserName(n,&len);
		username = n;
		delete [] n;
	} else {
		username = "";
	}
}
#endif // #ifndef WIN32

void 
SDESItemsHolder::setItem(SDESItemType item, const std::string& val)
{
	if ( item > SDESItemTypeEND && item <= SDESItemTypeH323CADDR ) {
		sdesItems[item] = val;
	}
}
	
const std::string&
SDESItemsHolder::getItem(SDESItemType type) const
{
	if ( type > SDESItemTypeEND && type <= SDESItemTypeH323CADDR ) {
		return sdesItems[type];
	} else
		return sdesItems[SDESItemTypeCNAME];
}

SyncSource::SyncSource(uint32 ssrc):
	state(stateUnknown), SSRC(ssrc), participant(NULL),
	networkAddress("0"), dataTransportPort(0), controlTransportPort(0)
{
}

SyncSource::~SyncSource()
{
	activeSender = false;
	state = statePrevalid;
}

Participant::Participant(const std::string& cname) : SDESItemsHolder()
{
	SDESItemsHolder::setItem(SDESItemTypeCNAME,cname);
}

Participant::~Participant()
{
}

const size_t RTPApplication::defaultParticipantsNum = 11;

RTPApplication& defaultApplication()
{
	// default application CNAME is automatically assigned.
	static RTPApplication defApp("");

	return defApp; 
}

RTPApplication::RTPApplication(const std::string& cname) :
		SDESItemsHolder(),
		participants( new Participant* [defaultParticipantsNum] ),
		firstPart(NULL), lastPart(NULL)
{
	// guess CNAME, in the form of user@host_fqn
	if ( cname.length() > 0 )
		SDESItemsHolder::setItem(SDESItemTypeCNAME,cname);
	else
		findCNAME();
}

RTPApplication::~RTPApplication()
{
	ParticipantLink *p;
	while ( NULL != firstPart ) {
		p = firstPart;
		firstPart = firstPart->getNext();
#ifdef	CCXX_EXCEPTIONS
		try {
#endif
			delete p;
#ifdef	CCXX_EXCEPTIONS
		} catch (...) {}
#endif
	}
	lastPart = NULL;
#ifdef	CCXX_EXCEPTIONS
	try {
#endif
		delete [] participants;
#ifdef	CCXX_EXCEPTIONS
	} catch (...) {}
#endif
}

// TODO: it should be implemented using the participant iterators
const Participant*
RTPApplication::getParticipant(const std::string& cname) const
{
	ParticipantLink* pl = firstPart;
	while ( (NULL != pl) && 
		( pl->getParticipant()->getSDESItem(SDESItemTypeCNAME)
		  != cname) ) {
		pl = pl->getNext();
	}
	if ( pl ) {
		return pl->getParticipant();
	} else {
		return NULL;
	}
}

void
RTPApplication::addParticipant(Participant& part)
{
	ParticipantLink* pl = new ParticipantLink(part,NULL);
	if ( NULL == firstPart )
		firstPart = lastPart = pl;
	else
		lastPart->setNext(pl);
	lastPart = pl;
}

void
RTPApplication::removeParticipant(ParticipantLink* pl)
{
	if ( NULL == pl )
		return;
	if ( pl->getPrev() )
		pl->getPrev()->setNext(pl->getNext());
	if ( pl->getNext() )
		pl->getNext()->setPrev(pl->getPrev());
	delete pl;
}

void
RTPApplication::findCNAME()
{
	// build string username@host_fqn
	std::string username;
	findusername(username);
	
	// First create an InetHostAddress object, otherwise the
	// object will be destructed and the hostname corrupted.
	InetHostAddress iha;
	const char *p = iha.getHostname();
	// Returned hostname can be NULL
	std::string hname;
	if (p) hname = p;

	setSDESItem(SDESItemTypeCNAME, 
		    username + "@" + hname);
}

#ifdef	CCXX_NAMESPACES
}
#endif

/** EMACS **
 * Local variables:
 * mode: c++
 * c-basic-offset: 8
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1