/*	
 *	cliptcp.h
 *
 *	TCPプロトコルドライバ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Tue Sep 20 04:34:00 JST 2005 Naoyuki Sawa
 *	- 1st リリース。
 *	* Fri Sep 23 15:29:00 JST 2005 Naoyuki Sawa
 *	- tcp_socket_state()を追加しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_TCP_H__
#define __CLIP_TCP_H__

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

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

/*--------------------------------------------------------------------------*
 |                                                                          |
 |                       TCPプロトコル状態遷移図                            |
 |                                                                          |
 |   (参考資料です。本ドライバはこのとおりの実装でなく、簡略化しています)   |
 |                                                                          |
 |                            +------------+                                |
 |                            |            | <----------------------+       |
 |                            |   CLOSED   |               A        |       |
 |                            |            | -----------+  |        |       |
 |                            +------------+ ACTIVE OPEN|  |        |       |
 |                     PASSIVE OPEN|  A      -----------|  |        |       |
 |                                 |  |        SYN送信  |  |        |       |
 |                                 V  |CLOSE            |  |        |       |
 |                            +------------+            |  |        |       |
 |                            |            |            |  |        |       |
 |             +------------> |   LISTEN   |            |  |        |       |
 |             |              |            |            |  |        |       |
 |             |              +------------+            |  |        |       |
 |             |          SYN受信  |  | 送信            |  |        |       |
 |             |        -----------|  |-------          |  | CLOSE  |       |
 |             |        SYN･ACK送信|  |SYN送信          |  |------- |       |
 |             |RST受信            |  |                 V  |RST送信 |       |
 |       +------------+ <----------+  +----------> +------------+   |       |
 |       |            |                    SYN受信 |            |   |       |
 |       |SYN-RECEIVED| <------------------------- |  SYN-SENT  |   |       |
 |       |            |                    ACK送信 |            |   |       |
 |       +------------+ -----------+  +----------- +------------+   |       |
 |             | CLOSE  ACK受信    |  |SYN･ACK受信                  |       |
 |             |-------  ofSYN     |  |-----------                  |       |
 |             |FIN送信            |  |  ACK送信                    |       |
 |             |                   V  V                             |       |
 |             |              +------------+                        |       |
 |             |              |            |                        |       |
 |             |              |ESTABLISHED |                        |       |
 |             |              |            |                        |       |
 |             |              +------------+                        |       |
 |             |             CLOSE |  |FIN受信                      |       |
 |             |            -------|  |-------                      |       |
 |             V            FIN送信|  |ACK送信                      |       |
 |       +------------+            |  |            +------------+   |       |
 |       |            | <----------+  +----------> |            |   |       |
 |       | FIN-WAIT-1 |                            | CLOSE-WAIT |   |       |
 |       |            | -----------+               |            |   |       |
 |       +------------+ FIN受信    |               +------------+   |       |
 |             |ACK受信 -------    |                CLOSE |         |       |
 |             | ofFIN  ACK送信    |               -------|         |       |
 |             V                   V               FIN送信V         |       |
 |       +------------+       +------------+       +------------+   |       |
 |       |            |       |            |       |            |   |       |
 |       | FIN-WAIT-2 |       |  CLOSING   |       |  LAST-ACK  |   |       |
 |       |            |       |            |       |            |   |       |
 |       +------------+       +------------+       +------------+   |       |
 |             |FIN受信     ACK受信|               ACK受信|         |       |
 |             |-------      ofFIN |                ofFIN |         |       |
 |             |ACK送信            V                      |         |       |
 |             |              +------------+ TIMEOUT      |         |       |
 |             |              |            |  =2MSL       V         |       |
 |             +------------> | TIME-WAIT  | -----------------------+       |
 |                            |            |                                |
 |                            +------------+                                |
 |                                                                          |
 *--------------------------------------------------------------------------*/

typedef struct _TCPCLIENT TCPCLIENT;

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

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

	/* ActiveOpen、PassiveOpenいずれの場合も、local_portを指定、または、指定しないことが可能です。
	 * local_portを指定しなければ(0を設定)、tcp_open()が自動的にエフェメラルポートを割り当てます。
	 */
	int local_port;				/* ローカルポート */

	/* ActiveOpen の場合は、remote_ip_addressの指定必須です。(0以外を設定)
	 * PassiveOpenの場合は、remote_ip_addressを指定すると、特定のアドレスからの接続だけを受け付けます。
	 *                      remote_ip_addressを指定しなければ、任意のアドレスからの接続を受け付けます。
	 */
	int remote_ip_address;			/* リモートIPアドレス */

	/* ActiveOpen の場合は、remote_portの指定必須です。(0以外を設定)
	 * PassiveOpenの場合は、remote_portを指定すると、特定のポートからの接続だけを受け付けます。
	 *                      remote_portを指定しなければ、任意のポートからの接続を受け付けます。
	 */
	int remote_port;			/* リモートポート */

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

	int state;				/* 状態 */

	int recv_sequence_number;		/* 受信シーケンス番号 */
	int send_sequence_number;		/* 送信シーケンス番号 */
	int send_window;			/* 送信ウインドウ */

	BUFFER* recv_buffer;			/* 受信バッファ */
	BUFFER* send_buffer;			/* 送信バッファ */

	int T0;					/* 再送判断の基準時刻 */

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

} /*TCPCLIENT*/;

/* TCPCLIENT.state */
#define TCP_LISTEN        0 /* 任意のリモートTCPおよびリモートポートからのコネクション要求を待っていることを表している。 */
#define TCP_SYN_SENT      1 /* コネクション要求を送信した後、それに対応するコネクション要求を待っていることを表している。 */
#define TCP_SYN_RECEIVED  2 /* コネクション要求の受信と送信の両方を行った後、コネクション要求の確認応答による承認を待っていることを表している。 */
#define TCP_ESTABLISHED   3 /* オープンコネクションを表しており、受信したデータはユーザに渡せる。コネクションのデータ転送フェーズにおける通常の状態である。 */
#define TCP_FIN_WAIT_1    4 /* リモートTCPからのコネクション終了要求、あるいは以前に送信したコネクション終了要求の確認応答を待っていることを表している。 */
#define TCP_FIN_WAIT_2    5 /* リモートTCPからのコネクション終了要求を待っていることを表している。 */
#define TCP_CLOSE_WAIT    6 /* ローカルユーザからのコネクション終了要求を待っていることを表している。 */
#define TCP_CLOSING       7 /* リモートTCPからのコネクション終了要求の確認応答を待っていることを表している。 */
#define TCP_LAST_ACK      8 /* すでにリモートTCPへ送信したコネクション終了要求の確認応答を待っていることを表している。(これはリモートTCPのコネクション終了要求の確認応答を含む) */
#define TCP_TIME_WAIT     9 /* リモートTCPがコネクション終了要求の確認応答を受信していると確信できるだけの時間を待っていることを表している。 */
#define TCP_CLOSED       10 /* 全くコネクションがない状態を表している。 */

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

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

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

/* TCP接続を起動します。
 * [in]
 *	client		呼び出し側にて確保した、クライアント登録用の構造体。
 *			各フィールドを、あらかじめ適切に初期化しておいてください。
 *	active		PassiveOpenならば、0を指定してください。
 *			ActiveOpen ならば、1を指定してください。
 * [note]
 *	* tcp_open()は、接続処理を起動後、ただちに処理を返します。
 *	  ActiveOpen、PassiveOpen、いずれの場合も、接続処理はバックグラウンドで行われます。
 *	* クライアント登録用の構造体は、TCPプロトコルドライバ内部のリストにリンクされます。
 *	  tcp_close()を呼び出して登録解除するまで、構造体を開放してはいけません。
 * [interrupt]
 *	通常処理	割り込み許可状態での呼び出し	○
 *	通常処理	割り込み禁止状態での呼び出し	○
 *	割り込み処理	割り込み禁止状態での呼び出し	△　可能だが、推奨しない
 */
void tcp_open(TCPCLIENT* client, int active);

/* TCP接続を終了します。
 * [in]
 *	client		登録済みクライアントの構造体。
 *	timeout		切断待ちタイムアウト[ms]。
 *			負数が指定されたら、既定値を使います。(2005/09/19現在、1秒です)
 *			タイムアウト前にCLOSED状態となった場合、ただちに処理を返します。
 * [note]
 *	* 未登録のクライアントを登録解除しようとすると、エラー終了します。
 * [interrupt]
 *	通常処理	割り込み許可状態での呼び出し	○
 *	通常処理	割り込み禁止状態での呼び出し	×
 *	割り込み処理	割り込み禁止状態での呼び出し	×
 */
void tcp_close(TCPCLIENT* client, int timeout);

/* データを受信します。
 * [in]
 *	client		登録済みクライアントの構造体。
 *	data		データを格納するバッファの先頭アドレス。
 *	maxlength	バッファの許容量。
 * [out]
 *	戻り値		受信バッファにデータが有れば、データを格納し、データ長を返します。(正数)
 *			受信バッファにデータが無く、受信可能、または、接続待ち状態ならば、0を返します。
 *			受信バッファにデータが無く、受信終了状態ならば、負数を返します。
 * [interrupt]
 *	通常処理	割り込み許可状態での呼び出し	○
 *	通常処理	割り込み禁止状態での呼び出し	○
 *	割り込み処理	割り込み禁止状態での呼び出し	○
 */
int tcp_recv(TCPCLIENT* client, void* data/*[maxlength]*/, int maxlength);

/* データを送信します。
 * [in]
 *	client		登録済みクライアントの構造体。
 *	data		送信するデータの先頭アドレス。
 *	length		データ長。
 * [out]
 *	戻り値		送信可能状態ならば、実際に送信したデータ長を返します。(0、または、正数)
 *			接続待ち状態ならば、0を返します。
 *			送信終了状態ならば、負数を返します。
 * [interrupt]
 *	通常処理	割り込み許可状態での呼び出し	○
 *	通常処理	割り込み禁止状態での呼び出し	○
 *	割り込み処理	割り込み禁止状態での呼び出し	○
 */
int tcp_send(TCPCLIENT* client, const void* data/*[length]*/, int length);

/****************************************************************************
 *	TCPソケット
 ****************************************************************************/

/* TCPソケット構造体 */
typedef struct _TCPSOCKET {
	TCPCLIENT tcp_client;	/* TCPクライアント登録用 */
} TCPSOCKET;

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

/* TCPソケットを開きます。
 * [in]
 *	local_port		ローカルポート。
 *				ActiveOpen の場合: 指定、または、省略(0)可能です。通常は、省略します。
 *				PassiveOpenの場合: 指定、または、省略(0)可能です。通常は、指定します。
 *				いずれの場合も、省略すると、自動的にエフェメラルポートを割り当てます。
 *	remote_ip_address	リモートIPアドレス。
 *				ActiveOpen の場合: 指定必須です。
 *				PassiveOpenの場合: 指定、または、省略(0)可能です。通常は、省略します。
 *				                   指定すると、特定のリモートIPアドレスからの接続を受け入れます。
 *				                   省略すると、任意のリモートIPアドレスからの接続を受け入れます。
 *	remote_port		リモートポート。
 *				ActiveOpen の場合: 指定必須です。
 *				PassiveOpenの場合: 指定、または、省略(0)可能です。通常は、省略します。
 *				                   指定すると、特定のリモートポートからの接続を受け入れます。
 *				                   省略すると、任意のリモートポートからの接続を受け入れます。
 *	active			PassiveOpenならば、0を指定してください。
 *				ActiveOpen ならば、1を指定してください。
 * [out]
 *	戻り値			TCPソケット。
 * [note]
 *	* 一般的な、ActiveOpenの呼び出しは、次のようになります。
 *		tcp_socket = tcp_socket_open(0, IP_ADDRESS(192,168,1,1), 80, 1); // 192.168.1.1:80へ接続
 *	* 一般的な、PassiveOpenの呼び出しは、次のようになります。
 *		tcp_socket = tcp_socket_open(80, 0, 0, 0); // ポート番号80で任意のリモート接続を待ち受け
 *	* この関数は、常に成功します。
 *	  接続処理は、バックグラウンドで進行します。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
TCPSOCKET* tcp_socket_open(int local_port, int remote_ip_address, int remote_port, int active);

/* TCPソケットを閉じます。
 * [in]
 *	tcp_socket		TCPソケット。
 *	timeout			切断待ちタイムアウト[ms]。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	×
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
void tcp_socket_close(TCPSOCKET* tcp_socket, int timeout);

/* TCPソケットから、データを読み出します。
 * [in]
 *	tcp_socket		TCPソケット。
 *	data			データを格納するバッファの先頭アドレス。
 *	maxlength		バッファの許容量。
 * [out]
 *	戻り値			tcp_recv()を参照してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
int tcp_socket_recv(TCPSOCKET* tcp_socket, void* data/*[maxlength]*/, int maxlength);

/* TCPソケットへ、データを書き込みます。
 * [in]
 *	tcp_socket		TCPソケット。
 *	data			送信するデータの先頭アドレス。
 *	length			データ長。
 * [out]
 *	戻り値			tcp_send()を参照してください。
 * [interrupt]
 *	通常処理		割り込み許可状態での呼び出し	○
 *	通常処理		割り込み禁止状態での呼び出し	○
 *	割り込み処理		割り込み禁止状態での呼び出し	×
 */
int tcp_socket_send(TCPSOCKET* tcp_socket, const void* data/*[length]*/, int length);

/* TCPソケットの状態を取得します。
 * [in]
 *	tcp_socket		TCPソケット。
 * [out]
 *	戻り値			状態。
 * [note]
 *	* TCP情報のうち、状態を参照する機会が多いと考え、プログラムの読み易さのために、本関数を用意しました。
 *	  それ以外のTCP情報、ローカルポート、リモートIPアドレス、リモートポートなどは、直接参照してください。
 */
static inline int tcp_socket_state(TCPSOCKET* tcp_socket) { return tcp_socket->tcp_client.state; }

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

#endif /*__CLIP_TCP_H__*/
