/****************************************************************/
/*  SIP Implementation Program                                  */
/*  Version 10.0.1                                              */
/*  Designed By Ying Min                                        */
/*  Last Update: 2006-10-19                                     */
/****************************************************************/

#include "./include/sip_pub.h"
#include "./include/sip.h"
#include "./include/sip_const.h"
#include "./include/sip_struct.h"
#include "./include/sip_def.h"
#include "./include/sip_transaction.h"
#include "./include/sip_transport.h"
#include "./include/sip_msg_parse.h"
#include "./include/sip_debug.h"

int sip_get_local_ip(void)
{
    struct hostent *host;
    
    if (gethostname(sipHostName, 50) == -1)
    {
        printf("SIP gethostname fail!\n");
        return -1;
    }
    
    if ((host = gethostbyname(sipHostName)) == NULL)
    {
        printf("SIP gethostbyname fail!\n");
        return -1;
    }
    else
    {
        sprintf(sipDottedHostIp, "%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]);
        sipHostIp = inet_addr(sipDottedHostIp);             // Network byte order sipHostIp, like 0xE60012AC
        printf("sipHostName: %s, sipHostIp: %s (0x%lX)\n", sipHostName, sipDottedHostIp, sipHostIp);
    }
    
    return 0;
}

int sip_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, "SIP set socket buffer failed\n");
        close(sock);
        return -4;
    }
    
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
         &on,sizeof(on)) != 0)
    {
        fprintf(stderr, "SIP set addr reusable failed\n");
        close(sock);
        return -5;
    }

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

int sip_init_tcp_server_socket(struct sockaddr_in saddr, int multicast)
{
    int     sock;
    int     on = 1, timeout = 20;

    sock = socket(AF_INET, SOCK_STREAM, 0);

    if (sock < 0)
    {    
        fprintf(stderr, "TCP Socket() failed\n");
        return -3;
    }

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
         &on,sizeof(on)) != 0)
    {
        fprintf(stderr, "SIP set tcp addr reusable failed\n");
        close(sock);
        return -4;
    }

    if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
          &timeout, sizeof(timeout)) != 0)
    {
        fprintf(stderr, "SIP set tcp keepalive failed\n");
        close(sock);
        return -5;
    }

    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
    {
        fprintf(stderr, "SIP set tcp nonblock failed\n");
        close(sock);
        return -6;
    }

    if (bind(sock, (struct sockaddr *) &saddr, sizeof(struct sockaddr)) < 0)
    {
        fprintf(stderr, "SIP tcp binding failed, port: %d\n", htons(saddr.sin_port));
        close(sock);
        return -2;
    }

    if (listen(sock, SIP_TCP_BACKLOG) < 0)
    {
        fprintf(stderr, "listen error\n");
        return -1;
    }

    return sock;
}

int sip_init_socket()
{
    struct sockaddr_in sinAddr;
    WORD port = 5060;

    memset(&sinAddr, 0, sizeof(struct sockaddr));
    sinAddr.sin_family = AF_INET;
    sinAddr.sin_port = htons(port);
    sinAddr.sin_addr.s_addr = INADDR_ANY;
    memset(&(sinAddr.sin_zero), 0, 8);
    
    sipUdpSocketFd = sip_init_udp_socket(sinAddr, 0);
    if (sipUdpSocketFd < 0)
    {
        printf("SIP UDP Socket(%d) failed\n", port);
        return -1;
    }

    sipTcpServerSocketFd = sip_init_tcp_server_socket(sinAddr, 0);
    if (sipTcpServerSocketFd < 0)
    {
        printf("SIP TCP Socket(%d) failed\n", port);
        return -1;
    }
    
    return 0;
}

int sip_init()
{
    int i;
    
    printf("SIP Module Init Start!\n");
    
    if (sip_get_local_ip() < 0)
        exit(1);
    
    if (sip_init_socket() < 0)
        exit(2);

//    memset((BYTE *)sipSipUaUser, 0, sizeof(SIP_SIP_UA_USER));
    memset((BYTE *)&sipRecvMsg, 0, sizeof(SIP_API_STRUCT));
    memset((BYTE *)&sipUsers, 0, sizeof(SIP_USERS_STRUCT));
    sipUsers.proxyIndex = SIP_MAX_NUM_OF_USERS;

    sipTransHead = 0;
    for (i = 0; i < SIP_MAX_NUM_OF_TRANS; i++)
        sip_trans_init(i);
    
    sip_parser_init();
    
    printf("SIP Module Init Complete!\n");
    
    return 0;
}

void sip_t10ms()
{
    static DWORD cnt_10ms = 0;
    
    if (!(++cnt_10ms % 10))
    {   // 100 ms
        sip_mon();
    }
}

void sip_timer()
{
    WORD transId;
    
    sip_transport_proc();
    
    for (transId = 0; transId < SIP_MAX_NUM_OF_TRANS; transId++)
    {
        if (sipTrans[transId].flag == 0)
            continue;
        sip_transaction_proc(transId);
    }
    
    sip_t10ms();
}

int sip_register_user(SIP_USER *sipUser)
{
    BYTE i;
    
    for (i = 0; i < SIP_MAX_NUM_OF_USERS; i++)
    {   // Search for already registered user
        if ((sipUsers.sipUsers[i].flag == 1) &&
            (strcmp(sipUsers.sipUsers[i].sipUser.userName, sipUser->userName) == 0))
        {
            memcpy(&sipUsers.sipUsers[i].sipUser, sipUser, sizeof(SIP_USER));
            if (sipUser->proxyType != SIP_PROXY_TYPE_NONE)
                sipUsers.proxyIndex = i;
            return i;
        }
    }
    
    for (i = 0; i < SIP_MAX_NUM_OF_USERS; i++)
    {
        if (sipUsers.sipUsers[i].flag == 0)
        {
            memcpy(&sipUsers.sipUsers[i].sipUser, sipUser, sizeof(SIP_USER));
            sipUsers.sipUsers[i].flag = 1;
            if (sipUser->proxyType != SIP_PROXY_TYPE_NONE)
                sipUsers.proxyIndex = i;
            return i;
        }
    }
    
    sprintf(sipAsciTempBuf, "SIP register user fail\r\n");
    sip_log_err(sipAsciTempBuf);
    
    return -1;
}

/*int sip_store_sip_ua_user(BYTE  index, char *domain)
{
    if ((domain == NULL) || (index >= SIP_MAX_NUM_OF_SIP_UA_USER))
        return -1;

    strcpy(sipSipUaUser[index].domain, domain);

    return 0;
}*/
