Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of libMiMic by
core/uip/NyLPC_cTcpSocket.cpp
- Committer:
- nyatla
- Date:
- 2013-03-27
- Revision:
- 2:b96c1e90d120
- Parent:
- 1:9f6a78395432
File content as of revision 2:b96c1e90d120:
/*********************************************************************************
* PROJECT: MiMic
* --------------------------------------------------------------------------------
*
* This file is part of MiMic
* Copyright (C)2011 Ryo Iizuka
*
* MiMic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* For further information please contact.
* http://nyatla.jp/
* <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
*
*********************************************************************************/
#include "NyLPC_cTcpSocket_protected.h"
#include "NyLPC_stdlib.h"
#include "NyLPC_cUipService_protected.h"
static NyLPC_TUInt32 iss32=3939;
#define SIZE_OF_IPv4_TCPIP_HEADER 40
/**
* for Debug
* RTOの情報をログ領域に取る。
*/
#ifdef RTO_LOG
NyLPC_TUInt32 rto_log[256];
int rto_log_st=0;
#define DEBUG_RTO_LOG(i_inst) if(rto_log_st<256){rto_log[rto_log_st++]=i_inst->uip_connr.current_rto32;};
#else
#define DEBUG_RTO_LOG(i_inst)
#endif
static void sendRst(NyLPC_TcTcpSocket_t* i_inst);
/**
* ソケットステータスを元に、IPパケットを構成します。
* この関数は、ロック状態でコールしてください。
*/
static void setPacket(const NyLPC_TcTcpSocket_t* i_inst,NyLPC_TcIPv4Payload_t* i_payload,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len)
{
void* buf;
switch(i_tcpf){
case TCP_PSH|TCP_ACK:
buf=NyLPC_cIPv4Payload_initTcpTx(i_payload,0x05,((UIP_TCPH_LEN) / 4),i_len);
NyLPC_cIPv4Payload_setTcpTxHeaderByConnection(i_payload,&(i_inst->uip_connr),TCP_ACK|TCP_PSH);
//bufの書き込み
memcpy(buf,i_buf,i_len);
break;
case TCP_ACK:
case TCP_FIN|TCP_ACK:
case TCP_RST|TCP_ACK:
NyLPC_cIPv4Payload_initTcpTx(i_payload,0x05,((UIP_TCPH_LEN) / 4),0);
NyLPC_cIPv4Payload_setTcpTxHeaderByConnection(i_payload,&(i_inst->uip_connr),i_tcpf);
break;
case TCP_SYN|TCP_ACK:
NyLPC_cIPv4Payload_initTcpTx(i_payload,0x05,((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4),0);
NyLPC_cIPv4Payload_setTcpTxHeaderByConnection(i_payload,&(i_inst->uip_connr),i_tcpf);
//MSSの設定(OPTION領域のアドレス0)
NyLPC_TTcpHeader_setMmsOpt((NyLPC_TUInt8*)(i_payload->payload.tcp+1),i_inst->uip_connr.default_mss);
break;
case TCP_SYN:
NyLPC_cIPv4Payload_initTcpTx(i_payload,0x05,((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4),0);
NyLPC_cIPv4Payload_setTcpTxHeaderByConnection(i_payload,&(i_inst->uip_connr),i_tcpf);
//MSSの設定(OPTION領域のアドレス0)
NyLPC_TTcpHeader_setMmsOpt((NyLPC_TUInt8*)(i_payload->payload.tcp+1),i_inst->uip_connr.default_mss);
break;
default:
NyLPC_Abort();
}
NyLPC_cIPv4Payload_setTcpWnd(i_payload,NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
NyLPC_cIPv4Payload_closeTcpTxPacket(i_payload);
return;
}
/**
* 指定した送信パケットがACK済であるか調べる。
*/
static NyLPC_TBool isPacketAcked(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
{
int rp;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
rp=i_inst->txbuf.rp;
while(rp!=i_inst->txbuf.wp){
if(q[rp].ackno==i_sq){
return NyLPC_TBool_FALSE;
}
rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
}
return NyLPC_TBool_TRUE;
}
/**
* 送信キューからi_sq以前に送信したパケットを除外して、残り個数を返却する。
*/
static int getNumOfSending(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
{
int rp,n;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
rp=i_inst->txbuf.rp;
n=0;
while(rp!=i_inst->txbuf.wp){
if(q[rp].ackno==i_sq){
return n;
}
n++;
rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
}
return n;
}
/**
* この関数は、コネクションをリセットします。
* ロック状態でコールしてください。
* 関数は、現在バッファにある再送信待ちデータを開放します。
*/
static void resetTxQWithUnlock(NyLPC_TcTcpSocket_t* i_inst)
{
int i,l;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
l=0;
while(i_inst->txbuf.rp!=i_inst->txbuf.wp){
dlist[l]=NyLPC_cIPv4Payload_detachBuf(&(q[i_inst->txbuf.rp].data));
l++;
i_inst->txbuf.rp=(i_inst->txbuf.rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
}
i_inst->txbuf.rp=i_inst->txbuf.wp=0;
//ロック解除
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//セーブしたバッファを開放
for(i=0;i<l;i++){
NyLPC_cUipService_releaseTxBuf(dlist[i]);
}
return;
}
/**
* TXバッファの再送パケットのACK番号を更新します。
* ロックして実行してください。
* @param i_ackno
* ネットワークオーダーのACK番号
*/
static void updateTxAck(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_ackno)
{
NyLPC_TUInt8 rp;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
NyLPC_ArgAssert(i_inst!=NULL);
rp=i_inst->txbuf.rp;
while(rp!=i_inst->txbuf.wp){
NyLPC_cIPv4Payload_updateAckNo(&(q[rp].data),i_ackno);
rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
}
}
/**
* RTOの予測関数
*/
static void estimateRTO(NyLPC_TcTcpSocket_t* i_inst,int s,int n)
{
NyLPC_TcStopwatch_t sw;
NyLPC_TUInt32 cr_rtt_min,cr_rtt_max,sk_rto,new_rto,w;
int i;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
NyLPC_cStopwatch_initialize(&sw);
sk_rto=i_inst->uip_connr.current_rto32;
//ACKされたパケットの個数は?
switch(n){
case 1:
NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
cr_rtt_min=NyLPC_cStopwatch_elapseInMsec(&sw);
if(sk_rto<cr_rtt_min){
//現在のRTOよりも大きい→再送があった。(再送の理由が回線遅延によるものかわからないので、基本RTOを25%増やす。)
new_rto=sk_rto*10/8;
}else if(sk_rto/4<cr_rtt_min){
//現在のRTOの1/4< n < 現在のRTO 想定内の変動。1/8
new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
}else{
//現在の1/4以下。RTOを再計算。 RTOが大きすぎるので再計算。(計測値を優先した現在値との平均値)
new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
}
break;
default:
//複数のパケットなら、最大と最小の時刻を得る。
NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
cr_rtt_min=cr_rtt_max=NyLPC_cStopwatch_elapseInMsec(&sw);
for(i=1;i<n;i++){
NyLPC_cStopwatch_set(&sw,q[(s+i)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ].tick_of_sent);
w=NyLPC_cStopwatch_elapseInMsec(&sw);
if(cr_rtt_min>w){
cr_rtt_min=w;
}
if(cr_rtt_max<w){
cr_rtt_max=w;
}
}
if(sk_rto<cr_rtt_min && sk_rto<cr_rtt_max){
//最大値,最小値とも現在のRTTより大きい→低速な回線を検出。
new_rto=cr_rtt_max*10/8;//最大経過時間の25%増しの時間を設定。
}else if(sk_rto/4<cr_rtt_min){
//現在のRTOの1/4< n < 現在のRTO 想定範囲内。1/8の加重平均で速度計算。
new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
}else{
//現在の1/4以下。RTOが大きすぎるので再計算。(計測値を優先した加重平均)
new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
}
break;
}
NyLPC_cStopwatch_finalize(&sw);
if(new_rto<UIP_IP_RTO_MINIMUM){
new_rto=UIP_IP_RTO_MINIMUM;
}
i_inst->uip_connr.current_rto32=new_rto;
}
/**
* TXキューから、入力されたシーケンス番号より前のパケットを除外します。
* リングバッファのrp->wp-1までをチェックして、sqに等しいi_sq以前のパケットバッファをo_dlistへ返します。
*
*/
static int updateTxQByIndex(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,void* o_dlist[])
{
int rp,n;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
//ロック状態なう
rp=i_inst->txbuf.rp;
n=0;
//This is debug
DEBUG_RTO_LOG(i_inst);
while(rp!=i_inst->txbuf.wp){
o_dlist[n]=NyLPC_cIPv4Payload_getBuf(&(q[rp].data));
if(q[rp].ackno==i_sq){
//i_inst->txbuf.rp->rpのパケットのRTOからbaseRTOの値を再計算。
estimateRTO(i_inst,i_inst->txbuf.rp,n+1);
i_inst->txbuf.rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
return n+1;
}
n++;
rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
}
return 0;
}
/**
* 空きキューを1個返します。
* 空きキューの
*/
static struct NyLPC_TcTcpSocket_TxQItem* getTxQ(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TcStopwatch_t* i_timer)
{
int i;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
while(!NyLPC_cStopwatch_isExpired(i_timer)){
//クローズドに遷移してしまったら、エラーである。
if(i_inst->tcpstateflags==UIP_CLOSED){
return NULL;
}
//キューの空きをチェック。wp+1==rpなら、キューがいっぱい。rp==wpなら、キューが空。
if(((i_inst->txbuf.wp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ)==i_inst->txbuf.rp){
//一時的なアンロック
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//タスクスイッチ
NyLPC_cThread_yield();
//ロック
NyLPC_cMutex_lock(&(i_inst->_smutex));
continue;
}
i=i_inst->txbuf.wp;
i_inst->txbuf.wp=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
return &(q[i]);
}
//失敗。タイムアウト。
return NULL;
}
/**********************************************************************
* public 関数
**********************************************************************/
NyLPC_TBool NyLPC_cTcpSocket_initialize(NyLPC_TcTcpSocket_t* i_inst,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
{
int i;
NyLPC_TcUipService_t* srv=_NyLPC_TcUipService_inst;
//uipサービスは初期化済であること。
NyLPC_Assert(NyLPC_TcUipService_isInitService());
NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(i_inst->_smutex)));
i_inst->tcpstateflags=UIP_CLOSED;
i_inst->txbuf.rp=i_inst->txbuf.wp=0;
for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
NyLPC_cIPv4Payload_initialize(&(i_inst->txbuf.txq[i].data));
}
//管理リストへ登録。
return NyLPC_cIPv4_addSocket(&(srv->_tcpv4),i_inst);
}
void NyLPC_cTcpSocket_finalize(NyLPC_TcTcpSocket_t* i_inst)
{
int i;
NyLPC_TcUipService_t* srv=_NyLPC_TcUipService_inst;
NyLPC_Assert(NyLPC_TcUipService_isInitService());
//uipサービスは初期化済であること。
if(!NyLPC_cIPv4_removeSocket(&(srv->_tcpv4),i_inst)){
//削除失敗、それは死を意味する。
NyLPC_Abort();
}
//開放漏れの保険
if(i_inst->txbuf.rp!=i_inst->txbuf.wp){
NyLPC_cMutex_lock(&(i_inst->_smutex));
resetTxQWithUnlock(i_inst);
}
for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
NyLPC_cIPv4Payload_finalize(&(i_inst->txbuf.txq[i].data));
}
NyLPC_cFifoBuffer_finalize(&(i_inst->rxbuf));
NyLPC_cMutex_finalize(&(i_inst->_smutex));
return;
}
/**
* この関数は、cIPv4Tcpが呼び出すシステムAPIです。
* uipコアタスクが実行します。
* ソケットを、SYNパケットで初期化して、UIP_SYN_RECV状態にします。
* @return
* 遷移に成功すると、TRUEを返します。
*/
NyLPC_TBool NyLPC_cTcpSocket_setSynPayload(NyLPC_TcTcpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config,const NyLPC_TcIPv4Payload_t* i_ipp)
{
NyLPC_TUInt16 tmp16;
//ソケットが無効であること。
NyLPC_cMutex_lock(&(i_inst->_smutex));
if(i_inst->tcpstateflags==UIP_CLOSED)
{
/* Fill in the necessary fields for the new connection. */
i_inst->uip_connr.current_rto32 = UIP_IP_RTOP_INITIAL;
i_inst->uip_connr.lport = i_ipp->payload.tcp->destport;
i_inst->uip_connr.rport = i_ipp->payload.tcp->srcport;
i_inst->uip_connr.ripaddr=i_ipp->header->srcipaddr;
i_inst->uip_connr.snd_nxt32=iss32;
i_inst->uip_connr.lipaddr=&(i_config->ip_addr);
/* rcv_nxt should be the seqno from the incoming packet + 1. */
i_inst->uip_connr.rcv_nxt32= NyLPC_ntohl(i_ipp->payload.tcp->seqno32)+1;
//MSSの設定
i_inst->uip_connr.default_mss=i_inst->uip_connr.peer_mss=i_config->default_mss;
if(NyLPC_TTcpHeader_getTcpMmsOpt(i_ipp->payload.tcp,&tmp16)){
i_inst->uip_connr.peer_mss=tmp16;
}
i_inst->uip_connr.peer_win=0;
NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
//前回のデータが残っていた場合の保険
if(i_inst->txbuf.rp!=i_inst->txbuf.wp){
resetTxQWithUnlock(i_inst);
}else{
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}
//ここでステータスがかわる。
i_inst->tcpstateflags = UIP_SYN_RCVD;
return NyLPC_TBool_TRUE;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
return NyLPC_TBool_FALSE;
}
/**
* sq番のTxがキューから消え去るのを待ちます。
* この関数は、アンロック状態でコールしてください。
* <div>
* パケットがキューからなくなる条件は、以下の2つです。
* <ul>
* <li>ACKを受信してパケットキューが更新された。</li>
* <li>RSTを受信して(CLOSEDに遷移して)、キューがクリアされた。</li>
* <li>送信タイムアウトで関数が(CLOSEDに遷移させて)キューをクリアした。</li>
* </ul>
* </div>
* @param i_wait_msec
* @return
* 1番目の条件でパケットが消失したときのみ、TRUEを返します。
* 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
*/
static NyLPC_TBool waitForTxRemove(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,NyLPC_TcStopwatch_t* i_timer)
{
NyLPC_TUInt8 f;
NyLPC_cMutex_lock(&(i_inst->_smutex));
while(!NyLPC_cStopwatch_isExpired(i_timer)){
//パケットが送信中か調べる。
if(!isPacketAcked(i_inst,i_sq)){
//まだある場合は、タスクスイッチを繰り返して消失を待つ。
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cThread_yield();
NyLPC_cMutex_lock(&(i_inst->_smutex));
continue;
}
//なくなった場合は、原因を調べる。
f=i_inst->tcpstateflags;
NyLPC_cMutex_unlock(&(i_inst->_smutex));
return (f==UIP_CLOSED)?NyLPC_TBool_FALSE:NyLPC_TBool_TRUE;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
return NyLPC_TBool_FALSE;
}
/**
* 再送信処理をセットして、パケットを送信します。
* この関数は「アンロック状態で」実行してください。
* @param i_len
* 送信データサイズを指定します。
* この番号は、シーケンス番号の加算値ではありませんので、注意をしてください。
* @return
* <ul>
* <li>n=-1:送信キューへの投入に失敗した。</li>
* <li>n>=0:nバイトのデータを送信キューへの投入することに成功した。</li>
* </ul>
* 送信キューに失敗する理由は2つあります。1つは、TXバッファがフルでタイムアウト。もうひとつは、非同期なコネクリョンのリセットです。
* 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
*/
static NyLPC_TInt32 sendWithRetransmit(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len,NyLPC_TcStopwatch_t* i_timer,NyLPC_TUInt32* o_ack)
{
struct NyLPC_TcTcpSocket_TxQItem* txq;
NyLPC_TUInt16 s;
void* buf;
NyLPC_TUInt32 next_ack;
//送信バッファを取得
buf=NyLPC_cUipService_allocTxBuf(i_len+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
NyLPC_cMutex_lock(&(i_inst->_smutex));
//ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
if(i_len>0){
while(i_inst->uip_connr.peer_win==0){
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//時間切れならエラー。
if(NyLPC_cStopwatch_isExpired(i_timer)){
return -1;
}
NyLPC_cThread_yield();
NyLPC_cMutex_lock(&(i_inst->_smutex));
}
}
//送信キューの取得
txq=getTxQ(i_inst,i_timer);
//送信キューが取れなかった。
if(txq==NULL){
//シーケンス番号をロールバックできないので、エラーとする。
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cUipService_releaseTxBuf(buf);
return -1;
}
//IPv4ペイロードの書き込み
NyLPC_cIPv4Payload_setTxBuf(&(txq->data),buf);
//送信バッファを基準とした送信サイズを計算
s-=SIZE_OF_IPv4_TCPIP_HEADER;
//送信サイズよりMMSが小さければ、送信サイズを修正
if(i_inst->uip_connr.peer_mss<s){
s=i_inst->uip_connr.peer_mss;
}
//送信サイズよりpeerのウインドウサイズが小さければ修正
if(i_inst->uip_connr.peer_win<s){
s=i_inst->uip_connr.peer_win;
}
//送信サイズより、データサイズが小さければ、送信サイズを修正
if(i_len<s){
s=i_len;
}
//ACK番号の計算
next_ack=i_inst->uip_connr.snd_nxt32+s+((i_tcpf&(TCP_FIN|TCP_SYN))!=0x00?1:0);
txq->rto32=i_inst->uip_connr.current_rto32;
txq->tick_of_sent=NyLPC_cStopwatch_now();
//パケットの書き込み
setPacket(i_inst,&(txq->data),i_tcpf,i_buf,s);
//シーケンス番号の更新
i_inst->uip_connr.snd_nxt32=next_ack;
//Peerのウインドウサイズを更新
i_inst->uip_connr.peer_win-=s;
//ACK番号の返却
*o_ack=txq->ackno=NyLPC_HTONL(next_ack);
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cUipService_sendIPv4Tx(buf);
return s;
}
/**
* RSTを1フレームだけ送信します。
* この関数は、クローズドステータスのソケットにしてからコールします。
* この関数は、アンロック状態でコールしてね。
*/
static void sendRst(NyLPC_TcTcpSocket_t* i_inst)
{
NyLPC_TcIPv4Payload_t ipv4;
NyLPC_TUInt16 s;
void* buf;
NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);
//ペイロードライタの初期化
NyLPC_cIPv4Payload_initialize(&ipv4);
//IPヘッダ+10バイトくらい。
buf=NyLPC_cUipService_allocTxBuf((SIZE_OF_IPv4_TCPIP_HEADER)+5,&s);
NyLPC_cMutex_lock(&(i_inst->_smutex));
NyLPC_cIPv4Payload_setTxBuf(&ipv4,buf);
i_inst->uip_connr.snd_nxt32++;
setPacket(i_inst,&ipv4,TCP_RST|TCP_ACK,buf,0);
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cUipService_sendIPv4Tx(buf);
NyLPC_cUipService_releaseTxBuf(buf);
NyLPC_cIPv4Payload_finalize(&ipv4);
return;
}
/**
* 受信データを排他処理してバッファに書き込む。
* 十分な空き領域がない場合、失敗する。
* この関数は、ロックして実行してください。
*/
static NyLPC_TBool addRecvData(NyLPC_TcTcpSocket_t* i_inst,void* i_data,NyLPC_TUInt16 i_data_size)
{
//受信データサイズを確認
if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))>=i_data_size){
//バッファに格納可能なら、格納。
NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),i_data,i_data_size);
}else{
//エラー:ドロップする。
return NyLPC_TBool_FALSE;
}
return NyLPC_TBool_TRUE;
}
/**
* Public function
*/
/**
* この関数は、UIP_SYN_RCVDステータスのソケットを、ESTABLISHEDへ遷移させます。
* cTcpListener_listen関数を通過したインスタンスに実行してください。
* この関数は、アプリケーションが呼び出します。
* @return
*
*/
NyLPC_TBool NyLPC_cTcpSocket_accept(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
{
volatile NyLPC_TUInt8 f;
NyLPC_TUInt32 sq;
NyLPC_TcStopwatch_t sw;
NyLPC_cStopwatch_initialize(&sw);
//ステータスチェック
f=i_inst->tcpstateflags;
switch(f)
{
case UIP_ESTABLISHED:
return NyLPC_TBool_TRUE;
case UIP_SYN_RCVD:
//処理対象
break;
default:
return NyLPC_TBool_FALSE;
}
NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
if(sendWithRetransmit(i_inst,TCP_SYN|TCP_ACK,NULL,0,&sw,&sq)==0){
//ちょっと待つ。
NyLPC_cThread_yield();
//キューにあるTXが消えるのを待つ。
if(waitForTxRemove(i_inst,sq,&sw)){
//ACK受信に成功して、TXが消失
NyLPC_cStopwatch_finalize(&sw);
return NyLPC_TBool_TRUE;
}
}
//ロックして、強制的なステータス遷移
NyLPC_cMutex_lock(&(i_inst->_smutex));
f=i_inst->tcpstateflags;
if(f!=UIP_CLOSED){
i_inst->tcpstateflags=UIP_CLOSED;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//もし、強制CLOSE遷移であれば、RSTも送信。
if(f!=UIP_CLOSED){
sendRst(i_inst);
}
return NyLPC_TBool_FALSE;
}
/**
* この関数は、ソケットの受信バッファの読み取り位置と、読み出せるデータサイズを返却します。
* 関数はポインターを返却するだけで、バッファの読み取り位置をシークしません。
* シークするにはNyLPC_cTcpSocket_pseekを使います。
*/
NyLPC_TInt32 NyLPC_cTcpSocket_precv(NyLPC_TcTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec)
{
volatile NyLPC_TUInt8 st;
NyLPC_TUInt16 rlen;
//タイマを生成
NyLPC_TcStopwatch_t sw;
NyLPC_cStopwatch_initialize(&sw);
//ESTABLISHED以外の場合は、エラー。
NyLPC_cStopwatch_setNow(&sw);
while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec)
{
//読み出しバッファ情報のコピー
//MUTEX LOCK
NyLPC_cMutex_lock(&(i_inst->_smutex));
st=i_inst->tcpstateflags;
rlen=NyLPC_cFifoBuffer_getLength(&(i_inst->rxbuf));
*o_buf_ptr=NyLPC_cFifoBuffer_getPtr(&(i_inst->rxbuf));
//MUTEX UNLOCK
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//バッファが空の場合は、ステータスチェック。ESTABLISHEDでなければ、エラー(PASVCLOSE等の場合)
switch(st){
case UIP_ESTABLISHED:
if(rlen>0){
//バッファにパケットがあれば返却
NyLPC_cStopwatch_finalize(&sw);
return rlen;
}
break;
case UIP_CLOSE_WAIT:
if(rlen>0){
//バッファにパケットがあれば返却
NyLPC_cStopwatch_finalize(&sw);
return rlen;
}
//引き続きエラー処理
default:
//他の場合はエラー
NyLPC_cStopwatch_finalize(&sw);
return -1;
}
//タスクスイッチ
NyLPC_cThread_yield();
};
//規定時間内に受信が成功しなかった。
NyLPC_cStopwatch_finalize(&sw);
return 0;
}
/**
* 受信バッファをシークします。
* シーク後に、遅延ACKを送出します。
*/
void NyLPC_cTcpSocket_pseek(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek)
{
NyLPC_TcIPv4Payload_t ipv4payload;
void* buf;
NyLPC_TUInt16 s;
NyLPC_ArgAssert(i_seek<=NyLPC_cFifoBuffer_getLength(&(i_inst->rxbuf)));
if(i_seek==0){
return;
}
//ペイロードライタの初期化
NyLPC_cIPv4Payload_initialize(&ipv4payload);
//ACK送信バッファの取得
buf=NyLPC_cUipService_allocTxBuf((SIZE_OF_IPv4_TCPIP_HEADER)+5,&s);
//MUTEX LOCK
NyLPC_cMutex_lock(&(i_inst->_smutex));
//受信バッファを読み出しシーク
NyLPC_cFifoBuffer_pop(&(i_inst->rxbuf),i_seek);
//ACKパケットの生成
NyLPC_cIPv4Payload_setTxBuf(&ipv4payload,buf);
setPacket(i_inst,&ipv4payload,TCP_ACK,buf,0);
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//ACK送信
NyLPC_cUipService_sendIPv4Tx(buf);
NyLPC_cUipService_releaseTxBuf(buf);
//ペイロードライタの破棄
NyLPC_cIPv4Payload_finalize(&ipv4payload);
}
/**
* See header file.
*/
void* NyLPC_cTcpSocket_allocSendBuf(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
{
NyLPC_TUInt16 s;
void* buf;
NyLPC_TcStopwatch_t sw;
NyLPC_cStopwatch_initialize(&sw);
NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
//送信バッファを取得
buf=NyLPC_cUipService_allocTxBuf(i_hint+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
//ここ、要求サイズとpeerのwinのうち、小さいほうを割り当てたほうが良くない?
NyLPC_cMutex_lock(&(i_inst->_smutex));
//ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
while(i_inst->uip_connr.peer_win==0){
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//時間切れならエラー。
if(NyLPC_cStopwatch_isExpired(&sw)){
NyLPC_cStopwatch_finalize(&sw);
return NULL;
}
NyLPC_cThread_yield();
NyLPC_cMutex_lock(&(i_inst->_smutex));
}
//送信バッファを基準とした送信サイズを計算
s-=SIZE_OF_IPv4_TCPIP_HEADER;
//送信サイズよりMMSが小さければ、送信サイズを修正
if(i_inst->uip_connr.peer_mss<s){
s=i_inst->uip_connr.peer_mss;
}
//送信サイズよりpeerのウインドウサイズが小さければ修正
if(i_inst->uip_connr.peer_win<s){
s=i_inst->uip_connr.peer_win;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//バッファサイズ確定。
*o_buf_size=s;
NyLPC_cStopwatch_finalize(&sw);
return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_TCPIP_HEADER;
}
/**
* See Header file.
*/
void NyLPC_cTcpSocket_releaseSendBuf(NyLPC_TcTcpSocket_t* i_inst,void* i_buf_ptr)
{
NyLPC_cUipService_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER);
}
/**
* 事前にAllocしたTxパケットを送信します。
* このAPIはゼロコピー送信をサポートするためのものです。
* @param i_buf_ptr
* allocSendBufで取得したメモリを指定します。
* @return
* 関数が失敗した場合、i_buf_ptrは「開放されません。」
*/
NyLPC_TBool NyLPC_cTcpSocket_psend(NyLPC_TcTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec)
{
struct NyLPC_TcTcpSocket_TxQItem* txq;
void* buf;
NyLPC_TcStopwatch_t sw;
//ESTABLISHEDでなければエラー
if(i_inst->tcpstateflags!=UIP_ESTABLISHED){
//ESTABLISHEDでなければエラー
return NyLPC_TBool_FALSE;
}
//送信データ0ならエラー
if(i_len<1){
return NyLPC_TBool_TRUE;
}
NyLPC_cStopwatch_initialize(&sw);
NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
//先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER;
NyLPC_cMutex_lock(&(i_inst->_smutex));
//送信キューの取得
txq=getTxQ(i_inst,&sw);
//送信キューが取れなかった。
if(txq==NULL){
//シーケンス番号をロールバックできないので、エラーとする。
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cStopwatch_finalize(&sw);
return NyLPC_TBool_FALSE;
}
//ここから先はi_bufの所有権はインスタンスになってる。
//IPv4ペイロードの書き込み
NyLPC_cIPv4Payload_setTxBuf(&(txq->data),buf);
//allocをした時点でwin,mssは考慮されているので、そのままそうしんしる。
//ACK番号の計算
txq->rto32=i_inst->uip_connr.current_rto32;
txq->tick_of_sent=NyLPC_cStopwatch_now();
//パケットヘッダの生成
NyLPC_cIPv4Payload_initTcpTx(&(txq->data),0x05,((UIP_TCPH_LEN) / 4),i_len);
NyLPC_cIPv4Payload_setTcpTxHeaderByConnection(&(txq->data),&(i_inst->uip_connr),TCP_ACK|TCP_PSH);
NyLPC_cIPv4Payload_setTcpWnd(&(txq->data),NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
NyLPC_cIPv4Payload_closeTcpTxPacket(&(txq->data));
//シーケンス番号の更新
i_inst->uip_connr.snd_nxt32=i_inst->uip_connr.snd_nxt32+i_len;
//Peerのウインドウサイズを更新
i_inst->uip_connr.peer_win-=i_len;
//ACK番号の返却
txq->ackno=NyLPC_HTONL(i_inst->uip_connr.snd_nxt32);
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cUipService_sendIPv4Tx(buf);
NyLPC_cStopwatch_finalize(&sw);
return NyLPC_TBool_TRUE;
}
/**
* See header file.
*/
NyLPC_TInt16 NyLPC_cTcpSocket_send(NyLPC_TcTcpSocket_t* i_inst,const void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec)
{
NyLPC_TUInt32 sq;
NyLPC_TInt32 r;
NyLPC_TcStopwatch_t sw;
//ESTABLISHEDでなければエラー
if(i_inst->tcpstateflags!=UIP_ESTABLISHED){
//ESTABLISHEDでなければエラー
return -1;
}
if(i_len<1){
return 0;
}
NyLPC_cStopwatch_initialize(&sw);
NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
//PSHACKを送信する。
r=sendWithRetransmit(i_inst,TCP_PSH|TCP_ACK,i_buf_ptr,i_len,&sw,&sq);
NyLPC_cStopwatch_finalize(&sw);
//失敗時も何もしない?強制CLOSEしなくて平気?
return r;
}
void NyLPC_cTcpSocket_close(NyLPC_TcTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
{
NyLPC_TcStopwatch_t sw;
volatile NyLPC_TUInt8 f;
NyLPC_TUInt32 sq;
NyLPC_cStopwatch_initialize(&sw);
NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
NyLPC_cMutex_lock(&(i_inst->_smutex));
f=i_inst->tcpstateflags;
//ステータスチェック
switch(f)
{
case UIP_CLOSED:
//閉じている。
goto ReturnWithUnlock;
case UIP_ESTABLISHED:
//アクティブクローズ。
i_inst->tcpstateflags=UIP_FIN_WAIT_1;
//送信のために一旦解除
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//FINの送信
if(sendWithRetransmit(i_inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
//ちょっと待つ。
NyLPC_cThread_yield();
//TXの消去待ち
if(waitForTxRemove(i_inst,sq,&sw)){
//再ロック
NyLPC_cMutex_lock(&(i_inst->_smutex));
//タイムアウトするか、UIP_CLOSED、もしくはTIME_WAITに遷移するのを待つ。(遷移はRxprocで自動的に実行。)
while(!NyLPC_cStopwatch_isExpired(&sw)){
switch(i_inst->tcpstateflags)
{
case UIP_TIME_WAIT:
i_inst->tcpstateflags=UIP_CLOSED;
case UIP_CLOSED:
NyLPC_Assert(i_inst->txbuf.rp==i_inst->txbuf.wp);
//成功。
goto ReturnWithUnlock;
case UIP_FIN_WAIT_1:
case UIP_FIN_WAIT_2:
case UIP_CLOSING:
//一時的なアンロック
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cThread_yield();
NyLPC_cMutex_lock(&(i_inst->_smutex));
default:
break;
}
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}
}
break;
case UIP_CLOSE_WAIT:
//LAST_ACKへ遷移
i_inst->tcpstateflags=UIP_LAST_ACK;
//送信のために一旦解除
NyLPC_cMutex_unlock(&(i_inst->_smutex));
if(sendWithRetransmit(i_inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
//ちょっと待つ。
NyLPC_cThread_yield();
//TXの消去待ち
if(waitForTxRemove(i_inst,sq,&sw)){
//再ロック
NyLPC_cMutex_lock(&(i_inst->_smutex));
//TX消去後にCLOSEDに遷移していればOK
if(i_inst->tcpstateflags==UIP_CLOSED)
{
NyLPC_Assert(i_inst->txbuf.rp==i_inst->txbuf.wp);
goto ReturnWithUnlock;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}
}
//エラー。RSTで切断。
break;
default:
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_Warning();
break;
}
if(i_inst->_smutex._lock_count>0){
NyLPC_Warning();
}
//このパスに到達するのは、FIN送信/ACKに成功したにも拘らず、規定時間内にCLOSEDに遷移しなかった場合。
//コネクションを強制遷移して、RST
NyLPC_cMutex_lock(&(i_inst->_smutex));
f=i_inst->tcpstateflags;
if(f!=UIP_CLOSED){
i_inst->tcpstateflags=UIP_CLOSED;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//もし、強制CLOSE遷移であれば、RSTも送信。
if(f!=UIP_CLOSED){
sendRst(i_inst);
}
NyLPC_cStopwatch_finalize(&sw);
return;
ReturnWithUnlock:
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_cStopwatch_finalize(&sw);
return;
}
/**
* 定期的に実行する関数。最低でも1s単位で実行してください。
* 動作
*/
void NyLPC_cTcpSocket_periodic(
NyLPC_TcTcpSocket_t* i_inst)
{
int i;
struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
NyLPC_TcStopwatch_t sw;
NyLPC_TUInt32 now;
int rp;
NyLPC_cStopwatch_initialize(&sw);
now=NyLPC_cStopwatch_now();
//MUTEX LOCK
NyLPC_cMutex_lock(&(i_inst->_smutex));
if(i_inst->tcpstateflags==UIP_CLOSED)
{
//CLOSEDなら、バッファ開放。
resetTxQWithUnlock(i_inst);
}else if(i_inst->txbuf.rp==i_inst->txbuf.wp){
//再送信パケットがなければ何もしないよ。
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}else if(i_inst->uip_connr.peer_win==0){
//peer_winが0の場合は何もしない。
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}else{
//再送信処理
rp=i_inst->txbuf.rp;
NyLPC_cStopwatch_set(&sw,q[rp].tick_of_sent);
if(NyLPC_cStopwatch_elapseInMsec(&sw)>q[rp].rto32){
//最古のパケットの送信時間をチェックして、タイムアウトが発生したら、再送時間と送信時刻をセット
//最古パケットRTOを2倍。
q[rp].rto32*=2;
for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
q[i].tick_of_sent=now;
}
if(q[rp].rto32>UIP_IP_RTO_MAX_RTO){
//最古のRTOが64秒を超えたら、CLOSED
i_inst->tcpstateflags =UIP_CLOSED;
resetTxQWithUnlock(i_inst);
sendRst(i_inst);
}else{
//規定時間内なら、再送処理
for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
NyLPC_cUipService_sendIPv4Tx(NyLPC_cIPv4Payload_getBuf(&(q[i].data)));
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}
}else{
NyLPC_cMutex_unlock(&(i_inst->_smutex));
}
}
NyLPC_cStopwatch_finalize(&sw);
return;
}
/**
* この関数は、rxパケットを処理して、ソケットの状態を更新します。
* uipサービスタスクが実行する関数です。
* o_ippのペイロードに、応答ペイロードを設定することがあります。
* この関数はNyLPC_cTcpSocket_periodicと排他実行すること。
*/
NyLPC_TBool NyLPC_cTcpSocket_parseRx(
NyLPC_TcTcpSocket_t* i_inst,
NyLPC_TcIPv4Payload_t* o_ipp)
{
int i,s;
NyLPC_TUInt16 tmp16;
NyLPC_TUInt16 data_size;
NyLPC_TUInt8 in_tcpflag=o_ipp->payload.tcp->flags;
void* tcp_data_offset;
NyLPC_TBool is_new_packet;
int num_of_noack;
void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
NyLPC_TBool ret;
//パラメータの計算
tmp16=NyLPC_TTcpHeader_getHeaderLength(o_ipp->payload.tcp);
//TCPペイロードの長さは、IPパケットの長さ-(IPヘッダ+TCPヘッダ)
data_size=NyLPC_TIPv4Header_getPacketLength(o_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(o_ipp->header)-tmp16;
//TCPデータオフセット
tcp_data_offset=o_ipp->payload.rawbuf+tmp16;
//インスタンスをロックする。
NyLPC_cMutex_lock(&(i_inst->_smutex));
//RSTのチェック。RST受信時は、状態にかかわらず、CLOSEDステータスに移行する。
if (in_tcpflag & TCP_RST)
{
i_inst->tcpstateflags =UIP_CLOSED;
goto DROP;
}
is_new_packet=NyLPC_ntohl(o_ipp->payload.tcp->seqno32)==i_inst->uip_connr.rcv_nxt32;
//OPTIONの反映
//MSSの取得
if(NyLPC_TTcpHeader_getTcpMmsOpt(o_ipp->payload.tcp,&tmp16)){
//取得で着たら更新
i_inst->uip_connr.peer_mss=tmp16;
}
//受信パケットを元に、未ACKパケットの数を計算
num_of_noack=getNumOfSending(i_inst,o_ipp->payload.tcp->ackno32);//i_inst->txbuf.num_of_txq;
//ステータス毎のACK応答
switch(i_inst->tcpstateflags)
{
case UIP_SYN_RCVD:
//ACKを受信したら、ESTABLISHEDへ。
//すべてのパケットをACKしたかで判定。()
if(num_of_noack==0){
i_inst->tcpstateflags=UIP_ESTABLISHED;
}else{
//それ以外のパケットはドロップする。
break;//goto DROP;
}
//新しいパケットがなければ、無応答
if(!is_new_packet){
break;//goto DROP;
}
//引き続き、ESTABLISHEDの処理へ。
case UIP_ESTABLISHED:
if(data_size>0){
if(is_new_packet){
if(addRecvData(i_inst,tcp_data_offset,data_size)){
//通常のACK返却
i_inst->uip_connr.rcv_nxt32+=data_size;
}else{
//失敗したときは必要に応じて単純ACK
}
}
}
//MSSとWNDの更新
i_inst->uip_connr.peer_mss = i_inst->uip_connr.default_mss;
//どちらにしろ、ACK送信
if(is_new_packet && (in_tcpflag & TCP_FIN)){
//FINがあるときは、ステータスをCLOSE_WAITへセットして、ACKを返す。
i_inst->tcpstateflags = UIP_CLOSE_WAIT;
i_inst->uip_connr.rcv_nxt32++;
}
break;
case UIP_CLOSE_WAIT:
//必要に応じたACK応答
break;
case UIP_LAST_ACK:
//ACK(by FIN)が得られたなら、CLOSEDへ。
if(num_of_noack==0){
i_inst->tcpstateflags=UIP_CLOSED;
}
//必要に応じたACK応答
break;
case UIP_FIN_WAIT_1:
//FIN受信->CLOSINGへ
if(is_new_packet && (in_tcpflag & TCP_FIN)){
i_inst->uip_connr.rcv_nxt32++;
if(num_of_noack==0){
//FINとACKを受信
i_inst->tcpstateflags=UIP_TIME_WAIT;
}else{
//FINのみ
i_inst->tcpstateflags=UIP_CLOSING;
}
}else if(num_of_noack==0){
//ACKのみ
i_inst->tcpstateflags=UIP_FIN_WAIT_2;
}
//必要に応じたACK応答
break;
case UIP_FIN_WAIT_2:
//FIN受信->TIME_WAITへ(pureACK)
if(is_new_packet && (in_tcpflag & TCP_FIN)){
i_inst->uip_connr.rcv_nxt32++;
i_inst->tcpstateflags=UIP_TIME_WAIT;
}
break;
case UIP_CLOSING:
//ACK受信したら、TIME_WAITへ
if(num_of_noack==0){
i_inst->tcpstateflags=UIP_TIME_WAIT;
}
break;
case UIP_CLOSED:
//何もできない。何もしない。
break;//goto DROP;
case UIP_TIME_WAIT:
//最終ACKを送り続ける。
break;
default:
goto DROP;
}
//ウインドウサイズを更新
i_inst->uip_connr.peer_win=NyLPC_ntohs(o_ipp->payload.tcp->wnd16);
//送信キューから、Peerが受信したデータを削除する。
if(in_tcpflag & TCP_ACK){
//再送パケットキューから送信済みのデータを回収(後で開放)
NyLPC_Trace();
s=updateTxQByIndex(i_inst,o_ipp->payload.tcp->ackno32,dlist);
NyLPC_Trace();
}else{
s=0;
}
//新しいパケットがきた場合は、再送キューのACKを更新する。
if(is_new_packet){
//再送キューのACKを更新
updateTxAck(i_inst,NyLPC_htonl(i_inst->uip_connr.rcv_nxt32));
}
//送信キューのない
ret=NyLPC_TBool_FALSE;
if(((in_tcpflag&(TCP_FIN|TCP_SYN))!=0x00) ||
((!is_new_packet) && (data_size>0)))
{
setPacket(i_inst,o_ipp,TCP_ACK,NULL,0);
ret=NyLPC_TBool_TRUE;
}else{
ret=NyLPC_TBool_FALSE;
}
NyLPC_cMutex_unlock(&(i_inst->_smutex));
//取り外したTXメモリの開放
for(i=0;i<s;i++){
//取り外したTXメモリを開放
NyLPC_cUipService_releaseTxBuf(dlist[i]);
}
NyLPC_Trace();
return ret;
DROP:
//ACKしたパケットを送信キューから削除
NyLPC_cMutex_unlock(&(i_inst->_smutex));
NyLPC_Trace();
return NyLPC_TBool_FALSE;
}
