/**
* @file CM_Socket.c
* @brief socket操作的封装
* @author GT-BU
* @date 2021.02.01
* @version V1.1
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2017.12.20  <td>V1.0     <td>MSCP项目组 <td>创建初始版本
* <tr><td>2021.02.01  <td>V1.1     <td>GT-BU      <td>TSCP项目集成、更新
* </table>
*/
#include "CM_Socket.h"
#include "CM_Memory.h"

/** socket服务初始化标志 */
static CM_BOOL s_Socket_Initialized = CM_FALSE;

/**
* @brief socket初始化
* @return 初始化结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
*/
ENUM_CM_RETURN CM_Socket_Init(void)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;/* 函数返回值 */
    /*- 是否已经初始化成功 */
    if (CM_TRUE == s_Socket_Initialized)
    {
        /*- 初始化结果置为成功 */
        rt = ENUM_CM_TRUE;
    }
    else
    {
#ifdef WIN32
        WSADATA wsa; /* 临时变量 */
        CM_INT32 ret = 1; /* 临时变量 */
        /*- 启动socket库 */
        CM_Memset(((void*)(&wsa)), (CM_UINT8)0U, ((size_t)(sizeof(wsa))), ((size_t)(sizeof(wsa))));
        ret = WSAStartup(MAKEWORD(2, 2), &wsa);
        /*- 是否启动成功 */
        if (0 == ret)
        {
            /*- 初始化成功 */
            s_Socket_Initialized = CM_TRUE;
            rt = ENUM_CM_TRUE;
        }

#else/*Linux Vxworks常用PIOX标准*/
        /*- 忽略SIGPIPE信号 */
        (void)signal(SIGPIPE, SIG_IGN);/*sigaction*/
        /*- 初始化成功 */
        s_Socket_Initialized = CM_TRUE;
        rt = ENUM_CM_TRUE;
#endif        
    }
    /*- 返回初始化结果 */
    return rt;
}

/**
* @brief 创建socket
* @param pSock socket指针
* @param isUDP 是否是UDP socket
* - CM_TRUE 是UDP socket
* - CM_FALSE 是TCP socket
* @return 创建结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
*/
ENUM_CM_RETURN CM_Socket_Create(INOUT CM_SOCKET* pSock, IN CM_BOOL isUDP)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;/* 函数返回值 */
#ifdef WIN32
    unsigned long dwBytesReturned = 0U;/* 临时变量 */
    CM_BOOL bNewBehavior = FALSE; /* 临时变量 */
    CM_INT32 status = 0; /* 临时变量 */
#endif
    /*- 是否尚未初始化socket或输入非法 */
    if ((CM_TRUE != s_Socket_Initialized) || (NULL == pSock))
    {
        /*- 创建失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 是否是创建UDP socket */
        if (CM_TRUE == isUDP)
        {
            /*- 创建UDP socket */
            *pSock = socket(AF_INET, SOCK_DGRAM, 0);
#ifdef WIN32
            status = WSAIoctl(*pSock, _WSAIOW(IOC_VENDOR, 12), &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);
            /*函数成功则返回0*/
            /*- @alias 检查是否创建成功 */
            if (0 != status)
            {
                *pSock = INVALID_SOCKET;
            }
#endif
        }
        else
        {
            /*- 创建 TCP socket */
            *pSock = socket(AF_INET, SOCK_STREAM, 0);
        }

#ifdef WIN32
        /*- @alias 检查创建是否成功 */
        if (INVALID_SOCKET == *pSock)
        {
            rt = ENUM_CM_FALSE;
        }
        else
        {
            rt = ENUM_CM_TRUE;
        }

#else/*Linux Vxworks常用PIOX标准*/
        /*- @alias 检查创建是否成功 */
        if (0 >= *pSock)
        {
            rt = ENUM_CM_FALSE;
        }
        else
        {
            rt = ENUM_CM_TRUE;
        }
#endif
    }
    /*- 返回socket创建结果 */
    return rt;
}

/**
* @brief 关闭socket
* @param pSock socket指针
* @return 关闭结果
* - ENUM_CM_TRUE 成功
* - ENUM_CM_FALSE 失败
*/
ENUM_CM_RETURN CM_Socket_Close(INOUT CM_SOCKET* pSock)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;  /* 函数返回值 */
    /*- socket是否未初始化或输入非法 */
    if ((CM_TRUE != s_Socket_Initialized) || (NULL == pSock))
    {
        /*- 关闭失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 关闭连接的读和写*/
        (void)shutdown(*pSock, 2);

        /*- @alias 关闭socket */
        if (0 != (CM_INT32)(*pSock))
        {
#ifdef WIN32
            closesocket(*pSock);
#else/*Linux Vxworks常用PIOX标准*/
            (void)close(*pSock);
#endif
            *pSock = 0;
        }
        else
		{
			/* 无处理 */
		}
        /*- 关闭成功 */
        rt = ENUM_CM_TRUE;
    }
    /*- 返回关闭结果 */
    return rt;
}

