/*
*========================================================================
*
*   SYSTEM   : AZN_PLAZA_LANE BACKGROUND
*   FILE     : sock_function.c
*   Progrmer : JBY (baarong@neighbor21.co.kr)
*   Date     : 2018.09.05
*   Modified :
*   Remark   :
*
*========================================================================
*/

/*==========================================================================*/
/* Head  정의                                                               */
/*==========================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/msg.h>
#include <sys/ipc.h>

#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include "lo_ctrl.h"
#include "func_list.h"
#include "file_lb.h"
#include "lb_func_list.h"
#include "path_def.h"

/*==========================================================================*/
/* 전역 변수 정의                                                           */
/*==========================================================================*/

extern    u_char    r_buffer[4096];       /* SOCK recv buffer       */
extern    u_char    rs_buffer[4096*4];    /* SOCK recv save buffer  */
extern    int       r_length;             /* SOCK length to be read */
extern    int       rs_length;            /* SOCK recv save length  */
extern    char      lcl_addr[15+1];       /* SOCK LCL address       */
extern    FILE *debug;

extern int conn_sock;

#define FAIL     -1

#define KEEPALIVE_OPTION  1             /* 0 set = default(off)   */
#define REUSEADDR_OPTION  1             /* 0 set = default(off)   */
#define RCVBUFF_OPTION    0             /* 0 set = default        */
#define SNDBUFF_OPTION    0             /* 0 set = default        */

/*
 *========================================================================
 *
 *   Function : sock_open_port()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : TCP/IP OPEN
 *
 *========================================================================
*/
int sock_open_port(int lane)
{
    struct sockaddr_in serv_addr, cli_addr;
	struct linger ling;
	struct timeval send_tv;
    socklen_t clilen;
    int optval;

    lo_comm_ctrl.rcv.psn = 0;
    lo_comm_ctrl.rcv.sno = 0;
    lo_comm_ctrl.snd.sno = 0;
//printf("-------------------------------------1-------------------------------\n");
    sock_close_port();
	
//printf("-------------------------------------2-------------------------------\n");
    conn_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (conn_sock < 0)
    {
        proc_log("conn_sock FAIL");
        return (FAIL);
    }
//printf("-------------------------------------3-------------------------------\n");
#if KEEPALIVE_OPTION
    optval=KEEPALIVE_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0 ){
        proc_log("KEEPALIVE_OPTION FAIL");
        return(FAIL);
    }
#endif
//printf("-------------------------------------4-------------------------------\n");
#if RCVBUFF_OPTION
    optval=RCVBUFF_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)) < 0 ){
        proc_log("RCVBUFF_OPTION FAIL");
        return(FAIL);
    }
#endif
//printf("-------------------------------------5-------------------------------\n");
#if SNDBUFF_OPTION
    optval=SNDBUFF_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) < 0 ){
        proc_log("SNDBUFF_OPTION FAIL");
        return(FAIL);
    }
#endif

    ling.l_onoff = 1;
    ling.l_linger = 0;
    setsockopt(conn_sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));

    send_tv.tv_sec = 15;
	send_tv.tv_usec = 0;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&send_tv, sizeof(send_tv)) < 0)
    {
        proc_log("SEND_TIME_OUT_OPTION FAIL");
        return(FAIL);
    }

//printf("-------------------------------------6-------------------------------\n");
#if REUSEADDR_OPTION
    optval=REUSEADDR_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0 ){
        proc_log("REUSEADDR_OPTION FAIL");
        return(FAIL);
    }
#endif
//printf("-------------------------------------7-------------------------------\n");
    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family      = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port        = htons(atoi((const char *)lo_comm_ctrl.device_nm));
//printf("-------------------------------------8-------------------------------\n");
    if (bind(conn_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
        return(FAIL);
    }
    if (listen(conn_sock, 1) < 0){
        return(FAIL);
    }
//printf("-------------------------------------9[%d]-------------------------------\n", atoi((const char *)lo_comm_ctrl.device_nm));
    clilen = sizeof(cli_addr);
//printf("-------------------------------------A-------------------------------\n");
    do{
        close(lo_comm_ctrl.port_fd);
        lo_comm_ctrl.port_fd = accept(conn_sock, (struct sockaddr *)&cli_addr, &clilen);
        proc_log("%d차로로 %s:%d가 접속하였습니다.\n", lane, inet_ntoa(cli_addr.sin_addr), serv_addr.sin_port);
        printf("%d차로로 %s:%d가 접속하였습니다.\n", lane, inet_ntoa(cli_addr.sin_addr), serv_addr.sin_port);
    }while(0);
    return (lo_comm_ctrl.port_fd);
}

/*
 *========================================================================
 *
 *   Function : sock_accept_port()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : TCP/IP ACCEPT
 *
 *========================================================================
*/
int sock_accept_port()
{
    struct sockaddr cli_addr;
    socklen_t clilen;

    lo_comm_ctrl.rcv.psn = 0;
    lo_comm_ctrl.rcv.sno = 0;
    lo_comm_ctrl.snd.sno = 0;

    sock_close_port();

    clilen = sizeof(cli_addr);
    lo_comm_ctrl.port_fd = accept(conn_sock, (struct sockaddr *)&cli_addr, &clilen);

    return (lo_comm_ctrl.port_fd);
}

/*
 *========================================================================
 *
 *   Function : sock_conn_port()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : 해당 Port에 연결
 *
 *========================================================================
*/
int sock_conn_port()
{
    struct sockaddr_in serv_addr;
    int    sock,optval=10;

    lo_comm_ctrl.rcv.psn = 0;
    lo_comm_ctrl.rcv.sno = 0;
    lo_comm_ctrl.snd.sno = 0;

    sock_close_port();

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) return (sock);

#ifdef KEEPALIVE_OPTION
    if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof(optval)) < 0 ){
        return(FAIL);
    }
#endif

    bzero(&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family      = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port        = htons(atoi((const char *)hi_comm_ctrl.device_nm));

    if ((lo_comm_ctrl.port_fd = connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0){
        return(FAIL);
    }

    return (lo_comm_ctrl.port_fd);
}

/*
 *========================================================================
 *
 *   Function : sock_send_data()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : TCP/IP WRITE  차로제어기에 송신
 *
 *========================================================================
*/
int sock_send_data()
{
    int    snd_dd, conchk;
    int    retry = 5;
    int    i;
    char   sDate[15];
	char   buf;
	int tmp_fd = 0;
	struct timeval timeout;

    while (1){
        tmp_fd = lo_comm_ctrl.port_fd;
		
		timeout.tv_sec = 20;
		timeout.tv_usec = 0;

//printf("1\n");
        snd_dd = send(tmp_fd, lo_comm_ctrl.snd.buf, lo_comm_ctrl.snd.len, 0);
		
//        conchk = select(1, &tmp_fd, 0, 0, &timeout);
//        if(conchk <= 0)
//            return (-1);

//printf("2\n");
        if (snd_dd < 0){
            proc_log("(sock_function.c) snd_dd = %d, errno = %d, retry = %d\n", snd_dd, errno, retry);
            sleep(1);
            if((errno != EAGAIN && errno != EINTR) || !retry--) return (-1);
        }else break;
     }
//printf("3\n");
    lb_get_nowdate_tm(sDate);
//printf("4\n");
//   tagbl_Packet("\n%s", sDate);
//printf("5[%d]\n", snd_dd);
    /* 패킷 확인 */
//    for(i=0; i<snd_dd; i++){
//        if((i%50) == 0) tagbl_Packet("\n");
//printf("6[%d]\n", i);
//        tagbl_Packet("%02X", lo_comm_ctrl.snd.buf[i]);
//    }
//printf("7\n");
//    tagbl_Packet("\n");
//printf("8\n");
    lo_comm_ctrl.rcv.psn = 0;
//proc_log("Socket Send End\n");
    return 0;
}

/*
 *========================================================================
 *
 *   Function : sock_close_port()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : TCP/IP SHUTDOWN  port close
 *
 *========================================================================
*/
int sock_close_port()
{
    int     i ;
#if 0
    if (lo_comm_ctrl.port_fd < 0) return 0;

    close(lo_comm_ctrl.port_fd);
#else
    if (conn_sock < 0) return 0;

    close(conn_sock);
#endif
    //tagbl_packet_close();
    /* 관리자 포트 Close () */
   for(i=0; i<33; i++)
   {
        close(hi_comm_ctrl.manager[i].sock);
        hi_comm_ctrl.manager[i].sock = -1;
        hi_comm_ctrl.manager[i].lo_lane_ctrl_cmd.cmd = 0;
   }

    lo_comm_ctrl.port_fd = -1;
    //fclose(debug);
    return 0;
}

/*
 *========================================================================
 *
 *   Function : tagbl_packet_open()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.08.07
 *   Modified :
 *   Remark   : 패킷 log 시작
 *
 *========================================================================
*/
FILE *packet_f;

void tagbl_packet_open(char *plz, int lane)
{
    char   debug_f[128];
    char   debug_d[128];
    struct tm       *tm;
    time_t t;

    t = time(0);
    tm = localtime(&t);

    if(packet_f) fclose(packet_f);

    sprintf(debug_d, "%s/%04d%02d%02d", LOG_DIR, tm->tm_year+1900, tm->tm_mon+1,tm->tm_mday);
    mkdir(debug_d, 0755);

    sprintf(debug_f, "%s/tagbl_packet%.2s%02d.log", debug_d, plz, lane);
    packet_f = fopen(debug_f, "a+t");
}

/*
 *========================================================================
 *
 *   Function : tagbl_Packet()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.08.07
 *   Modified :
 *   Remark   : 차로 log PACKET 처리
 *
 *========================================================================
*/
int tagbl_Packet( char *fmt, ... )
{
#if 1
    va_list    ap;

    if( packet_f == NULL ) return -1;
    //tagbl_packet_open();

    va_start( ap, fmt );
    vfprintf( packet_f, fmt, ap );
    va_end( ap );

    fflush( packet_f );

    //tagbl_packet_close();
#endif
    return 0;
}

/*
 *========================================================================
 *
 *   Function : tagbl_packet_close()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.08.07
 *   Modified :
 *   Remark   : 패킷 log 종료
 *
 *========================================================================
*/
void tagbl_packet_close()
{
    fclose(packet_f);
}
