/*
RTMP Server
*/
#include <sys/select.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <strings.h>
#include "rtmp.h"
amfHeader_real *AMFS = 0x0;
int main(void) {
  int sockFD = 0x0; //Listener Socket
  int newFD  = 0x0; //New Socket;
  struct sockaddr_in my_addr;	// my address information
  struct sockaddr_in their_addr; // connector's address information
  socklen_t sin_size;
  struct sigaction sa;
  int yes=1;
  AMFS = (amfHeader_real *)malloc(sizeof(amfHeader_real) * 128);
  if ((sockFD = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
    }
  if (setsockopt(sockFD, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
    perror("setsockopt");
    exit(1);
    }
	
   my_addr.sin_family = AF_INET;		 // host byte order
   my_addr.sin_port = htons(MYPORT);	 // short, network byte order
   my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
   memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
  if (bind(sockFD, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
    perror("bind");
    exit(1);
    }
  if (listen(sockFD, BACKLOG) == -1) {
    perror("listen");
    exit(1);
    }
/*
  sa.sa_handler = sigchld_handler; // reap all dead processes
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_RESTART;
  if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
    }
*/
  while(1) {  // main accept() loop
    sin_size = sizeof(struct sockaddr_in);
    if ((newFD = accept(sockFD, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
      perror("accept");
      continue;
      }
    fcntl(newFD, F_SETFL, fcntl(newFD, F_GETFL, 0) | O_NONBLOCK);
    printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
/*
    if (!fork()) { // this is the child process
      close(sockFD); // child doesn't need the listener
*/
      if (doHandshake(newFD) != 0) {
        close(newFD);
        exit(0);
        }
/*
      if (doAccept(newFD) != 0) {
        close(newFD);
        exit(0);
        }
*/
      while (1) {
        //bzero(&data,4096);
        //recv(new_fd,&data,1,MSG_WAITALL);     
        /*
        if (getAMF(newFD,data[0]) != 0x0) {
        */
        if (getAMF(newFD) != 0x0) {
          printf("Error");
          close(newFD);
          exit(0);
          } 
        }
/*
      }
*/
    close(newFD);  // parent doesn't need this
    }
  return 0;
  }
int getAMF(int fd) {
  int AMF;
  int recLen     = 0x0;
  int amfID      = 0x0;
  int headerSize = 0x0;
  int packetSize = 0x0;
  int i = 0x0;
  char data[12];
  amfHeader *amfHdr = (amfHeader *)&data;
  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(fd,&readset);
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
  recLen = recv(fd,&AMF,1,0);
  if (recLen != 1)
    return(-1);
  headerSize = (AMF & 0xC0) >> 6;
  amfID      = (AMF & 0x3F); 
  switch(headerSize) {
    case 0:
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
      recLen = recv(fd,&data,11,0);
      printf("12 Byte Header\n");
      packetSize = (amfHdr->amfSize[0] * 256 * 256) + (amfHdr->amfSize[1] * 256) + amfHdr->amfSize[2];
      printf("PacketSize: [%i]\n",packetSize);
      AMFS[amfID].bodySize  = packetSize;
      AMFS[amfID].bodyCount = 0;
      AMFS[amfID].body = (char *)malloc(packetSize);
      AMFS[amfID].amfType = amfHdr->amfType[0];
      if (packetSize > 128) {
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
        recv(fd,AMFS[amfID].body + AMFS[amfID].bodyCount,128,0);
        AMFS[amfID].bodyCount = 128;
        }
      break;
    case 3:
      printf("4 Byte Header\n");
      if ((AMFS[amfID].bodySize - AMFS[amfID].bodyCount) > 128) {
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
        recv(fd,AMFS[amfID].body + (AMFS[amfID].bodyCount - 1),128,0);
        AMFS[amfID].bodyCount += 128;
        }
      else {
        printf("Bal: (%i)\n",(AMFS[amfID].bodySize - AMFS[amfID].bodyCount));
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
        recLen = recv(fd,AMFS[amfID].body + (AMFS[amfID].bodyCount - 1),(AMFS[amfID].bodySize - AMFS[amfID].bodyCount)-1,0);
        printf("Received: [%i]\n",recLen);
        AMFS[amfID].bodyCount += (AMFS[amfID].bodySize - AMFS[amfID].bodyCount)-1;
        }
      break;
    default:
      printf("Unhandled Header Size: [%i]\n",headerSize);
      return(-1);
      break;
    }
  if (AMFS[amfID].bodySize == AMFS[amfID].bodyCount)
    doProcessPacket(fd,amfID);
  return(0x0); 
  }
int doProcessPacket(int fd,int amfID) {
  printf("WOOP");
  return(0x0);
  }
int getAMF_old(int fd,int amf) {
  int recLen        = 0x0;
  int amfID         = 0x0;
  int headerSize    = 0x0;
  int packetSize    = 0x0;
  char data[12];
  amfHeader *amfHdr = (amfHeader *)&data;
  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(fd,&readset);
  headerSize = (amf & 0xC0) >> 6;
  amfID      = amf & 0x3F;
  printf("AMF ID: [0x%X]\n",amfID);
  switch(headerSize) {
    case 0:
      printf("12 Byte Header\n");
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
      recLen = recv(fd,&data,11,0);
      printf("Size: [0x%X:0x%X:0x%X]\n",amfHdr->amfSize[0] & 0xFF,amfHdr->amfSize[1] & 0xFF,amfHdr->amfSize[2] & 0xFF);
      packetSize = (amfHdr->amfSize[0] * 256 * 256) + (amfHdr->amfSize[1] * 256) + amfHdr->amfSize[2];
      printf("PacketSize: [%i]\n",packetSize);
/*
      recLen = recv(fd,&packet,packetSize,0);
        if (recLen != packetSize) {
          printf("Error Reading Packet\n");
          return(-1);
          }
*/
      break;
    default:
      printf("Unhandled Header Size: [%i]\n",headerSize);
      return(-1);
      break;
    }
  switch (amfHdr->amfType[0]) {
    case 0x14:
      doAmfFunction(fd,amfID,packetSize);
      break;
    default:
      printf("Unhandled amfType: [0x%X]\n",amfHdr->amfType[0]);
      return(-1);
      break;
    }
  return(0x0);
  }
int doAmfFunction(int fd,int amfID,int packetSize) {
  int   recLen = 0x0;
  int   i      = 0x0;
  int   ch     = 0x0;
  char *packet = 0x0;
  char  function[256];
  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(fd,&readset);
  printf("Reading Packet");
  packet = (char *)malloc(packetSize);
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
  recLen = recv(fd,packet,packetSize,MSG_WAITALL);
  for (i = 0;i < packet[2];i++) {
    function[i] = packet[i + 3];
    }
  function[i] = '\0';
  printf("Function: [%s]\n",function);
  if (!strcmp(function,"connect"))
    doAccept(fd);
  for (i=0;i<recLen;i++) {
    ch = packet[i];
    if (ch >= 10 && ch <= 128)
    printf("[%c]",ch);
    else
      printf("[0x%X]",ch);
    }
  printf("\n");
  return(0x0);
  }
int doHandshake(int fd) {
  int recLen = 0x0;
  int i      = 0x0;
  int cmd    = 0x0;
  char data1[1536];
  char data2[1536];
  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(fd,&readset);
  printf("Hi");
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
  printf("Bye");
 
  recLen = read(fd,&cmd,1);
  printf("recLen: %i\n",recLen);
  if (cmd != 0x03) {
    printf("Invalid Handshake\n");
    return(-1);
    }
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
  recLen = recv(fd,&data1,1536,0);
  printf("recLen: %i\n",recLen);
  for (i = 0;i < 1536;i++) {
    data2[i] = (char)i;
    }
  if (send(fd,&cmd,1,0) != 1) {
    printf("Error Sending Header\n");
    return(-1);
    }
  if (send(fd,&data2,1536,0) != 1536) {
    printf("Error Sending Hand2\n");
    return(-1);
    }
  if (send(fd,&data1,1536,0) != 1536) {
    printf("Error Sending Hand1\n");
    return(-1);
    }
  while (select(fd + 1,&readset,0x0,0x0,0x0)) {
    if (FD_ISSET(fd,&readset))
      break;
    }
  recLen = recv(fd,&data1,1536,0); 
  printf("recLen: [%i]\n",recLen);
  if (recLen 
  
  return(0x0);
  }
int doAccept(int fd) {
  char data[1024];
  char raw1[] = {0x02,0x00,0x00,0x00,0x00,0x00,0x04,0x05,0x00,0x00,0x00,0x00,0x07,0xeb,0x58,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x96,0x14,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x00,0x3f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x03,0x00,0x04,0x63,0x6f,0x64,0x65,0x02,0x00,0x1d,0x4e,0x65,0x74,0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x2e,0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x2e,0x53,0x75,0x63,0x63,0x65,0x73,0x73,0x00,0x05,0x6c,0x65,0x76,0x65,0x6c,0x02,0x00,0x06,0x73,0x74,0x61,0x74,0x75,0x73,0x00,0x07,0x64,0x65,0x74,0x61,0x69,0x6c,0x73,0x05,0x00,0x0b,0x64,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x02,0x00,0x15,0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x20,0x73,0x75,0x63,0x63,0x65,0x65,0x64,0x65,0x64,0x2e,0x00,0x0e,0x6f,0x62,0x6a,0x65,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x03,0xd0,0x90,0x02,0xc3,0x63,0x74,0x45,0x6e,0x63,0x6f,0x64,0x69,0x6e,0x67,0x00,0x40,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09};
  int recLen = 0x0;
 // recLen = recv(fd,&data,1024,0);
 // printf("reLen: [%i]\n",recLen);
  recLen = send(fd,&raw1,sizeof(raw1),0);
  printf("raw1: [%i:%i]\n",sizeof(raw1),recLen);
  return(0x0);
  }