/*!
	COverlappedSocket を入出力に使うBIO

	参考：bss_file.c, bss_sock.c
*/
#include "StdAfx.h"
#include "SSLOverlappedSocketBIO.h"

//!	COverlappedSocket型BIO
#define BIO_TYPE_OVR_SOCKET		(30 | 0x400)	//	BIO_TYPE_SOURCE_SINK

/*
	OpenSSL でのコールバック定義
	Win32では特別な定義は不要
*/
#ifndef MS_CALLBACK
	#define MS_CALLBACK
#endif

/*
	BIOのコールバック関数
*/
static int MS_CALLBACK	ovrs_write(BIO *h, const char *buf, int num);
static int MS_CALLBACK	ovrs_read(BIO *h, char *buf, int size);
static int MS_CALLBACK	ovrs_puts(BIO *h, const char *str);
static long MS_CALLBACK	ovrs_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int MS_CALLBACK	ovrs_new(BIO *h);
static int MS_CALLBACK	ovrs_free(BIO *data);

//!	BIOインタフェース取得
static BIO_METHOD *BIO_s_ovrs(void);


/*!
	BIO定義
*/
static BIO_METHOD methods_ovrs =
{
	BIO_TYPE_OVR_SOCKET,
	"COverlappedSocket",
	ovrs_write,
	ovrs_read,
	ovrs_puts,
	NULL, // ovr_gets,
	ovrs_ctrl,
	ovrs_new,
	ovrs_free,
	NULL,
};


/*!
	割り当て(唯一の公開関数)
*/
BIO *BIO_new_ovrs(COverlappedSocket *ovrs)
{
	if(ovrs == NULL)
		return(NULL);

	//	新規生成
	BIO *ret = BIO_new(BIO_s_ovrs());
	if(ret == NULL)
		return(NULL);

	//	設定
	ret->ptr = ovrs;
	ret->init = 1;
	return(ret);
}


/*!
	インタフェース取得
*/
static BIO_METHOD *BIO_s_ovrs(void)
{
	return(&methods_ovrs);
}


/*!
	初期化
*/
static int ovrs_new(BIO *bi)
{
	bi->init=0;
	bi->num=0;
	bi->ptr=NULL;
	bi->flags=0;
	return(1);
}

/*!
	開放
*/
static int ovrs_free(BIO *a)
{
	if (a == NULL)
		return(0);
	a->ptr=NULL;
	a->init=0;
	return(1);
}

/*!	
	読み込み
*/
static int ovrs_read(BIO *b, char *out, int outl)
{
	if(out != NULL)
	{
		//	ポインタ取得
		COverlappedSocket *ovrs = (COverlappedSocket*)b->ptr;

		//	操作実行
		return(ovrs->BlockingRecv(out, outl));
	}
	return(0);
}

/*!
	書き込み
*/
static int ovrs_write(BIO *b, const char *in, int inl)
{
	//	ポインタ取得
	COverlappedSocket *ovrs = (COverlappedSocket*)b->ptr;

	//	操作実行
	return(ovrs->BlockingSend(const_cast<char *>(in), inl));
}

/*!
	書き込み(文字列)
*/
static int ovrs_puts(BIO *bp, const char *str)
{
	return(ovrs_write(bp, str, strlen(str)));
}


/*!
	コントロール
*/
static long ovrs_ctrl(BIO *b, int cmd, long num, void *ptr)
{
	long ret=1;

	switch (cmd)
	{
	case BIO_CTRL_RESET:
		num=0;
	case BIO_C_FILE_SEEK:
		ret=0;
		break;

	case BIO_CTRL_DUP:
	case BIO_CTRL_FLUSH:
		ret=1;
		break;

	default:
		ret=0;
		break;
	}
	return(ret);
}
