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.
Dependents: MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more
uip/NyLPC_cTcpSocket.cpp
- Committer:
- nyatla
- Date:
- 2013-01-30
- Revision:
- 0:142ee8b12fef
File content as of revision 0:142ee8b12fef:
/*********************************************************************************
* 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,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
{
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;
}
MiMic Webservice library