/*
 *========================================================================
 *
 *   시스템명 : 요금징수 시스템
 *   파 일 명 :
 *   작 성 자 : 오효섭 (catacath@neighbor21.co.kr)
 *   작 성 일 : 2012.10.04
 *   수 정 일 :
 *   설    명 :
 *
 *========================================================================
*/

/*==========================================================================*/
/* 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 <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include "hi_ctrl.h"
#include "lo_ctrl.h"
#include "func_list.h"
#include "file_lb.h"
#include "lb_func_list.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.08.24
 *   Modified :
 *   Remark   : TCP/IP OPEN
 *
 *========================================================================
*/
int sock_open_port()
{
    struct sockaddr_in serv_addr, cli_addr;
    struct linger ling;
    int    clilen, optval;

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

    sock_close_port();

    conn_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (conn_sock < 0)
    {
        lane_log("conn_sock FAIL");
        return (FAIL);
    }

#if KEEPALIVE_OPTION
    optval=KEEPALIVE_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0 ){
        lane_log("KEEPALIVE_OPTION FAIL");
        return(FAIL);
    }
#endif

#if RCVBUFF_OPTION
    optval=RCVBUFF_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)) < 0 ){
        lane_log("RCVBUFF_OPTION FAIL");
        return(FAIL);
    }
#endif

#if SNDBUFF_OPTION
    optval=SNDBUFF_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) < 0 ){
        lane_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));

#if REUSEADDR_OPTION
    optval=REUSEADDR_OPTION;
    if(setsockopt(conn_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0 ){
        lane_log("REUSEADDR_OPTION FAIL");
        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((char const *)hi_comm_ctrl.device_nm));

    if (bind(conn_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
        return(FAIL);
    }

    if (listen(conn_sock, 1) < 0){
        return(FAIL);
    }

    clilen = sizeof(cli_addr);

    do{
        close(lo_comm_ctrl.port_fd);
        lo_comm_ctrl.port_fd = accept(conn_sock, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen);
        lane_log("%d차로로 %s:%d가 접속하였습니다.\n", hi_comm_ctrl.lane_no, inet_ntoa(cli_addr.sin_addr), serv_addr.sin_port);
        printf("%d차로로 %s:%d가 접속하였습니다.\n", hi_comm_ctrl.lane_no, inet_ntoa(cli_addr.sin_addr), serv_addr.sin_port);
    }while(0);

    return (lo_comm_ctrl.port_fd);
}

 /*
 *========================================================================
 *
 *   함 수 명 : sock_accept_port()
 *   작 성 자 : 오효섭 (catacath@nate.com)
 *   작 성 일 : 2012.10.04
 *   수 정 일 :
 *   설    명 : TCP/IP ACCEPT
 *
 *========================================================================
*/
int sock_accept_port()
{
    struct sockaddr cli_addr;
    int    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, (socklen_t *)&clilen);

    return (lo_comm_ctrl.port_fd);
}

 /*
 *========================================================================
 *
 *   함 수 명 : sock_conn_port()
 *   작 성 자 : 오효섭 (catacath@nate.com)
 *   작 성 일 : 2012.10.04
 *   수 정 일 :
 *   설    명 : 해당 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((char const *)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 : azn_recv_data()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.08.24
 *   Modified :
 *   Remark   : TCP/IP READ
 *              차로에서 받은 데이타를 수신 하여 Buffering
 *
 *========================================================================
*/
int azn_recv_data()
{
    int  i;
    extern struct  ns_pkt_chng {
        int cmd;       /* command              */
        int (*func)(); /* low->high function   */
        int hi_size;   /* high packet size     */
        int lo_size;   /* low packet size      */
    } ns_pkt_chng[];

    if(rs_length < 3) return(0);

    for (i= 0; ns_pkt_chng[i].cmd != -1; i++)
    {
        if (ns_pkt_chng[i].cmd == rs_buffer[4]) break;
    }

    if (ns_pkt_chng[i].cmd == -1 || (rs_length > ns_pkt_chng[i].lo_size && rs_buffer[ns_pkt_chng[i].lo_size] != ETX)){
        lane_log("수신 [%02X] ETX size (%d) (%d) check Err.\n", 
                  rs_buffer[4],
                  ns_pkt_chng[i].lo_size,
                  rs_buffer[ns_pkt_chng[i].lo_size]);
#ifdef _TRACE_
        trace_high(rs_buffer, ns_pkt_chng[i].lo_size);
#endif
        return(-1);
    }

    if(rs_length > ns_pkt_chng[i].lo_size && ns_pkt_chng[i].cmd != -1){
        lo_comm_ctrl.rcv.psn = 1;
        lo_comm_ctrl.rcv.len = ns_pkt_chng[i].lo_size + 1; /* ETX(1 Byte Add) */
        memcpy(lo_comm_ctrl.rcv.buf, rs_buffer, lo_comm_ctrl.rcv.len);
    }

    if(lo_comm_ctrl.rcv.psn == 1){
        lo_comm_ctrl.rcv.psn = 0;
        rs_length -= lo_comm_ctrl.rcv.len;

        if(rs_length < 0) rs_length = 0;

        for (i=0; i<rs_length; i++){
            rs_buffer[i] = rs_buffer[i+lo_comm_ctrl.rcv.len];
        }
#ifdef _TRACE_
        trace_low(F_DATA, lo_comm_ctrl.rcv.len);
#endif
    }else lo_comm_ctrl.rcv.len = 0;

    return (lo_comm_ctrl.rcv.len);
}

/*
 *========================================================================
 *
 *   Function : sock_recv_data()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.08.24
 *   Modified :
 *   Remark   : TCP/IP READ
 *
 *========================================================================
*/
int sock_recv_data()
{
    int  i, retry = RETRY_COUNT;
    char sDate[15];

    do {
        r_length = recv(lo_comm_ctrl.port_fd, r_buffer, sizeof(r_buffer),0);
    }while(r_length < 0 && (errno == EAGAIN || errno == EINTR) && retry--);

    if (r_length < 0){
        lane_log("SOCK PROC(ERRNO %d)\n", errno);
        lo_comm_ctrl.rcv.err = errno;
        return (-1);
    }

    if(r_length == 0){
        lo_comm_ctrl.rcv.err = RE_FIN;
        lane_log("SOCK PROC(FIN)\n");
        return(-1);
    }

    lb_get_nowdate_tm(sDate);
    Packet("\n%s", sDate);

    /* 패킷 확인 */
    for(i=0; i<r_length; i++){
        if((i%50) == 0) Packet("\n");
        Packet("%02X", r_buffer[i]);
    }
    Packet("\n");

    if(r_length > 0){
          memcpy(&rs_buffer[rs_length],r_buffer,r_length);
          rs_length += r_length;
    }

    return (0);        /* on progressing */
}

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

    while (1){
        snd_dd = send(lo_comm_ctrl.port_fd, lo_comm_ctrl.snd.buf, lo_comm_ctrl.snd.len,0);
        if (snd_dd < 0){
               if((errno != EAGAIN && errno != EINTR) || !retry--) return (-1);
        }else break;
     }

    lb_get_nowdate_tm(sDate);
    Packet("\n%s", sDate);

    /* 패킷 확인 */
    for(i=0; i<snd_dd; i++){
        if((i%50) == 0) Packet("\n");
        Packet("%02X", lo_comm_ctrl.snd.buf[i]);
    }
    Packet("\n");
    
    lo_comm_ctrl.rcv.psn = 0;
#ifdef _TRACE_
    trace_low('W', lo_comm_ctrl.snd.buf[4], lo_comm_ctrl.snd.len-4);
#endif
    return (0);
}


 /*
 *========================================================================
 *
 *   함 수 명 : sock_close_port()
 *   작 성 자 : 오효섭 (catacath@nate.com)
 *   작 성 일 : 2012.10.04
 *   수 정 일 :
 *   설    명 : TCP/IP SHUTDOWN  port close
 *
 *========================================================================
*/
int sock_close_port()
{
    int     i ;

    if (lo_comm_ctrl.port_fd < 0) return (0);

    close(lo_comm_ctrl.port_fd);
/*
    if(conn_sock < 0) return (0);
    close(conn_sock);
*/
    /* 관리자 포트 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);
}
