#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h> 
#include <string.h>

#include "apr.h"
#include "apr_pools.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_poll.h"
#include "apr_hash.h"
#include "apr_thread_proc.h"
#include "apr_errno.h"
#include "apr_env.h"

#include "ndlb_encode.h"
#define BUFLEN 512
#define PORT 1112

void err(char *s)
{
      perror(s);
          exit(1);
}
int sockfd,slen;
int firstappid = 1;
struct sockaddr_in serv_addr;
void initsock() {
  
  int i;
  slen=sizeof(serv_addr);
  
  if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
    err("socket");

  bzero(&serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(PORT);
 // if (inet_aton("66.220.31.147", &serv_addr.sin_addr)==0)
//  if (inet_aton("216.218.163.83", &serv_addr.sin_addr)==0)
//if (inet_aton("10.20.0.79", &serv_addr.sin_addr)==0)
  if (inet_aton("172.24.1.59", &serv_addr.sin_addr)==0)
  {
    fprintf(stderr, "inet_aton() failed\n");
    exit(1);
  }
}

#define FLOWPATHINSTANCEINITIALID 0x4000000000000000L +(((long long )(0 &  0x0F)) << 46)+ (((long long)(0 & 0x03FFL)) << 36) 

long long int my_gettimeofday()
{
  return ((long long int) apr_time_now() / (long long int)1000);
}

long long generate_flowpath_instance()
{
  long long currTimeStamp;

  /*Flowpath masks variables*/
  long long FlowpathInstance;

  currTimeStamp = my_gettimeofday();
int rSeq = 0;
long long xx=FLOWPATHINSTANCEINITIALID;
  apr_atomic_inc32(((volatile apr_uint32_t*)&rSeq));
  FlowpathInstance = (xx +2 +
    ((currTimeStamp & 0x3FFFFFFFFFL) << 8) + (apr_atomic_inc32(((volatile apr_uint32_t*)&rSeq)) & 0xFF));

  return FlowpathInstance;
}

long long main1(int msgType,int ii, long long ffid)
{
  long long gotfid = ffid;
  char buf[BUFLEN];

    char sBuff[128*1024] = "";
    msgHdr_t msgHdr;
    wrapheader_t wrapHeader;
    int len = 0;
    int bytesSent = 0;
    char *apiReqId="akkdnfjnflffk";
    char *awsReqId="lksjskwjdkdldl";
    char *funcName="lamdafunion_test1";
    int agentType=0;
    int pid=getpid();;
    char *tags ="tierName=tier_test1;ndAppServerHost=server_test1;appName=lamdafunion_test1";
    wrapHeader.wrapheadervar.apiReqLen = apiReqId ? strlen(apiReqId) : 0;
    wrapHeader.wrapheadervar.awsReqLen = awsReqId ? strlen(awsReqId) : 0;
    wrapHeader.wrapheadervar.funcNameLen = funcName ? strlen(funcName) : 0;
    wrapHeader.wrapheadervar.tagslength = tags ? strlen(tags) : 0;
    wrapHeader.wrapheadervar.agentType = agentType > 0 ? agentType : 0;
    wrapHeader.wrapheadervar.protocolType = 0;
    if(msgType==2) {
      wrapHeader.wrapheadervar.fpId = generate_flowpath_instance();
      gotfid = wrapHeader.wrapheadervar.fpId;
      fprintf(stderr, "fpid %lld\n", wrapHeader.wrapheadervar.fpId);
    }
    else
      wrapHeader.wrapheadervar.fpId = gotfid;
    if(firstappid) {
      firstappid = 0;
    wrapHeader.wrapheadervar.appId= -1;
  }
  else {
    wrapHeader.wrapheadervar.appId= 0;
  }
    //wrapHeader.wrapheadervar.flowpathinstance = 0;
    if(msgType < 4)
      wrapHeader.wrapheadervar.messageType = 0;
    else if(msgType == 4)
      wrapHeader.wrapheadervar.messageType = 1;
    else
      wrapHeader.wrapheadervar.messageType = 2;
//    wrapHeader.wrapheadervar.pid = pid > 0 ? pid : 0;
    wrapHeader.wrapheadervar.whLen = sizeof(wrapheadervar_t)+wrapHeader.wrapheadervar.awsReqLen+wrapHeader.wrapheadervar.apiReqLen+wrapHeader.wrapheadervar.funcNameLen+wrapHeader.wrapheadervar.tagslength+1;
   // fprintf(stderr, "lens %d and %d\n", sizeof(wrapheadervar_t),wrapHeader.wrapheadervar.whLen);
    memcpy(sBuff, "^", 1);
    len += 1;
    memcpy(sBuff + len , (char *)&(wrapHeader.wrapheadervar), sizeof(wrapHeader.wrapheadervar));
    len += sizeof(wrapheadervar_t);
    if(wrapHeader.wrapheadervar.apiReqLen>0)
    {
      memcpy(sBuff + len, apiReqId, wrapHeader.wrapheadervar.apiReqLen);
      len += wrapHeader.wrapheadervar.apiReqLen;
    }

    if(wrapHeader.wrapheadervar.awsReqLen>0)
    {
      memcpy(sBuff + len, awsReqId, wrapHeader.wrapheadervar.awsReqLen);
      len += wrapHeader.wrapheadervar.awsReqLen;
    }

    if(wrapHeader.wrapheadervar.funcNameLen>0)
    {
      memcpy(sBuff + len, funcName, wrapHeader.wrapheadervar.funcNameLen);
      len += wrapHeader.wrapheadervar.funcNameLen;
    }
    if(wrapHeader.wrapheadervar.tagslength>0)
    {
      memcpy(sBuff + len, tags, wrapHeader.wrapheadervar.tagslength);
      len += wrapHeader.wrapheadervar.tagslength;
    }

    if(msgType==0)
    {
      MethodEntry_t node;
      char *methodName=NULL;
	if(ii == 0) {
		methodName="PDO.query";
	}
	else if (ii == 1){
		methodName="custom_method_name";
	} else {
		methodName="request.get";
	}
      char *query_string = "select * from countries";
      char *urlParameter=NULL;
      int mid=0;
      long long startTime=0;
      int pid=getpid();
      node.MethodEntryVar.methodName = methodName ? strlen(methodName) : 0;
      node.MethodEntryVar.threadId= 0;
      node.MethodEntryVar.query_string = query_string ? strlen(query_string) : 0;
      node.MethodEntryVar.urlParameter = urlParameter ? strlen(urlParameter) : 0;
      node.MethodEntryVar.mid = mid > 0 ? mid : 0;
      node.MethodEntryVar.startTime = startTime > 0 ? startTime:0;

      msgHdr.header_len = sizeof(msgHdr_t);
      msgHdr.total_len = sizeof(MethodEntryVar_t) + msgHdr.header_len + node.MethodEntryVar.methodName +
	node.MethodEntryVar.query_string+ node.MethodEntryVar.urlParameter + 3;
      msgHdr.msg_type = 0;
      memcpy(sBuff + len , "^",1);
      len += 1;
      memcpy(sBuff + len , (char *)&(msgHdr), msgHdr.header_len);
      len += sizeof(msgHdr);
      memcpy(sBuff + len , "|",1);
      len += 1;
      memcpy(sBuff + len, (char *)&(node.MethodEntryVar), sizeof(MethodEntryVar_t));
      len += sizeof(MethodEntryVar_t);
      if(node.MethodEntryVar.methodName  > 0)
      {
	memcpy(sBuff + len, methodName, node.MethodEntryVar.methodName);
	len += node.MethodEntryVar.methodName;
      }

      if(node.MethodEntryVar.query_string)
      {
	memcpy(sBuff + len, query_string, node.MethodEntryVar.query_string);
	len += node.MethodEntryVar.query_string;
      }
      if(node.MethodEntryVar.urlParameter)
      {
	memcpy(sBuff + len, urlParameter, node.MethodEntryVar.urlParameter);
	len += node.MethodEntryVar.urlParameter;
      }
     // fprintf(stderr, "callentry for %s\n", methodName);
    }
    if(msgType==1)
    {
      MethodExit_t node;
      int statusCode=200;
      int eventType =1;
      int isCallout =1;
      int mid=12;
      long duration=363;
      //int startTime=1620;
      long long cpuTime=0;
      int tierCallOutSeqNum=45;
      long long endTime =0;
	char *methodName=NULL;
        if(ii == 0) {
                methodName="PDO.query";
        }
        else if (ii == 1){
                methodName="custom_method_name";
        } else {
                methodName="request.get";
        }
      char *backend_header="NA|10.20.0.85|NA|NA|mydb|mysql|NA|NA|NA|root";
      char *requestNotificationPhase="";
      node.MethodExitVar.statusCode = statusCode > 0 ? statusCode : 0;
      node.MethodExitVar.mid = mid > 0 ? mid : 0;
      node.MethodExitVar.eventType = eventType > 0 ? eventType : 0;
      node.MethodExitVar.isCallout = isCallout > 0 ? isCallout : 0;
      node.MethodExitVar.duration = duration > 0 ? duration : 0;
      node.MethodExitVar.threadId = 0;
      node.MethodExitVar.cpuTime = cpuTime > 0 ? cpuTime : 0;
      node.MethodExitVar.tierCallOutSeqNum = tierCallOutSeqNum > 0 ? tierCallOutSeqNum : 0;
      node.MethodExitVar.endTime = endTime > 0 ? endTime : 0;
      node.MethodExitVar.methodName = methodName ? strlen(methodName) : 0;
      node.MethodExitVar.backend_header = backend_header ? strlen(backend_header) : 0;
      node.MethodExitVar.requestNotificationPhase = requestNotificationPhase ? strlen(requestNotificationPhase) : 0; 
      msgHdr.header_len = sizeof(msgHdr_t);
      msgHdr.total_len = sizeof(MethodExitVar_t)+ msgHdr.header_len + node.MethodExitVar.methodName + node.MethodExitVar.backend_header +
	node.MethodExitVar.requestNotificationPhase + 3;
      msgHdr.msg_type = 1;

      memcpy(sBuff + len , "^",1);
      len += 1;
      memcpy(sBuff + len , (char *)&(msgHdr), msgHdr.header_len);
      len += sizeof(msgHdr);

      memcpy(sBuff + len , "|",1);
      len += 1;

      memcpy(sBuff + len, (char *)&(node.MethodExitVar), sizeof(node.MethodExitVar));
      len += sizeof(MethodExitVar_t);

      if(node.MethodExitVar.methodName > 0)
      {
	memcpy(sBuff + len, methodName, node.MethodExitVar.methodName);
	len += node.MethodExitVar.methodName;
      }

      if(node.MethodExitVar.backend_header > 0)
      {
	memcpy(sBuff + len, backend_header, node.MethodExitVar.backend_header);
	len += node.MethodExitVar.backend_header;
      }

      if (node.MethodExitVar.requestNotificationPhase > 0)
      {
	memcpy(sBuff + len, requestNotificationPhase, node.MethodExitVar.requestNotificationPhase);
	len += node.MethodExitVar.requestNotificationPhase;
      }
     // fprintf(stderr, "callexit for %s\n", methodName);
    }

    if(msgType==2)
    {
      transactionStart_t node;
      long qTimeMS =0;
      long long startTimeFP=0;
      char *fp_header="header";
      char *url ="http://10.20.0.85:81/PDO/pdo_test1.php";
      char *btHeaderValue=NULL;
      char *ndCookieSet=NULL;
      char *nvCookieSet=NULL;
      char *correlationHeader=""; 
      node.transactionStartVar.qTimeMS = qTimeMS > 0 ? qTimeMS : 0;
      node.transactionStartVar.startTimeFP = startTimeFP > 0 ? startTimeFP : 0;
      node.transactionStartVar.fp_header = fp_header ? strlen(fp_header) : 0;
      node.transactionStartVar.url = url ? strlen(url) : 0;
      node.transactionStartVar.btHeaderValue = btHeaderValue ? strlen(btHeaderValue) : 0;
      node.transactionStartVar.ndCookieSet = ndCookieSet ? strlen(ndCookieSet) : 0;
      node.transactionStartVar.nvCookieSet = nvCookieSet ? strlen(nvCookieSet) : 0;
      node.transactionStartVar.correlationHeader = correlationHeader  ? strlen(correlationHeader) : 0;
      msgHdr.header_len = sizeof(msgHdr_t);
      msgHdr.total_len = sizeof (transactionStartVar_t) + msgHdr.header_len + node.transactionStartVar.fp_header +
	node.transactionStartVar.ndCookieSet + node.transactionStartVar.nvCookieSet +
	node.transactionStartVar.correlationHeader +
	node.transactionStartVar.btHeaderValue +
	node.transactionStartVar.url + 3;
  node.transactionStartVar.flowpathinstance = wrapHeader.wrapheadervar.fpId;
      msgHdr.msg_type = 2;
      memcpy(sBuff+len, "^", 1);
      len += 1;
      memcpy(sBuff + len , (char *)&(msgHdr), sizeof(msgHdr_t));
      len += sizeof(msgHdr_t);
      memcpy(sBuff + len , "|",1);
      len += 1;
      memcpy(sBuff + len, (char *)&(node.transactionStartVar), sizeof(node.transactionStartVar));

      len += sizeof(node.transactionStartVar) ;
      if(node.transactionStartVar.fp_header)
      {
	memcpy(sBuff + len, fp_header, node.transactionStartVar.fp_header);
	len += node.transactionStartVar.fp_header;
      }

      if(node.transactionStartVar.url)
      {
	memcpy(sBuff + len, url, node.transactionStartVar.url);
	len += node.transactionStartVar.url;
      }

      if(node.transactionStartVar.btHeaderValue)
      {
	memcpy(sBuff + len, btHeaderValue, node.transactionStartVar.btHeaderValue);
	len += node.transactionStartVar.btHeaderValue;
      }

      if(node.transactionStartVar.ndCookieSet)
      {
	memcpy(sBuff + len, ndCookieSet, node.transactionStartVar.ndCookieSet);
	len += node.transactionStartVar.ndCookieSet;
      }

      if(node.transactionStartVar.nvCookieSet)
      {
	memcpy(sBuff + len, nvCookieSet, node.transactionStartVar.nvCookieSet);
	len += node.transactionStartVar.nvCookieSet;
      }

      if(node.transactionStartVar.correlationHeader)
      {
	memcpy(sBuff + len, correlationHeader, node.transactionStartVar.correlationHeader);
	len += node.transactionStartVar.correlationHeader;
      }

    }

    if(msgType==3)
    {
      transactionEnd_t transactionEnd;
      int N=sizeof (transactionEnd_t);
      int statuscode =200;
      long long endTime=0;
      transactionEnd.statuscode = statuscode > 0 ? statuscode : 0;
      transactionEnd.endTime = endTime > 0 ? endTime : 0;
      transactionEnd.flowpathinstance = wrapHeader.wrapheadervar.fpId;
      msgHdr.header_len = sizeof(msgHdr_t);
      msgHdr.total_len = msgHdr.header_len + N + 3;
      msgHdr.msg_type = 3;

      memcpy(sBuff+len, "^", 1);
      len += 1;

      memcpy(sBuff + len , (void *)&(msgHdr), sizeof(msgHdr));
      len += sizeof (msgHdr);
      memcpy(sBuff + len, "|", 1);
      len += 1;
      memcpy(sBuff + len, (void *)&transactionEnd, N);
      len += N;
    }
    if(msgType==4)
    {
      memcpy(sBuff+len, "^", 1);
      len += 1;
      //char *resp = "NetDiagnosticMessage 2.0;Version:2.0;TxnId:10032130;SeqNo:;Priority:0;Encoding:none;SrcComp:JavaAgent;DestComp:UI;Tier:navi123n;Server:127.0.0.1;Instance:java1243;MsgName:application_havoc_inject;MsgType:1;Status:Success;Message:"";Operation:Forward;SubOperation:;ContentLength:0;Connection:Same;TimeStamp:13/12/21 16:50:27;ContentType:;TimeOut:1000;AHMID:100;PODName:localhost;";
      char *resp = "NetDiagnosticMessage 2.0;Version:2.0;TxnId:10032130;SeqNo:;Priority:0;Encoding:none;SrcComp:UI;DestComp:JavaAgent;Tier:rachit123;Server:127.0.0.1;Instance:java4321;MsgName:application_havoc_inject;MsgType:0;Status:;Message:;Operation:Forward;SubOperation:;ContentLength:0;Connection:Same;TimeStamp:13/12/21 16:50:27;ContentType:text;AHMID:100;TimeOut:20;NHMID:10;PODName:10.10.3068.134;config:{\"enable\"-1,\"havocType\"-1, \"bTName\"-\"/http.GET\", \"uRL\"-\"/http\", \"methodFQM\" -\"okhttp3.Request$Builder.build()Lokhttp3/Request|\",\"delayInSec\"- 120, \"totalDurationInSec\"-30,\"threshOld\"-{\"count\"-56,\"percentage\"-\"35\",\"currentcount\"-\"20\"},\"protocol\"-\"test\",  \"hostname\" -\"test\", \"port\"-\"8080\",\"backendName\"- \"test\",\"leaksINMB\"-500,\"percentageCPU\"-20};";
      memcpy(sBuff + len, resp, strlen(resp));
      len += strlen(resp);
      //fprintf(stderr, "sbuff %s\n", sBuff);
    }
    if(msgType < 4)
    memcpy(sBuff + len, "\n", 1);
    len += 1;


  //while(1)
 // {
//    printf("\nEnter data to send(Type exit and press enter to exit) : ");
  //  scanf("%[^\n]",buf);
   // getchar();
   // if(strcmp(buf,"exit") == 0)
     // exit(0);

    if (sendto(sockfd, sBuff, len, 0, (struct sockaddr*)&serv_addr, slen)==-1)
      err("sendto()");
 // }


 // close(sockfd);
  return gotfid;
}
apr_pool_t* proxy_pool;
int main()
{
int ii = 0;
apr_initialize();
  apr_pool_create(&proxy_pool, NULL);

initsock();
int ss=0;
while(1)
{

  long long ff = main1(2,ii,0);
  if(ss >7)
    sleep(90);
  if(ss > 8)
    sleep(600);
  main1(0,ii,ff);
  main1(1,ii,ff);
  if(ss == 5)
    main1(3,ii,ff);
  


  ss++;
if(ii == 0)
ii=1;
else if(ii==1)
ii=2;
else 
ii=0;
  usleep(80000);
 }
 close(sockfd);
  return 0;

}

