/*	
 *	clipudp.h
 *
 *	UDPプロトコルドライバ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Wed Sep 07 03:55:00 JST 2005 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Sep 20 19:51:00 JST 2005 Naoyuki Sawa
 *	- udp_open()時にlocal_port=0ならば、エフェメラルポートを割り当てるよう変更しました。
 *	* Fri Sep 23 02:34:00 JST 2005 Naoyuki Sawa
 *	- udp_socket_open()の受信キュー容量を、少なくとも1480バイト以上に切り上げるよう変更しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_UDP_H__
#define __CLIP_UDP_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

/****************************************************************************
 *	UDPプロトコルドライバ
 ****************************************************************************/

typedef struct _UDPCLIENT UDPCLIENT;

/* UDPCLIENT.recv : 受信完了コールバックのプロトタイプ */
typedef void UDPRECV(UDPCLIENT* client,
	int remote_ip_address,			/* 送信元IPアドレス */
	int remote_port,			/* 送信元ポート */
	const unsigned char* data/*[length]*/,	/* UDPデータグラムのデータ部分 */
	int length);				/* UDPデータグラムのデータ長 */

/* クライアント登録用の構造体 */
/*typedef*/ struct _UDPCLIENT {

	/*------------------------------------------------------------------------------*
	 *	udp_open()を呼び出す前に、アプリケーションにて設定しておくフィールド。	*
	 *	udp_open()を呼び出した後は、変更してはいけない。			*
	 *------------------------------------------------------------------------------*/

	int local_port;		/* ローカルポート (省略可=0)
				 * 省略すると、自動的にエフェメラルポートを割り当てます。
				 */

	UDPRECV* recv;		/* 受信完了コールバック (NULL:無し) */

	/*------------------------------------------------------------------------------*
	 *	UDPプロトコルドライバが、内部で使用するフィールド。			*
	 *	アプリケーションは、以下のフィールドにアクセスしてはいけない。		*
	 *------------------------------------------------------------------------------*/

	LIST_ENTRY list_entry;	/* クライアントリスト */

} /*UDPCLIENT*/;

/*--------------------------------------------------------------------------*/

/* UDPプロトコルドライバを開始します。
 * [note]
 *	* udp_start()を呼び出したアプリケーションは、終了前に必ず、udp_stop()を呼び出してください。
 *	  udp_stop()を呼び出さずにアプリケーションを終了すると、P/ECEシステムが異常動作を起こします。
 *	* udp_open()を呼び出してクライアントを登録する前に、必ず、udp_start()を呼び出してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
void udp_start();

/* UDPプロトコルドライバを停止します。
 * [note]
 *	* udp_stop()は、常に安全に呼び出し可能です。
 *	  udp_start()を呼び出していなくても、いつでも、何回でも、udp_stop()を呼び出して構いません。
 *	* udp_stop()を呼び出すと、登録されているクライアントは、自動的にすべて登録解除されます。
 *	  udp_stop()を呼び出す前に、個々のクライアントを、明示的に登録解除する必要はありません。
 *	  また、udp_stop()を呼び出した後に、udp_close()を呼び出してはいけません。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
void udp_stop();

/* 特定のポートを処理する、クライアントを登録します。
 * [in]
 *	client			呼び出し側にて確保した、クライアント登録用の構造体。
 *				各フィールドを、あらかじめ適切に初期化しておいてください。
 * [note]
 *	* 同じポートを処理するクライアントを、同時に二つ以上登録しようとすると、エラー終了します。
 *	* クライアント登録用の構造体は、UDPプロトコルドライバ内部のリストにリンクされます。
 *	  udp_close()を呼び出して登録解除するまで、構造体を開放してはいけません。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	△　可能だが、推奨しない
 */
void udp_open(UDPCLIENT* client);

/* 登録済みクライアントを、登録解除します。
 * [in]
 *	client			登録済みクライアントの構造体。
 * [note]
 *	* 未登録のクライアントを登録解除しようとすると、エラー終了します。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	△　可能だが、推奨しない
 */
void udp_close(UDPCLIENT* client);

/* UDPデータグラムを送信します。
 * [in]
 *	client			登録済みクライアントの構造体、または、NULL。
 *				NULLを指定した場合、送信元ポート=0(無指定)で送信します。
 *	remote_ip_address	宛て先IPアドレス。
 *	remote_port		宛て先ポート。
 *	data			UDPデータグラムのデータ部分。(0バイト以上)
 *	length			UDPデータグラムのデータ長。  (0      以上)
 * [out]
 *	戻り値			成功ならば、データ長(length引数の値)をそのまま返します。(0、または、正数)
 *				送信キューがいっぱいで送信できない場合、負数を返します。
 * [note]
 *	* 0バイトのデータを送信することも可能です。(UDPヘッダだけで、データ部の無いパケット)
 *	  戻り値「0」は、成功を意味することに注意してください。
 *	* ブロッキング、ノンブロッキングの挙動については、ip_send()のコメントを参照してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	○
 */
int udp_send(UDPCLIENT* client, int remote_ip_address, int remote_port, const void* data/*[length]*/, int length);

/****************************************************************************
 *	UDPソケット
 ****************************************************************************/

/* UDPソケット構造体 */
typedef struct _UDPSOCKET {
	UDPCLIENT udp_client;	/* UDPクライアント登録用 */
	QUEUE* rxque;		/* 受信キュー */
} UDPSOCKET;

/*--------------------------------------------------------------------------*/

/* UDPソケットを開きます。
 * [in]
 *	local_port		ローカルポート。(省略可=0)
 *				省略すると、自動的にエフェメラルポートを割り当てます。
 *	rxque_capacity		受信キュー容量。
 *				rxque_capacityに1480未満が指定された場合、1480に切り上げて確保します。
 *				Ethernet環境における、UDPデータグラムの最大長は、1480バイトだからです。
 *				(ただしIPデータグラムをフラグメント化しない場合。UDPヘッダ8バイト含む。)
 *				    Ethernetﾌﾚｰﾑ(1514) - Ethernetﾍｯﾀﾞ(14) - IPﾍｯﾀﾞ(20) = 1480
 *				2005/09/23現在、IPデータグラムのフラグメント化に対応していないため、
 *				上述の仕様としましたが、今後の対応により、調整する可能性があります。
 * [out]
 *	戻り値			UDPソケット。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
UDPSOCKET* udp_socket_open(int local_port, int rxque_capacity);

/* UDPソケットを閉じます。
 * [in]
 *	udp_socket		UDPソケット。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
void udp_socket_close(UDPSOCKET* udp_socket);

/* 受信キューから、受信済みパケットのデータを取り出します。
 * [in]
 *	udp_socket		UDPソケット。
 *	remote_ip_address	成功時に、送信元IPアドレスを格納する変数へのポインタ。
 *				NULLならば、送信元IPアドレスを格納しません。
 *	remote_port		成功時に、送信元ポートを格納する変数へのポインタ。
 *				NULLならば、送信元ポートを格納しません。
 *	data			成功時に、受信データを格納するバッファへのポインタ。
 *	length			受信データを格納するバッファ容量。
 * [out]
 *	戻り値			成功ならば、実際に受信したデータ長を返します。(0、または、正数)
 *				受信キューが空、または、バッファ容量不足ならば、負数を返します。
 * [note]
 *	* 0バイトのデータを受信することも有り得ます。(UDPヘッダだけで、データ部の無いパケット)
 *	  戻り値「0」は、成功を意味することに注意してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
int udp_socket_recv(UDPSOCKET* udp_socket, int* remote_ip_address, int* remote_port, void* data/*[length]*/, int length);

/* データを送信します。
 * [in]
 *	udp_socket		UDPソケット。
 *				NULLを指定した場合、送信元ポート=0(無指定)で送信します。
 *	remote_ip_address	宛て先IPアドレス。
 *	remote_port		宛て先ポート。
 *	data			送信データ。
 *	length			送信データ長。
 * [out]
 *	戻り値			成功ならば、データ長(length引数の値)をそのまま返します。(0、または、正数)
 *				送信キューがいっぱいで送信できない場合、負数を返します。
 * [note]
 *	* 0バイトのデータを送信することも可能です。(UDPヘッダだけで、データ部の無いパケット)
 *	  戻り値「0」は、成功を意味することに注意してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
int udp_socket_send(UDPSOCKET* udp_socket, int remote_ip_address, int remote_port, const void* data/*[length]*/, int length);

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_UDP_H__*/
