/****************************************************************/
/*  RTP Implementation Program                                  */
/*  Version 9.0.1                                               */
/*  Designed By Ying Min                                        */
/*  Last Update: 2007-3-19                                      */
/****************************************************************/

#include "./include/rtp_pub.h"
#include "./include/rtp.h"
#include "./include/rtp_const.h"
#include "./include/rtp_def.h"
#include "./include/rtp_struct.h"
#include "./include/rtp_msg.h"

int rtp_get_local_ip(void)
{
    struct hostent  *host;
    char            hostName[64];
    char            hostIp[32];
    
    if (gethostname(hostName, 50) == -1)
    {
        printf("RTP gethostname fail!\n");
        exit(3);
    }
    
    if ((host = gethostbyname(hostName)) == NULL)
    {
        printf("RTP gethostbyname fail!\n");
        exit(4);
    }
    else
    {
        sprintf(hostIp, "%d.%d.%d.%d", 
                (BYTE)host->h_addr_list[0][0],
                (BYTE)host->h_addr_list[0][1],
                (BYTE)host->h_addr_list[0][2],
                (BYTE)host->h_addr_list[0][3]);
        rtpHostIp       = inet_addr(hostIp);    // Network byte order host_ip, like 0xE60012AC
        printf("RTP host IP: %s (0x%lX)\n", hostIp, rtpHostIp);
    }
    
    return 0;
}

void rtp_init(void)
{
    WORD    i;
    
    printf("RTP Init Start!\n");
    
    rtp_get_local_ip();
    
    memset((BYTE *) rtpSap, 0, sizeof(RTP_SAP) * RTP_MAX_NUM_OF_SAP);
    memset((BYTE *) rtpPort, 0, RTP_MAX_NUM_OF_PORT / 8);
    memset((BYTE *) rtpHdlPort, 0, sizeof(RTP_PORT) * RTP_MAX_NUM_OF_PORT);
    memset((BYTE *) rtpHdlPortFd, -1, sizeof(int) * RTP_MAX_NUM_OF_PORT);
    for (i = 0; i < RTP_MAX_NUM_OF_PORT; i++)
        rtpHdlPort[i].fd = -1;
    
    rtpHdlPortSelect = 0;
    rtpPortSelect = 0;
    RTP_BASE_UDP_PORT = RTP_BASE_UDP_PORT_CONST;
	/*
	{
		FILE *fp=NULL;
		unsigned short  base_port=25000;
		char s[80]="";

		fp = fopen("./conf/rtp.conf","r");
		if(fp != NULL)
		{
			while(fgets(s,1024,fp) !=(char *)0)
			{
				if( (int *)strchr(s,'#') !=NULL) continue;
				if( !strlen(s) ) continue;
				if(strncasecmp(s,"base port=",10)==0)
				{
					base_port = atoi(&s[10]);
					if(base_port>1000 && base_port<32768)
						RTP_BASE_UDP_PORT = base_port;
					else
						break;
				}
				else
					break;
			}
			fclose(fp);
		}

	}		*/
    printf("RTP Init Complete!\n");
}

// Called every 10 ms
void rtp_timer(void)
{
    rtp_recv_udp_msg();
}

void rtp_sap_init(BYTE sapIndex)
{
    memset((BYTE *) &rtpSap[sapIndex], 0, sizeof(RTP_SAP));
}

void rtp_port_init(WORD port)
{
    memset((BYTE *) &rtpHdlPort[port], 0, sizeof(RTP_PORT));
    rtpHdlPort[port].fd = -1;
    rtpHdlPortFd[port] = -1;
}

int rtp_init_udp_socket(struct sockaddr_in saddr, int multicast)
{
    int     sock;
    long    sockBuf = 40*1024; 
    int     on = 1, timeout = 20;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    
    if (sock < 0)
    {    
        fprintf(stderr, "Socket() failed\n");
        return -3;
    }
    
    if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
        &sockBuf, sizeof(sockBuf)) != 0)
    { 
        fprintf(stderr, "RTP set socket buffer failed\n");
        return -4;
    }
    
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
         &on,sizeof(on)) != 0)
    {
        fprintf(stderr, "RTP set addr reusable failed\n");
        return -5;
    }

    if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
         &timeout, sizeof(timeout)) != 0)
    {
       fprintf(stderr, "RTP set keepalive failed\n");
       return -6;
    }
    
    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
    {
        fprintf(stderr, "RTP set nonblock failed\n");
        return -7;
    }
    
    if (bind(sock, (struct sockaddr *) &saddr, sizeof(struct sockaddr)) < 0)
    {
        fprintf(stderr, "RTP binding failed, port: %d\n", htons(saddr.sin_port));
        close(sock);
        return -2;
    }
    
    return sock;
}

int rtp_init_socket(WORD hdlPort, WORD udpPort)
{
    struct sockaddr_in  sinAddr;
    int                 fd;
    
    memset(&sinAddr, 0, sizeof(struct sockaddr));
    sinAddr.sin_family = AF_INET;
    sinAddr.sin_port = htons(udpPort);
    sinAddr.sin_addr.s_addr = rtpHostIp; // INADDR_ANY;
    memset(&(sinAddr.sin_zero), 0, 8);
    
    fd = rtp_init_udp_socket(sinAddr, 0);
    if (fd < 0)
    {
        printf("RTP UDP Socket(%d) failed\n", udpPort);
        return -1;
    }
    
    rtpHdlPort[hdlPort].fd = fd;
    rtpHdlPortFd[hdlPort] = fd;
    
    return 0;
}

int rtp_get_udp_port(WORD hdlPort)
{
    WORD    port = rtpPortSelect;
    WORD    i, index1, index2;
    
    for (i = 0; i < RTP_MAX_NUM_OF_PORT; i++)
    {
        index1 = port / 32;
        index2 = port % 32;
        
        if (((rtpPort[index1] >> index2) & 1) == 1)
        {
            if (++port >= RTP_MAX_NUM_OF_PORT)
                port = 0;
            continue;
        }
        
        if (rtp_init_socket(hdlPort, port * 2 + RTP_BASE_UDP_PORT) < 0)
            return -1;

        rtpPort[index1] |= 1 << index2;
        rtpPortSelect = (port + 1) & RTP_MAX_NUM_OF_PORT_1;
        
        rtpHdlPort[hdlPort].rtpPort = port;
        return port;
    }
    
    return -1;
}

int rtp_release_udp_port(WORD hdlPort)
{
    WORD    port = rtpHdlPort[hdlPort].rtpPort;
    int     fd = rtpHdlPort[hdlPort].fd;
    WORD    index1, index2;
    
    if (port >= RTP_MAX_NUM_OF_PORT)
        return -1;
    
    index1 = port / 32;
    index2 = port % 32;
    rtpPort[index1] = rtpPort[index1] & (~(1 << index2));
    
    if (fd >= 0)
        close(fd);
    
    return 0;
}

int rtp_get_hdl_port()
{
    WORD    port = rtpHdlPortSelect;
    WORD    i;
    
    for (i = 0; i < RTP_MAX_NUM_OF_PORT; i++)
    {
        if (rtpHdlPort[port].flag != 0)
        {
            if (++port >= RTP_MAX_NUM_OF_PORT)
                port = 0;
            continue;
        }
        return port;
    }
    
    return -1;
}

int rtp_allocate_port(BYTE sapIndex, WORD usrPort, WORD *rtpPort)
{
    int     hdlPort, udpPort;
    
    if (sapIndex >= RTP_MAX_NUM_OF_SAP)
        return -1;
    
    if ((hdlPort = rtp_get_hdl_port()) < 0)
        return -1;
    
    if ((udpPort = rtp_get_udp_port(hdlPort)) < 0)
        return -1;
    
    rtpHdlPort[hdlPort].flag = 1;
    rtpHdlPort[hdlPort].sapIndex = sapIndex;
    rtpHdlPort[hdlPort].usrPort = usrPort;
    rtpHdlPort[hdlPort].timer = RTP_HANDSHAKE_TIMER;
    
    rtpHdlPortSelect = (hdlPort + 1) & RTP_MAX_NUM_OF_PORT_1;
    
    *rtpPort = udpPort * 2 + RTP_BASE_UDP_PORT;
    return hdlPort;
}

int rtp_release_port(BYTE sapIndex, WORD usrPort, WORD rtpPort, WORD hdlPort)
{
    if (hdlPort >= RTP_MAX_NUM_OF_PORT)
        return -1;
    
    if (rtpHdlPort[hdlPort].sapIndex != sapIndex)
        return -2;
    else if (rtpHdlPort[hdlPort].usrPort != usrPort)
        return -3;
    else if ((rtpHdlPort[hdlPort].rtpPort * 2 + RTP_BASE_UDP_PORT) != rtpPort)
        return -4;
    
    rtp_release_udp_port(hdlPort);
    
    rtp_port_init(hdlPort);
    
    return 0;
}

int rtp_sess_update(BYTE sapIndex, WORD usrPort, WORD hdlPort, RTP_SESSION *sess)
{
    if (hdlPort >= RTP_MAX_NUM_OF_PORT)
        return -1;
    
    if ((rtpHdlPort[hdlPort].sapIndex != sapIndex) ||
        (rtpHdlPort[hdlPort].usrPort != usrPort))
        return -1;
    
    memcpy((BYTE *) &rtpHdlPort[hdlPort].sess, (BYTE *) sess, sizeof(RTP_SESSION));
    
    rtpHdlPort[hdlPort].inc = rtpHdlPort[hdlPort].sess.interval * 8;
    
    return 0;
}

int rtp_set_mode(BYTE sapIndex, WORD usrPort, WORD hdlPort, BYTE mode)
{
    if ((hdlPort >= RTP_MAX_NUM_OF_PORT) || (mode > RTP_MODE_SENDRECV))
        return -1;
    
    if ((rtpHdlPort[hdlPort].sapIndex != sapIndex) ||
        (rtpHdlPort[hdlPort].usrPort != usrPort))
        return -1;
    
    rtpHdlPort[hdlPort].mode = mode;
    return 0;
}

int rtp_bind(RTP_SAP *sap)
{
    BYTE    i;
    
    if ((sap == NULL) || (sap->rtp_handshake == NULL))
        return -1;
    
    for (i = 0; i < RTP_MAX_NUM_OF_SAP; i++)
    {
        if (rtpSap[i].rtp_handshake != NULL)
            continue;
        memcpy((BYTE *) &rtpSap[i], sap, sizeof(RTP_SAP));
        rtpSap[i].name[RTP_MAX_USER_NAME_LEN - 1] = '\0';
        return i;
    }
    
    return -1;
}

int rtp_unbind(RTP_SAP *sap, BYTE sapIndex)
{
    if ((sap == NULL) || (sapIndex >= RTP_MAX_NUM_OF_SAP))
        return -1;
    
    if (strcmp(sap->name, rtpSap[sapIndex].name) != 0)
        return -1;
    
    rtp_sap_init(sapIndex);
    
    return 0;
}
