/*
 * <insert one-line description of what the program does>
 * Copyright (c) <2008-2009>, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
File Name:          ListenBroadcast.c

Description:

Environment (opt):
 
Notes (opt):
  =====================================================================
  Revision   Revision History		Author     Date
  =====================================================================
  
  =====================================================================
****************************************************************************/


#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <pthread.h>

#include "ConnMgmt/ListenBroadcast.h"
#include "GUI/error.h"
#include "Engine/TCEngine.h"
extern int Listened ;
int g_AutoProvisionSucceed=1;

int setProvisionSucceedFlag(int flag)
{
	pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

	int error = pthread_mutex_trylock(&mutex);
	if (error)//lock fail
	{
		WritestrLog(MODULE_CONNMGMT,"lock auto provision flag failed");
		return error;
	}
	g_AutoProvisionSucceed = flag;
	error = pthread_mutex_unlock(&mutex);
	if (error)//unlock fail
	{
		WritestrLog(MODULE_CONNMGMT,"unlock auto provision flag failed");
		return error;
	}
}
/* Description: check recieved data 
 * Module: ConnMgmt module
 * Parameter: the pointer of the recieve buffer
 * Return Value: 1 if valid, otherwise 0
 */

int check_flag( t_packet_format * pmessage )
{
 	
	char * p_flag = HEAD_FLAG_STRING;
	int i;
	
	if ( NULL == pmessage )
		return 0;
	
	//pmessage->data_len = ntohs(pmessage->data_len);

	//if ( TAIL_FLAG != pmessage->tail_flag )
	//	return 0;
	//check the tail sign
	//add by fred
	//if ( TAIL_FLAG != pmessage->data[pmessage->data_len])//len = 128, data[0] - data[127]:DATA, data[128]:Tail
	//	return 0;
	for( i = 0; i < 8; i ++ )
	{
		if ( pmessage->head_flag[i] != p_flag[i] )
			return 0;
	}

	return 1;
}

/* Description: start broadcast listening
 * Module: ConnMgmt module
 * Parameter: none
 * Return Value: if return 0, discover succeed, otherwise fail
 */

int ConnMgmt_StartListen()
{
const int on =1;

	//the auto provision not succeed yet.
	setProvisionSucceedFlag(0);

	int sin_len;
	int peeraddr_len;
	int socket_descriptor;
  	struct sockaddr_in sin,peeraddr;//peeraddr is added by fred for client info of multicast
	struct ip_mreq mreq; //mreq is added by fred for client info of multicast
	t_packet_format message;
	int recieve_bytes;
  	int receive_timeout = DEFAULT_TIMEOUT;
	char timeout_buf[50];
	int wait_seconds;
	int iRet=1;
	int i=0;


	struct hostent *server_host_name;
	if( (server_host_name=gethostbyname("GRUPO"))==0)
		printf("error host name\n");
	/* Get recieve timeout setting*/
//	if ( 0 == OtherInfo_Broadcast_Timeout( timeout_buf, "GET") )
//		receive_timeout = atoi( timeout_buf ) ;
//	receive_timeout *= 60; // trans to second
		
	/* 
	   Create a UDP socket
	   and bind it to the port
	*/
	socket_descriptor = socket(AF_INET, SOCK_DGRAM, 0);
	
	//printf("socket create return %d \n", socket_descriptor);
	iRet = setsockopt(socket_descriptor,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

	//printf("setsockopt return %d \n", iRet);
	int loop=1;
	iRet = setsockopt(socket_descriptor,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop)); 

	//printf("setsockopt return %d \n", iRet);
	/*
	   Initialize socket address structure for Internet Protocols
	   Multicast Info
	   Modify by Fred
	*/
	bzero(&sin, sizeof(struct sockaddr_in)); /* empty data structure */
	bzero(&peeraddr, sizeof(struct sockaddr_in)); /* empty data structure */

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr=htonl(INADDR_ANY);
	sin.sin_port = htons(BROADCASTING_PORT);//set multicast port
	sin_len = sizeof(sin);
	iRet=bind(socket_descriptor, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));	//bind socket
	if (iRet)
		printf("bind return %d \n", iRet);

	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	mreq.imr_multiaddr.s_addr=inet_addr(GRUPO);
	iRet = setsockopt(socket_descriptor,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,8); //>=0 success, <0 fail;join the multicast group
//	if (iRet)
		printf("setsockopt return %d,errno:  \n", iRet);
	if(iRet<0)
	{
		Listened = 0;
		return -1;
	}
	peeraddr_len=sizeof(peeraddr);

	while (1)
  	{
		/*  Listen on TC Server Broadcast address to discover server */
		recieve_bytes = recvfrom(socket_descriptor, &message, sizeof(message),0,
                        (struct sockaddr *)&peeraddr, &peeraddr_len);

//    		recieve_bytes = recvfrom(socket_descriptor, &message, sizeof(message), 
//			MSG_DONTWAIT, (struct sockaddr *)&peeraddr, &peeraddr_len);
	#ifdef DEBUG
		printf("rev bytes %d\n", recieve_bytes);
		printf("%s\n", message.data);
		//printf("%x\n", message.tail_flag);
		//printf("%s\n", message.head_flag);
	#endif

		/* Parse the receive data to discover Server URL*/
		if ( recieve_bytes != -1 
			&& check_flag( &message ) )
		{
			//message.data_len = ntohs(message.data_len);
			
			if ( message.data_len > 0 && message.data_len < MAX_DATA_LEN )
			{
				//check XOR (data[0] - data[len-1]) equal to data[len]
				char tempchar = message.data[0];
				for(i=1;i<message.data_len;i++)
				{
					tempchar ^= message.data[i];
				}
				
							
				#ifdef DEBUG
					printf("XOR value is 0x%x\n", message.data[message.data_len]);
				#endif

				if (tempchar == message.data[message.data_len])		//pass the XOR check 
				{
					message.data[message.data_len] = 0 ; //set it as the ending point for this char array;Add by Fred
					
					/* original code*/
					setProvisionSucceedFlag(1);//auto provision succeed
					ServerInfo_ServerAddress(message.data, "SET");//set server address
					char proxyaddr[MAX_DATA_LEN];
					memset (proxyaddr, 0, MAX_DATA_LEN);
					int iRet = ProxyInfo_Construct(proxyaddr);
					if (iRet) WritestrLog(MODULE_CONNMGMT, "ProxyInfo_Construct failed");
					
					if (proxyaddr != NULL && strlen(proxyaddr) > 0)
						ServerInfo_ProxyAddress(proxyaddr,"SET");//set proxy info
					iRet = 0;
				#ifdef DEBUG
					printf("Exit for discover server  \n");
				#endif

					goto EXIT_StartListen;
					/* original code*/
				}
				
			}
		}

		/* sleep random seconds  ( 1 ~ 60)*/
		wait_seconds = rand() % 6 + 1 ;
//		receive_timeout -= wait_seconds;

	#ifdef DEBUG
		printf("wait %d seconds remain %d seconds \n", wait_seconds, receive_timeout);
	#endif
		sleep( wait_seconds );
		
		/* timeout */
/*		if ( receive_timeout <= 0 )
		{
		#ifdef DEBUG
			printf("Exit for timeout  \n");
		#endif
			goto EXIT_StartListen;
		}*/
  	}

EXIT_StartListen:
	Listened = 1;
  	close(socket_descriptor);
	return iRet;
}
