#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <iostream>
using namespace std;

#define MaxRTTime        5
#define MaxRecvBuffSize  (20 * 1024)

void handleAlarm(int signal)
{
	return; // just return and interupt.
}


// main function
int main( int argc, char * argv[] )
{
	if(argc != 4)
	{
		cerr << PROG_NAME << " Version :" << PROG_VERSION << endl;
		cerr << "Usage: " << PROG_NAME << " server-ip port mode" << endl;
		return EXIT_FAILURE;
	}

	static bool success = false;
	// parse command line arguments
	string host = argv[1];
	int	port = 	atoi(argv[2]);
	string mode = argv[3];

	//cout << "arguments : " << host << "," << port << "," << mode  << endl;
	
	int r = -1;
	struct sockaddr_in cliaddr;
	int addr_len = sizeof(cliaddr);
	char recvbuf[MaxRecvBuffSize];
	string result;

	// socket initialize
	int s = -1;
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if(s < 0)
	{
		cerr << "Socket Create: errno:" << errno << " errmsg:" << strerror(errno) << endl;
		return EXIT_FAILURE;
	}

	struct timeval timeout;
	timeout.tv_sec = MaxRTTime;
	timeout.tv_usec = 0;
	int optlen = sizeof(timeout);

	int errtimeout = -1;
	if( setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, (socklen_t)optlen) < 0)
	{
		struct sigaction sigact, oldact;
		sigact.sa_handler = handleAlarm;
		sigemptyset(&sigact.sa_mask);
		sigact.sa_flags = 0;
#ifdef SA_INTERRUPT
		sigact.sa_flags |= SA_INTERRUPT;
#endif // SA_INTERRUPT		
		if(sigaction(SIGALRM, &sigact, &oldact) < 0)
		{
			cerr << "sigaction error: errno:" << errno << " errmsg:" << strerror(errno) << endl;
			return EXIT_FAILURE;
		}
		errtimeout = EINTR;
	}
	else
		errtimeout = EAGAIN;

	struct sockaddr_in SocAddr;	

	SocAddr.sin_family = AF_INET;
	SocAddr.sin_port = htons(port);
	//SocAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (inet_aton(host.c_str(), &SocAddr.sin_addr)==0) 
	{
		cerr << "inet_aton() failed: errno:" << errno << " errmsg:" << strerror(errno) << endl;
		return EXIT_FAILURE;
	}
	
	// send
	int len = mode.length();
	if( sendto( s, mode.c_str(), mode.length(), 0, (struct sockaddr *)&SocAddr, sizeof(SocAddr) ) !=  len)
	{
		cerr << "sendto error : errno :"<< errno << " errmg:" << strerror(errno) << endl;
		goto GOTO_END;
	}	

	if( errtimeout == EINTR )
	{
		alarm(MaxRTTime);
	}

	// receive
	do 
	{
		memset(recvbuf, 0, MaxRecvBuffSize);
		r = recvfrom( s, (char *)&recvbuf, (unsigned int)MaxRecvBuffSize, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len );
		//cerr << "nREAD = " << r << "," << errno << endl;
		
		if(r >= 0) 
			result += recvbuf;
		else 
		{
			if( errno == errtimeout ) // timeout
			{
				cerr << "3:" << (long)time(NULL) << ":Disabled" << endl;
				goto GOTO_END;
			}
		}

	} while (r <= 0);	

	cout << result << endl;
	
	if (result.size()) 
		success = true;

GOTO_END:
	close(s);

	return success ? EXIT_SUCCESS : EXIT_FAILURE;
}

