
/*********************************************************************
*   < NETWORK_TCP_UDP.CPP >
**********************************************************************
*   TCP,UDP通信
**********************************************************************
*                                                   Copyright (C) 2005
*   Programed by Ochi
*********************************************************************/

#include "network.h"

/*********************************************************************
*   接続までの準備
**********************************************************************
*   引数　：無し
*   戻り値：結果(LRESULT)
*********************************************************************/
LRESULT CSocket::ConReady( void )
{
    nConnectType = NO_CONNECT;
    closesocket( srcSocket );
    WSACleanup();

    // Winsockを初期化
    if( WSAStartup(MAKEWORD(1,1), &wsaData) )
    {
        Message( "CSocket::Connect", "Winsockを初期化できません", 3 );
        return false;
    }

    // Socketを生成
    if( (srcSocket=socket(AF_INET,nProtocol,0))==INVALID_SOCKET )
    {
        Message( "CSocket::Connect", "ソケットを生成できません", 3 );
        return false;
    }

    // 相手のホスト情報を取得
    if( (lpHost = gethostbyname(szHost)) == NULL )
    {
        nIP = inet_addr(szHost);
        if( (lpHost=gethostbyaddr((char *)&nIP,sizeof(nIP),AF_INET))==NULL )
        {
            Message( "CSocket::Connect()", "以下の理由で接続できません\n\n"
                     "１．ネットワークに接続されていない\n"
                     "２．設定されているIPまたはホストが存在しない　　　\n" , 2 );
            return false;
        }
    }

    return true;
}

/*********************************************************************
*   切断する
**********************************************************************
*   引数　：無し
*   戻り値：結果(LRESULT)
*********************************************************************/
LRESULT CSocket::Close( void )
{
    nConnectType = NO_CONNECT;
    closesocket( srcSocket );
    WSACleanup();

    return true;
}

/*********************************************************************
*   接続する
**********************************************************************
*   引数　：無し
*   戻り値：結果(LRESULT)
*********************************************************************/
LRESULT CSocket::Connect ( void )
{
    char szBuf[RECV_UDP];

    ConReady();

    memset( &dstAddr, 0, sizeof(dstAddr) );
    memcpy( &(dstAddr.sin_addr), lpHost->h_addr, lpHost->h_length );
    dstAddr.sin_family = lpHost->h_addrtype;
    dstAddr.sin_port = htons( nPort );

    if ( connect(srcSocket,(struct sockaddr*)&dstAddr,sizeof(dstAddr)) == SOCKET_ERROR )
    {
        // クライアント接続ができなかった場合はサーバーとなり、相手からの接続を待つ
        SERVER:
        nConnectType = SERVER;

        // クライアントだったのでソケットを作り直す
        closesocket( srcSocket );
        WSACleanup();

        // Winsockを初期化
        if( WSAStartup(MAKEWORD(1,1), &wsaData) )
        {
            Message( "CSocket::Connect", "Winsockを初期化できません", 3 );
            return false;
        }

        // ソケットを生成
        if( (srcSocket=socket(AF_INET,nProtocol,0))==INVALID_SOCKET )
        {
            Message( "CSocket::Connect", "ソケットを生成できません", 3 );
            goto END_SOCKET;
        }

        memset( &dstAddr, 0, sizeof(dstAddr) );
        dstAddr.sin_family = AF_INET;
        dstAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        dstAddr.sin_port = htons(nPort);

        if( bind(srcSocket,(const struct sockaddr*)&dstAddr,sizeof(dstAddr))==SOCKET_ERROR )
        {
            Message( "CSocket::Connect()", "bind エラー", 2 );
            goto END_SOCKET;
        }

        client_len = sizeof( dstAddr );
        strcpy( szBuf, ReceiveMessage() );
        if( !strcmp("can you communicate?", szBuf) )
        {
            strcpy( szBuf,"i can communicate.");
            if ( SendMessage(szBuf)!=false )
            {
                return true;
            }
            else
            {
                Message("CSocket::Connect", "send に失敗しました。", 2 );
                goto END_SOCKET;
            }
        }
    }

    // クライアントとして接続できたら
    // 相手と同じアプリケーションで通信しているかを確認する
    nConnectType = CLIENT;
    strcpy(szBuf,"can you communicate?");
    if( SendMessage("can you communicate?")==false )
    {
        goto SERVER;
    }

    strcpy( szBuf, ReceiveMessage() );
    if( !strcmp(szBuf, "i can communicate.") )
    {
        return true;
    }
    else
    {
        goto SERVER;
    }

END_SOCKET:
    nConnectType = NO_CONNECT;
    closesocket( srcSocket );
    WSACleanup();

    return false;
}

/*********************************************************************
*   受信する
**********************************************************************
*   引数　：無し
*   戻り値：受信したメッセージ(char*)
*********************************************************************/
char* CSocket::ReceiveMessage( void )
{
    char szMessage[RECV_UDP];

    switch( nConnectType )
    {
    case SERVER:
        if( nProtocol==SOCK_STREAM )
        {
            if( recv(srcSocket,szMessage,sizeof(szMessage),0) == SOCKET_ERROR )
            {
                strcpy(szMessage, "");
            }
        }
        else {
            if( recvfrom(srcSocket,szMessage,sizeof(szMessage),0,(struct sockaddr *)&dstAddr, &client_len) == SOCKET_ERROR )
            {
                strcpy( szMessage, "" );
            }
        }
        break;

    case CLIENT:
        if( recv(srcSocket,szMessage,sizeof(szMessage),0)==SOCKET_ERROR )
        {
            strcpy( szMessage, "" );
        }
        break;

    case NO_CONNECT:
        strcpy( szMessage, "" );
        break;

    default:
        strcpy( szMessage, "" );
        break;
    }

    char* pszReturn = szMessage;
    return pszReturn;
}

/*********************************************************************
*   メソッドを渡す
**********************************************************************
*   引数　：メソッドの種類
*   戻り値：要求されたメソッド
*********************************************************************/
LRESULT CSocket::ReturnObject( LRESULT ObjectType )
{
    switch( ObjectType )
    {
    case CONNECT_TYPE:
        return nConnectType;
        break;

    default:
        break;
    }

    return false;
}

/*********************************************************************
*   送信する
**********************************************************************
*   引数　：送信する文字列(const char*)
*   戻り値：結果(LRESULT)
*********************************************************************/
LRESULT CSocket::SendMessage( const char* pszMessage )
{
    switch( nConnectType )
    {
    case SERVER:
        if( nProtocol==SOCK_STREAM )
        {
            if( send(srcSocket, pszMessage, strlen(pszMessage)+1, 0)==SOCKET_ERROR )
            {
                return false;
            }
        }
        else {
            if( sendto(srcSocket, pszMessage, strlen(pszMessage)+1,0,(struct sockaddr *)&dstAddr, client_len)==SOCKET_ERROR )
            {
                return false;
            }
        }
        break;

    case CLIENT:
        if( send(srcSocket, pszMessage, strlen(pszMessage)+1, 0) ==SOCKET_ERROR )
        {
            return false;
        }
        break;

    case NO_CONNECT:
        Message("CSocket::SendMessage", "メッセージが送信できませんでした", 2 );
        return false;
        break;

    default:
        break;
    }

    return true;
}

/*********************************************************************
*   接続のための設定
**********************************************************************
*   引数　：ホスト名(char*), ポート番号(UINT), プロトコル(UINT)
*   　　　　タイムアウト(UINT)
*   戻り値：結果(LRESULT)
*********************************************************************/
LRESULT CSocket::Setting( char* HOST, UINT PORT, UINT PROTOCOL, UINT TIMEOUT )
{
    strcpy( szHost, HOST );
    nPort = PORT;
    nProtocol = PROTOCOL;
    nTimeOut = TIMEOUT;

    return true;
}
