/*
 KX High Capacity High Performance Epoll Socket Client Daemon Class
 ---------------------------------------------------------------------------
 $Id: $ $Revision: $
 $HeadURL: $
 Copyright(c) 1990 - 2018 KRKIM(DURUMUL) Allrights reserved.
 */

/**
 * @file
 * @brief 
 * @detail 
 */

/*
 * History:
 * ===========================================================================
 * 2018.09.30  KRKIM   Initialized.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>

#include <list>
#include <queue>
#include <vector>
#include <pthread.h>

#include "network.h"
#include "epollcomn.h"
#ifdef USE_INTERDBPOOL
#include "dbpool.h"
#endif

#include "kxHashMap.h"
#include "kxThread.h"
#include "iocq.h"
#include "tokenizer.h"

#include "kxSockSession.h"
#include "kxClientSession.h"
#include "kxtracelog.h"

using namespace std;

CKxClientSession::CKxClientSession() : CKxSockSession()
{
    m_hostname = NULL;
    m_bconnected = 0;
    m_threadno = -1;
    memset(&m_sockaddr,0,sizeof(sockaddr_in));//remote addr
}

CKxClientSession::~CKxClientSession()
{
    Destroy();
}

void CKxClientSession::SetPort(short port)
{
    m_nPort = port;
}

void CKxClientSession::SetHost(char *hostname)
{
    if (m_hostname)
        free(m_hostname);
    m_hostname = strdup(hostname);
}

char *CKxClientSession::GetHost()
{
    return m_hostname;
}

int CKxClientSession::GetPort()
{
    return m_nPort;
}

bool CKxClientSession::Init(char *hostname, int port, int conntimeout)
{
    SetHost(hostname);
    SetPort(port);

    m_conntimeout = conntimeout;
    return true;
}

bool CKxClientSession::InitSocket()
{
    int sockfd;
    struct hostent    *ph;
	struct sockaddr_in addr;

	/* Get port number of server.  */
	addr.sin_port = htons(m_nPort);

	/* Find internet address of host.  */
	if ((addr.sin_addr.s_addr = inet_addr(m_hostname)) != -1){  /* IP주소로 입력된 경우 */
		addr.sin_family = AF_INET;
	}
	else{
		if ((ph = gethostbyname(m_hostname)) == NULL){     /* Name으로 입력된 경우 */
			return -1;
		}
		else{
			addr.sin_family = ph->h_addrtype;
			memcpy((char *)&addr.sin_addr,ph->h_addr,ph->h_length);
		}
	}
    memcpy(&m_sockaddr,&addr,sizeof(m_sockaddr));
	/* open a socket.  */
	if ((sockfd = socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP*/)) < 0){
		return -1;
	}
    m_sockfd = sockfd;
	char *remoteaddr = inet_ntoa(m_sockaddr.sin_addr);
	strncpy(m_ip,remoteaddr,sizeof(m_ip));
    kxTraceLog(0, "[CKxClientSession] InitSocket:hostname=%s port=%d conntimeout=%d sockfd(%d)\n",
        m_hostname,m_nPort, m_conntimeout,sockfd);
    return true;
}

int CKxClientSession::Connect()
{
    int rc;
    int sockfd = m_sockfd;
    // ignore sigpipe signal for socket
    //signal (SIGPIPE, SIG_IGN);

	/* connect to host */
#if 1
	/* connect to the server */
    rc = connect(sockfd,(struct sockaddr *)&m_sockaddr,sizeof(struct sockaddr));
#else
    rc = tcp_connect_socktimeout(sockfd,
		(struct sockaddr_in*)&m_sockaddr,/*sizeof(addr),*/m_conntimeout);
#endif

    if (rc < 0)
    {
        //kxTraceLog(TL_HIGH,"tcp_connect() error. rc = %d host %s port %d m_sockfd(%d) errno %d(%s)\n",
        //rc,m_hostname,m_nPort,m_sockfd,errno,strerror(errno));
        //close(sockfd);
        return rc;
	}
    m_sockfd = sockfd;
    m_bconnected = 1;
    return 0;
}

bool CKxClientSession::IsConnected()
{
    return(m_bconnected == 1) ? true : false;
}

int CKxClientSession::senddata(const char *chatmsg, int len)
{
    int sendflags = 0;
	int sent;
	sent = send(GetSockFD(), chatmsg, len, sendflags);
    return sent;
}

int CKxClientSession::PostSendNow(char *pData, int nLen)
{
    int sendflags = 0;
	PostSend(pData, nLen);
	SendPacket();
	kxTraceLog(0, "PostSendNow\n");
    return 0;
}

/**
 *
 * @brief   해당 클라이언트소켓을 닫는다.
 * @details
 * @param   CKxSockSession pclient 클라이언트 소켓 클래스
 * @date    2018-09-09
 * @version 0.0.1
 * @return  0 -> 성공, -1 -> 실패
 * @todo
 */

int CKxClientSession::CloseClient()
{
    int clientfd;
    CKxSockSession *pclient = this;
    clientfd = pclient->GetSockFD();
    FreeSendContext();
    shutdown(clientfd, 2);
    close(clientfd);
    m_bconnected = 0;
    m_sockfd = INVALID_SOCKET;
    m_threadno = -1;
    return 0;
}
