/* $Id: main.c 258 2010-12-14 04:35:42Z qin $ */
/* $ID: main.c,v 1.64 2008/03/06 01:18:51 miyazawa Exp $ */

/*
* Copyright (C) 2004 WIDE Project.
* All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <unistd.h>
 #include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include<pthread.h>
#include <netinet/in.h>
#include "tcp_sock.h"

/*******************************************************************************
* 1.NAME         : iked_RecvMesg()
* 2.DESCRIPTION  :
* 3.PARAMETER    : (IN)  fd      : socket fd
*                  (OUT) message : メッセージ
* 4.RETURN VALUE : -1       メッセージ取得失敗(ERR)
*                : -2       メッセージ取得失敗(timeout)
*                : 0        メッセージ取得失敗(ソケット切断)
*                : >0       メッセージの長さ(ヘッダーと内容)
* 5.NOTE         :
*     本関数を呼んで正常の時, メッセージの領域は呼ぶ方から解放する
*******************************************************************************/
int recv_mesg( int fd, char **message )
{
    int ret;
    char *buf;
    int receive_size;
     char   msg_buf[4012];

        // メッセージのヘッダーを取得
	ret=wait_io(fd,0);
	if ( 0 > ret ) {
		return ret;
	}
	ret = recv( fd, msg_buf, sizeof( msg_buf ) , MSG_DONTWAIT );
	if ( 0 > ret )
	{

	    // 受信ERR
	    GDB_PRINTF( "failed to get  message head(fd=%d, errno=%d ).\n", fd, errno );
	    return ret;
	}
	else if ( 0 == ret )
	{
	    // ソケット切断
	    GDB_PRINTF( "connection closed by client (fd=%d, errno=%d ).\n", fd, errno );
	    return ret;
	}

	receive_size=ret;

    buf = (char *)calloc( receive_size+1,sizeof(char) );
    if( NULL == buf )
    {
        GDB_PRINTF(  "failed to get memory space(errno=%d ).\n",errno);
        return (-1);
    }
    *message = buf;
    memcpy( buf, msg_buf, receive_size );
    
    return receive_size;
}
/*******************************************************************************
* 1.NAME         : iked_SendMesg()
* 2.DESCRIPTION  :
* 3.PARAMETER    : (IN)  fd      : socket fd
*                  (IN) message : メッセージ
* 4.RETURN VALUE : -1       メッセージ送信(ERR)
*                : 0        メッセージ送信失敗(ソケット切断)
* 5.NOTE         :
*      本関数をよんでデーターを送信する時
*******************************************************************************/
int send_mesg( int fd, char *ctx )
{
    int ret;
    int send_size;
    int finished_size;
    struct  ike_msg_head * msg_head=NULL;

    // 送信待ち
    ret=wait_io(fd,1);
    if ( 0 > ret )
    {
        return( ret );
    }

    // 送信
    msg_head = (struct  ike_msg_head *)ctx;
    finished_size=0;
    for ( send_size = strlen(ctx) ; ; )
    {
        ret = send( fd, ((char *)ctx)+finished_size, send_size ,MSG_DONTWAIT);
        if ( 0 > ret )
        {
            if ( EINTR == errno )
            {
                continue;
            }

            GDB_PRINTF(  "failed to send message(fd=%d, errno=%d ).\n", fd, errno );
            return ret;
        }

        finished_size += ret;
        send_size -= ret;

        if ( send_size <= 0 )
        {
            break;
        }

        // 送信待ち
        ret=wait_io(fd,1);
        if ( 0 > ret )
        {
            return( ret );
        }
    }

    return 0;
}
/*******************************************************************************
* 1.NAME         : iked_WaitRecv()
* 2.DESCRIPTION  :
* 3.PARAMETER    : (IN)  fd      : socket fd
* 4.RETURN VALUE : -1       select失敗(ERR)
*                : -2       select失敗(timeout)
*                : 0        select OK
* 5.NOTE         :
*         select関数により、受信データを待つ。
*******************************************************************************/
int wait_io( int fd, int flg )
{
    int     ret;
/*
   time_t timer;
    char buffer[26];
    struct tm* tm_info;
*/

	
    fd_set  fd_mask;                      // ソケットビットマスク
    struct  timeval tim;                    // タイマ構造体

    tim.tv_sec = 5;                         // タイムアウト時間SET(秒)
    tim.tv_usec = 0;                        // タイムアウト時間SET(マイクロ秒)

    // ビットマスク初期設定
    FD_ZERO( &fd_mask );
    FD_SET( fd, &fd_mask );

	/*
    time(&timer);
    tm_info = localtime(&timer);
    strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
    puts(buffer);
    */
    // select待ち(タイマ)
	if ( 0 ==flg ){
		ret = select( fd + 1, &fd_mask, NULL, NULL, &tim );
	}else{
		ret = select( fd + 1, NULL, &fd_mask, NULL, &tim );
	}
    if ( 0 > ret )
    {
        // select ERROR
        GDB_PRINTF(  "failed to select for receive(fd=%d, errno=%d ).\n", fd, errno );
        return( -1 );
    }
    else if ( 0 == ret )
    {
        // timeout
        GDB_PRINTF( "timeout to select for receive(fd=%d, errno=%d ).\n", fd, errno );
    }
    else
    {
        // normal
        if ( FD_ISSET(fd, &fd_mask) )
        {
            return( 0 );
        }
    }

    // timeout
    return( -2 );
}


int set_nonblocking(int sockfd)
{
  int val;
  val = fcntl(sockfd, F_GETFL, 0); 
  fcntl(sockfd, F_SETFL, val | O_NONBLOCK);
  return 0;
}

int set_blocking(int sockfd)
{
  int val;
  val = fcntl(sockfd, F_GETFL, 0);
  val = val & ~(val & O_NONBLOCK);
  fcntl(sockfd, F_SETFL, val);
  return 0;
}
