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
NyLPC_cMiMicIpTcpSocket.c
00001 /********************************************************************************* 00002 * PROJECT: MiMic 00003 * -------------------------------------------------------------------------------- 00004 * 00005 * This file is part of MiMic 00006 * Copyright (C)2011 Ryo Iizuka 00007 * 00008 * MiMic is free software: you can redistribute it and/or modify 00009 * it under the terms of the GNU Lesser General Public License as published 00010 * by the Free Software Foundation, either version 3 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public License 00019 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 * 00021 * For further information please contact. 00022 * http://nyatla.jp/ 00023 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp> 00024 * 00025 *********************************************************************************/ 00026 #include "NyLPC_cMiMicIpTcpSocket_protected.h" 00027 #include "NyLPC_stdlib.h" 00028 #include "NyLPC_cMiMicIpNetIf_protected.h" 00029 00030 00031 static NyLPC_TUInt32 iss32=3939; 00032 #define SIZE_OF_IPv4_TCPIP_HEADER 40 00033 00034 /** 00035 * TCPのRTOの最大値。 00036 * ms単位である。 00037 * defaultは64SEC 00038 */ 00039 #define UIP_IP_RTO_MAX_RTO 64000 00040 /** 00041 * TCPのRTOの初期値。 00042 * ms単位である。 00043 * 伝送路の特性に合わせて調整すること。 00044 */ 00045 #define UIP_TCP_RTO_INITIAL 3000 00046 00047 /** 00048 * CONNECTION時のRTO 00049 */ 00050 #define UIP_TCP_RTO_CONNECTION_INITIAL 200 00051 00052 /** 00053 * 下限値 00054 */ 00055 #define UIP_TCP_RTO_MINIMUM 100 00056 00057 00058 /** 00059 * for Debug 00060 * RTOの情報をログ領域に取る。 00061 */ 00062 #ifdef RTO_LOG 00063 NyLPC_TUInt32 rto_log[256]; 00064 int rto_log_st=0; 00065 #define DEBUG_RTO_LOG(i_inst) if(rto_log_st<256){rto_log[rto_log_st++]=i_inst->uip_connr.current_rto32;}; 00066 #else 00067 #define DEBUG_RTO_LOG(i_inst) 00068 #endif 00069 00070 //#define lockResource(i_inst) NyLPC_cMutex_lock(&((i_inst)->_smutex)) 00071 //#define unlockResource(i_inst) NyLPC_cMutex_unlock(&((i_inst)->_smutex)) 00072 #define lockResource(i_inst) NyLPC_cMutex_lock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4))) 00073 #define unlockResource(i_inst) NyLPC_cMutex_unlock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4))) 00074 00075 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst); 00076 00077 00078 00079 00080 //////////////////////////////////////////////////////////////////////////////////////////////////// 00081 // 00082 // Packet writer 00083 // 00084 //////////////////////////////////////////////////////////////////////////////////////////////////// 00085 00086 00087 /** 00088 * TCPヘッダに値をセットする。checksum,wndは0初期化する。 00089 */ 00090 static void setTcpTxHeader(struct NyLPC_TTcpHeader* i_struct,NyLPC_TUInt8 i_flag,const struct uip_conn* i_conn) 00091 { 00092 i_struct->flags = i_flag; 00093 //sorce & destination port 00094 i_struct->srcport = i_conn->lport; 00095 i_struct->destport = i_conn->rport; 00096 //ACK number 00097 i_struct->ackno32 = NyLPC_htonl(i_conn->rcv_nxt32); 00098 //Seq Number 00099 i_struct->seqno32 = NyLPC_htonl(i_conn->snd_nxt32); 00100 //uip_func_tcp_send_noconn(BUF); 00101 i_struct->urgp[0] = i_struct->urgp[1] = 0; 00102 i_struct->tcpchksum= 0; 00103 } 00104 00105 static void setTxPacket(const NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len) 00106 { 00107 struct NyLPC_TIPv4Header* iph; 00108 struct NyLPC_TTcpHeader* tcph; 00109 NyLPC_TUInt8 iph_word=0x05; 00110 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4; 00111 //IPヘッダの更新 00112 iph=(struct NyLPC_TIPv4Header*)i_tx_buf; 00113 iph->vhl=0x40|(0x0f&iph_word); 00114 iph->destipaddr=i_inst->uip_connr.ripaddr; 00115 iph->srcipaddr =*(i_inst->uip_connr.lipaddr); 00116 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP); 00117 //TCPヘッダの更新 00118 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph)); 00119 00120 00121 //SYNが有るならMSSの書き込み 00122 if((TCP_SYN & i_tcpf)){ 00123 tcph_word+=((TCP_OPT_MSS_LEN) / 4); 00124 NyLPC_TTcpHeader_setMmsOpt(((NyLPC_TUInt8*)(tcph+1)),i_inst->uip_connr.default_mss); 00125 } 00126 tcph->tcpoffset=(tcph_word<<4); 00127 setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr)); 00128 00129 //最終的なパケットサイズと必要ならペイロードを書き込み 00130 if(i_buf!=NULL){ 00131 iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4); 00132 memcpy(((NyLPC_TUInt8*)i_tx_buf)+((iph_word+tcph_word)*4),i_buf,i_len); 00133 }else{ 00134 iph->len16=NyLPC_htons((iph_word+tcph_word)*4); 00135 } 00136 //WND設定 00137 tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))); 00138 //Checksumの生成 00139 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph)); 00140 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph)); 00141 return; 00142 } 00143 00144 /** 00145 * IP/TCPヘッダが40バイト固定として、i_tx_buf+40の位置にあるペイロードに対するIP/TCPヘッダを書き込みます。 00146 */ 00147 static void setTxPacketHeader(const NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,NyLPC_TUInt16 i_len) 00148 { 00149 struct NyLPC_TIPv4Header* iph; 00150 struct NyLPC_TTcpHeader* tcph; 00151 NyLPC_TUInt8 iph_word=0x05; 00152 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4; 00153 //IPヘッダの更新 00154 iph=(struct NyLPC_TIPv4Header*)i_tx_buf; 00155 iph->vhl=0x40|(0x0f&iph_word); 00156 iph->destipaddr=i_inst->uip_connr.ripaddr; 00157 iph->srcipaddr =*(i_inst->uip_connr.lipaddr); 00158 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP); 00159 00160 //TCPヘッダの更新 00161 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph)); 00162 tcph->tcpoffset=(tcph_word<<4); 00163 setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr)); 00164 00165 //最終的なパケットサイズと必要ならペイロードを書き込み 00166 iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4); 00167 //WND設定 00168 tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))); 00169 //Checksumの生成 00170 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph)); 00171 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph)); 00172 return; 00173 } 00174 00175 00176 00177 00178 00179 //////////////////////////////////////////////////////////////////////////////////////////////////// 00180 // 00181 // Mainclass::private 00182 // 00183 //////////////////////////////////////////////////////////////////////////////////////////////////// 00184 00185 /** 00186 * ACK番号を更新する。 00187 * @param i_ackno 00188 * ネットワークオーダーのACK番号 00189 */ 00190 static void updateAckNo(void* i_tx_buf,NyLPC_TUInt32 i_ackno) 00191 { 00192 struct NyLPC_TIPv4Header* iph=(struct NyLPC_TIPv4Header*)i_tx_buf; 00193 struct NyLPC_TTcpHeader* tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph)); 00194 00195 /* union{ 00196 NyLPC_TUInt32 l; 00197 NyLPC_TUInt8 b[4]; 00198 }old_ack,new_ack; 00199 NyLPC_TUInt16 v1; 00200 //checksumの計算 00201 old_ack.l=i_inst->payload.tcp->ackno32;//古いACK番号 00202 new_ack.l=i_ackno;//新しいACK番号 00203 v1=NyLPC_ntohs(~(i_inst->payload.tcp->tcpchksum));//1の補数を取って、ホストオーダーに戻す。 00204 //減算 00205 v1=sub16c(v1,(old_ack.b[0]<<8)+old_ack.b[1]); 00206 v1=sub16c(v1,(old_ack.b[2]<<8)+old_ack.b[3]); 00207 //加算 00208 v1=add16c(v1,(new_ack.b[0]<<8)+new_ack.b[1]); 00209 v1=add16c(v1,(new_ack.b[2]<<8)+new_ack.b[3]); 00210 v1=~NyLPC_htons(v1);*/ 00211 NyLPC_Trace(); 00212 tcph->ackno32=i_ackno; 00213 NyLPC_Trace(); 00214 tcph->tcpchksum = 0; 00215 NyLPC_Trace(); 00216 tcph->tcpchksum = ~(NyLPC_TIPv4Header_makeTcpChecksum(iph)); 00217 NyLPC_Trace(); 00218 00219 /* 00220 if((i_inst->payload.tcp->tcpchksum!=v1)){ 00221 NyLPC_Warning(); 00222 }*/ 00223 } 00224 00225 00226 00227 /** 00228 * 指定した送信パケットがACK済であるか調べる。 00229 */ 00230 static NyLPC_TBool isPacketAcked(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq) 00231 { 00232 int rp; 00233 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00234 rp=i_inst->txbuf.rp; 00235 while(rp!=i_inst->txbuf.wp){ 00236 if(q[rp].ackno==i_sq){ 00237 return NyLPC_TBool_FALSE; 00238 } 00239 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00240 } 00241 return NyLPC_TBool_TRUE; 00242 } 00243 /** 00244 * 送信キューからi_sq以前に送信したパケットを除外して、残り個数を返却する。 00245 */ 00246 static int getNumOfSending(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq) 00247 { 00248 int rp,n; 00249 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00250 rp=i_inst->txbuf.rp; 00251 n=0; 00252 while(rp!=i_inst->txbuf.wp){ 00253 if(q[rp].ackno==i_sq){ 00254 return n; 00255 } 00256 n++; 00257 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00258 } 00259 return n; 00260 } 00261 /** 00262 * この関数は、コネクションをリセットします。 00263 * ロック状態でコールしてください。 00264 * 関数は、現在バッファにある再送信待ちデータを開放します。 00265 */ 00266 static void resetTxQWithUnlock(NyLPC_TcMiMicIpTcpSocket_t* i_inst) 00267 { 00268 int i,l; 00269 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00270 void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ]; 00271 00272 l=0; 00273 while(i_inst->txbuf.rp!=i_inst->txbuf.wp){ 00274 dlist[l]=q[i_inst->txbuf.rp].packet; 00275 l++; 00276 i_inst->txbuf.rp=(i_inst->txbuf.rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00277 } 00278 i_inst->txbuf.rp=i_inst->txbuf.wp=0; 00279 //ロック解除 00280 unlockResource(i_inst); 00281 //セーブしたバッファを開放 00282 for(i=0;i<l;i++){ 00283 NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]); 00284 } 00285 return; 00286 } 00287 /** 00288 * TXバッファの再送パケットのACK番号を更新します。 00289 * ロックして実行してください。 00290 * @param i_ackno 00291 * ネットワークオーダーのACK番号 00292 */ 00293 static void updateTxAck(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_ackno) 00294 { 00295 NyLPC_TUInt8 rp; 00296 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00297 NyLPC_ArgAssert(i_inst!=NULL); 00298 rp=i_inst->txbuf.rp; 00299 while(rp!=i_inst->txbuf.wp){ 00300 updateAckNo(q[rp].packet,i_ackno); 00301 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00302 } 00303 } 00304 00305 /** 00306 * RTOの予測関数 00307 */ 00308 static void estimateRTO(NyLPC_TcMiMicIpTcpSocket_t* i_inst,int s,int n) 00309 { 00310 NyLPC_TcStopwatch_t sw; 00311 NyLPC_TUInt32 cr_rtt_min,cr_rtt_max,sk_rto,new_rto,w; 00312 int i; 00313 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00314 NyLPC_cStopwatch_initialize(&sw); 00315 00316 sk_rto=i_inst->uip_connr.current_rto32; 00317 //ACKされたパケットの個数は? 00318 switch(n){ 00319 case 1: 00320 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent); 00321 cr_rtt_min=NyLPC_cStopwatch_elapseInMsec(&sw); 00322 if(sk_rto<cr_rtt_min){ 00323 //現在のRTOよりも大きい→再送があった。(再送の理由が回線遅延によるものかわからないので、基本RTOを25%増やす。) 00324 new_rto=sk_rto*10/8; 00325 }else if(sk_rto/4<cr_rtt_min){ 00326 //現在のRTOの1/4< n < 現在のRTO 想定内の変動。1/8 00327 new_rto=(sk_rto+(cr_rtt_min*3*7))/8; 00328 }else{ 00329 //現在の1/4以下。RTOを再計算。 RTOが大きすぎるので再計算。(計測値を優先した現在値との平均値) 00330 new_rto=(sk_rto+(cr_rtt_min*3*3))/4; 00331 } 00332 break; 00333 default: 00334 //複数のパケットなら、最大と最小の時刻を得る。 00335 NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent); 00336 cr_rtt_min=cr_rtt_max=NyLPC_cStopwatch_elapseInMsec(&sw); 00337 for(i=1;i<n;i++){ 00338 NyLPC_cStopwatch_set(&sw,q[(s+i)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ].tick_of_sent); 00339 w=NyLPC_cStopwatch_elapseInMsec(&sw); 00340 if(cr_rtt_min>w){ 00341 cr_rtt_min=w; 00342 } 00343 if(cr_rtt_max<w){ 00344 cr_rtt_max=w; 00345 } 00346 } 00347 if(sk_rto<cr_rtt_min && sk_rto<cr_rtt_max){ 00348 //最大値,最小値とも現在のRTTより大きい→低速な回線を検出。 00349 new_rto=cr_rtt_max*10/8;//最大経過時間の25%増しの時間を設定。 00350 }else if(sk_rto/4<cr_rtt_min){ 00351 //現在のRTOの1/4< n < 現在のRTO 想定範囲内。1/8の加重平均で速度計算。 00352 new_rto=(sk_rto+(cr_rtt_min*3*7))/8; 00353 }else{ 00354 //現在の1/4以下。RTOが大きすぎるので再計算。(計測値を優先した加重平均) 00355 new_rto=(sk_rto+(cr_rtt_min*3*3))/4; 00356 } 00357 break; 00358 } 00359 NyLPC_cStopwatch_finalize(&sw); 00360 if(new_rto<UIP_TCP_RTO_MINIMUM){ 00361 new_rto=UIP_TCP_RTO_MINIMUM; 00362 } 00363 i_inst->uip_connr.current_rto32=new_rto; 00364 } 00365 00366 /** 00367 * TXキューから、入力されたシーケンス番号より前のパケットを除外します。 00368 * リングバッファのrp->wp-1までをチェックして、sqに等しいi_sq以前のパケットバッファをo_dlistへ返します。 00369 * 00370 */ 00371 static int updateTxQByIndex(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,void* o_dlist[]) 00372 { 00373 int rp,n; 00374 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00375 //ロック状態なう 00376 rp=i_inst->txbuf.rp; 00377 n=0; 00378 //This is debug 00379 DEBUG_RTO_LOG(i_inst); 00380 00381 while(rp!=i_inst->txbuf.wp){ 00382 o_dlist[n]=q[rp].packet; 00383 if(q[rp].ackno==i_sq){ 00384 //i_inst->txbuf.rp->rpのパケットのRTOからbaseRTOの値を再計算。 00385 estimateRTO(i_inst,i_inst->txbuf.rp,n+1); 00386 i_inst->txbuf.rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00387 return n+1; 00388 } 00389 n++; 00390 rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00391 } 00392 return 0; 00393 } 00394 00395 00396 00397 /** 00398 * 空きキューを1個返します。 00399 * 空きキューの 00400 */ 00401 static struct NyLPC_TcTcpSocket_TxQItem* getTxQ(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TcStopwatch_t* i_timer) 00402 { 00403 int i; 00404 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 00405 do{ 00406 //クローズドに遷移してしまったら、エラーである。 00407 if(i_inst->tcpstateflags==UIP_CLOSED){ 00408 return NULL; 00409 } 00410 //キューの空きをチェック。wp+1==rpなら、キューがいっぱい。rp==wpなら、キューが空。 00411 if(((i_inst->txbuf.wp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ)==i_inst->txbuf.rp){ 00412 //一時的なアンロック 00413 unlockResource(i_inst); 00414 //タスクスイッチ 00415 NyLPC_cThread_yield(); 00416 //ロック 00417 lockResource(i_inst); 00418 continue; 00419 } 00420 i=i_inst->txbuf.wp; 00421 i_inst->txbuf.wp=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ; 00422 return &(q[i]); 00423 }while(!NyLPC_cStopwatch_isExpired(i_timer)); 00424 //失敗。タイムアウト。 00425 return NULL; 00426 } 00427 00428 00429 00430 00431 00432 00433 /********************************************************************** 00434 * public 関数 00435 **********************************************************************/ 00436 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst); 00437 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst); 00438 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec); 00439 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec); 00440 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek); 00441 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec); 00442 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec); 00443 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec); 00444 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr); 00445 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec); 00446 static NyLPC_TBool connect(NyLPC_TiTcpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_peer_port,NyLPC_TUInt32 i_wait_in_msec); 00447 static void finalize(NyLPC_TiTcpSocket_t* i_inst); 00448 00449 const static struct NyLPC_TiTcpSocket_Interface _interface= 00450 { 00451 getPeerAddr, 00452 getPeerPort, 00453 accept, 00454 precv, 00455 pseek, 00456 send, 00457 close, 00458 allocSendBuf, 00459 releaseSendBuf, 00460 psend, 00461 connect, 00462 finalize 00463 }; 00464 00465 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst) 00466 { 00467 const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00468 return &inst->uip_connr.ripaddr; 00469 } 00470 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst) 00471 { 00472 const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00473 return inst->uip_connr.rport; 00474 } 00475 00476 00477 00478 00479 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_initialize(NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len) 00480 { 00481 int i; 00482 NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst; 00483 i_inst->_super._interface=&_interface; 00484 i_inst->_parent_ipv4=&srv->_tcpv4; 00485 00486 //uipサービスは初期化済であること。 00487 NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService()); 00488 00489 NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len); 00490 // NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(i_inst->_smutex)));//個別Mutex 00491 // i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));//共有Mutex 00492 i_inst->tcpstateflags=UIP_CLOSED; 00493 i_inst->txbuf.rp=i_inst->txbuf.wp=0; 00494 for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){ 00495 i_inst->txbuf.txq[i].packet=NULL; 00496 } 00497 //管理リストへ登録。 00498 return NyLPC_TBool_TRUE; 00499 } 00500 00501 00502 00503 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_listenSyn(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const struct NyLPC_TTcpSocketSynParam* i_lq,NyLPC_TUInt16 i_lport) 00504 { 00505 // NyLPC_Assert(NyLPC_cMutex_isLocked(i_inst->_smutex)); 00506 lockResource(i_inst); 00507 //ソケットが無効であること。 00508 if(i_inst->tcpstateflags==UIP_CLOSED) 00509 { 00510 //localipとdefault_mmsは別枠で設定 00511 /* Fill in the necessary fields for the new connection. */ 00512 i_inst->uip_connr.current_rto32 = UIP_TCP_RTO_INITIAL; 00513 i_inst->uip_connr.lport = i_lport; 00514 i_inst->uip_connr.rport = i_lq->rport; 00515 i_inst->uip_connr.ripaddr=i_lq->srcaddr; 00516 i_inst->uip_connr.snd_nxt32=iss32; 00517 /* rcv_nxt should be the seqno from the incoming packet + 1. */ 00518 i_inst->uip_connr.rcv_nxt32= i_lq->rcv_nxt32; 00519 //MSSの設定 00520 i_inst->uip_connr.peer_mss=(i_lq->mss!=0)?i_lq->mss:i_inst->uip_connr.default_mss; 00521 i_inst->uip_connr.peer_win=0; 00522 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf)); 00523 //ここでステータスがかわる。 00524 i_inst->tcpstateflags = UIP_SYN_RCVD; 00525 //前回のデータが残っていた場合の保険 00526 if(i_inst->txbuf.rp!=i_inst->txbuf.wp){ 00527 resetTxQWithUnlock(i_inst); 00528 }else{ 00529 unlockResource(i_inst); 00530 } 00531 return NyLPC_TBool_TRUE; 00532 } 00533 unlockResource(i_inst); 00534 return NyLPC_TBool_FALSE; 00535 } 00536 00537 00538 /** 00539 * sq番のTxがキューから消え去るのを待ちます。 00540 * この関数は、アンロック状態でコールしてください。 00541 * <div> 00542 * パケットがキューからなくなる条件は、以下の2つです。 00543 * <ul> 00544 * <li>ACKを受信してパケットキューが更新された。</li> 00545 * <li>RSTを受信して(CLOSEDに遷移して)、キューがクリアされた。</li> 00546 * <li>送信タイムアウトで関数が(CLOSEDに遷移させて)キューをクリアした。</li> 00547 * </ul> 00548 * </div> 00549 * @param i_wait_msec 00550 * @return 00551 * 1番目の条件でパケットが消失したときのみ、TRUEを返します。 00552 * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。 00553 */ 00554 static NyLPC_TBool waitForTxRemove(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,NyLPC_TcStopwatch_t* i_timer) 00555 { 00556 NyLPC_TUInt8 f; 00557 lockResource(i_inst); 00558 do{ 00559 //パケットが送信中か調べる。 00560 if(!isPacketAcked(i_inst,i_sq)){ 00561 //まだある場合は、タスクスイッチを繰り返して消失を待つ。 00562 unlockResource(i_inst); 00563 NyLPC_cThread_yield(); 00564 lockResource(i_inst); 00565 continue; 00566 } 00567 //なくなった場合は、原因を調べる。 00568 f=i_inst->tcpstateflags; 00569 unlockResource(i_inst); 00570 return (f==UIP_CLOSED)?NyLPC_TBool_FALSE:NyLPC_TBool_TRUE; 00571 }while(!NyLPC_cStopwatch_isExpired(i_timer)); 00572 unlockResource(i_inst); 00573 return NyLPC_TBool_FALSE; 00574 } 00575 00576 00577 /** 00578 * 再送信処理をセットして、パケットを送信します。 00579 * この関数は「アンロック状態で」実行してください。 00580 * @param i_len 00581 * 送信データサイズを指定します。 00582 * この番号は、シーケンス番号の加算値ではありませんので、注意をしてください。 00583 * @return 00584 * <ul> 00585 * <li>n=-1:送信キューへの投入に失敗した。</li> 00586 * <li>n>=0:nバイトのデータを送信キューへの投入することに成功した。</li> 00587 * </ul> 00588 * 送信キューに失敗する理由は2つあります。1つは、TXバッファがフルでタイムアウト。もうひとつは、非同期なコネクリョンのリセットです。 00589 * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。 00590 */ 00591 static NyLPC_TInt32 sendWithRetransmit(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt8 i_tcpf,const void* i_buf,NyLPC_TUInt16 i_len,NyLPC_TcStopwatch_t* i_timer,NyLPC_TUInt32* o_ack) 00592 { 00593 struct NyLPC_TcTcpSocket_TxQItem* txq; 00594 NyLPC_TUInt16 s; 00595 void* buf; 00596 NyLPC_TUInt32 next_ack; 00597 //送信バッファを取得 00598 //@bug オブションパケット送信時に4バイト足りないメモリ要求しない?問題になってないけど。 00599 for(;;){ 00600 buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_len+(SIZE_OF_IPv4_TCPIP_HEADER),&s); 00601 if(buf!=NULL){ 00602 break; 00603 } 00604 //タイムアウト確認 00605 if(NyLPC_cStopwatch_isExpired(i_timer)){ 00606 return -1; 00607 } 00608 }; 00609 lockResource(i_inst); 00610 //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。 00611 if(i_len>0){ 00612 while(i_inst->uip_connr.peer_win==0){ 00613 unlockResource(i_inst); 00614 //時間切れならエラー。 00615 if(NyLPC_cStopwatch_isExpired(i_timer)){ 00616 return -1; 00617 } 00618 NyLPC_cThread_yield(); 00619 lockResource(i_inst); 00620 } 00621 } 00622 //送信キューの取得 00623 txq=getTxQ(i_inst,i_timer); 00624 //送信キューが取れなかった。 00625 if(txq==NULL){ 00626 //シーケンス番号をロールバックできないので、エラーとする。 00627 unlockResource(i_inst); 00628 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf); 00629 return -1; 00630 } 00631 00632 //送信バッファを基準とした送信サイズを計算 00633 s-=SIZE_OF_IPv4_TCPIP_HEADER; 00634 //送信サイズよりMMSが小さければ、送信サイズを修正 00635 if(i_inst->uip_connr.peer_mss<s){ 00636 s=i_inst->uip_connr.peer_mss; 00637 } 00638 //送信サイズよりpeerのウインドウサイズが小さければ修正 00639 if(i_inst->uip_connr.peer_win<s){ 00640 s=i_inst->uip_connr.peer_win; 00641 } 00642 //送信サイズより、データサイズが小さければ、送信サイズを修正 00643 if(i_len<s){ 00644 s=i_len; 00645 } 00646 //ACK番号の計算 00647 next_ack=i_inst->uip_connr.snd_nxt32+s+(((i_tcpf&(TCP_FIN|TCP_SYN))!=0x00)?1:0); 00648 txq->rto32=i_inst->uip_connr.current_rto32; 00649 txq->tick_of_sent=NyLPC_cStopwatch_now(); 00650 00651 //パケットの書き込み 00652 setTxPacket(i_inst,buf,i_tcpf,i_buf,s); 00653 txq->packet=buf; 00654 00655 //シーケンス番号の更新 00656 i_inst->uip_connr.snd_nxt32=next_ack; 00657 //Peerのウインドウサイズを更新 00658 i_inst->uip_connr.peer_win-=s; 00659 //ACK番号の返却 00660 *o_ack=txq->ackno=NyLPC_HTONL(next_ack); 00661 unlockResource(i_inst); 00662 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf); 00663 return s; 00664 } 00665 /** 00666 * RSTを1フレームだけ送信します。 00667 * この関数は、クローズドステータスのソケットにしてからコールします。 00668 * この関数は、アンロック状態でコールしてね。 00669 */ 00670 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst) 00671 { 00672 void* buf; 00673 00674 NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED); 00675 //ペイロードライタの初期化 00676 00677 //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。 00678 buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf(); 00679 lockResource(i_inst); 00680 i_inst->uip_connr.snd_nxt32++; 00681 unlockResource(i_inst); 00682 setTxPacket(i_inst,buf,TCP_RST|TCP_ACK,NULL,0); 00683 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf); 00684 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf); 00685 NyLPC_cIPv4Payload_finalize(&ipv4); 00686 return; 00687 } 00688 00689 00690 00691 /** 00692 * 受信データをバッファに書き込む。 00693 * 十分な空き領域がない場合、失敗する。 00694 * この関数は、ロックして実行してください。 00695 */ 00696 static NyLPC_TBool addRecvData(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const void* i_data,NyLPC_TUInt16 i_data_size) 00697 { 00698 //受信データサイズを確認 00699 if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))>=i_data_size){ 00700 //バッファに格納可能なら、格納。 00701 NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),i_data,i_data_size); 00702 }else{ 00703 //エラー:ドロップする。 00704 return NyLPC_TBool_FALSE; 00705 } 00706 00707 return NyLPC_TBool_TRUE; 00708 } 00709 00710 00711 00712 00713 00714 /** 00715 * Public function 00716 */ 00717 static void finalize(NyLPC_TiTcpSocket_t* i_inst) 00718 { 00719 int i; 00720 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00721 NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService()); 00722 //開放漏れの保険 00723 if(inst->txbuf.rp!=inst->txbuf.wp){ 00724 lockResource(inst); 00725 resetTxQWithUnlock(inst); 00726 } 00727 for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){ 00728 inst->txbuf.txq[i].packet=NULL; 00729 } 00730 NyLPC_cFifoBuffer_finalize(&(inst->rxbuf)); 00731 // NyLPC_cMutex_finalize(&(i_inst->_smutex)); 00732 NyLPC_cMiMicIpNetIf_releaseTcpSocketMemory(inst); 00733 00734 return; 00735 } 00736 00737 static NyLPC_TBool connect(NyLPC_TiTcpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_peer_port,NyLPC_TUInt32 i_wait_in_msec) 00738 { 00739 volatile NyLPC_TUInt8 f; 00740 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00741 NyLPC_TUInt32 sq; 00742 NyLPC_TcStopwatch_t sw; 00743 NyLPC_TUInt16 lport; 00744 lockResource(inst); 00745 //ソケットが無効であること。 00746 if(inst->tcpstateflags!=UIP_CLOSED) 00747 { 00748 NyLPC_OnErrorGoto(Error); 00749 } 00750 //ポート番号の取得(lockResourceが他のソケットと共有なので、重複ポートの割当は起こりえない。でもちょっと注意して) 00751 lport=NyLPC_htons(NyLPC_cIPv4_getNewPortNumber(inst->_parent_ipv4)); 00752 if(lport==0){ 00753 NyLPC_OnErrorGoto(Error); 00754 } 00755 //connectの為の準備 00756 00757 //localipとdefault_mmsは別枠で設定 00758 /* Fill in the necessary fields for the new connection. */ 00759 inst->uip_connr.current_rto32 = UIP_TCP_RTO_CONNECTION_INITIAL;//RTOを短くしてARP発行時の再接続短縮を期待する。 00760 inst->uip_connr.lport = lport; 00761 inst->uip_connr.rport = NyLPC_htons(i_peer_port); 00762 inst->uip_connr.ripaddr=*i_addr; 00763 inst->uip_connr.snd_nxt32=iss32;//should be random 00764 /* rcv_nxt should be the seqno from the incoming packet + 1. */ 00765 inst->uip_connr.rcv_nxt32=0; 00766 //MSSの設定 00767 inst->uip_connr.peer_mss=inst->uip_connr.default_mss; 00768 inst->uip_connr.peer_win=1;//periodicの再送信を期待するために相手のWindowサイズは1と仮定する。 00769 NyLPC_cFifoBuffer_clear(&(inst->rxbuf)); 00770 //ここでステータスがかわる。 00771 inst->tcpstateflags = UIP_SYN_SENT; 00772 //前回のデータが残っていた場合の保険 00773 if(inst->txbuf.rp!=inst->txbuf.wp){ 00774 resetTxQWithUnlock(inst); 00775 }else{ 00776 unlockResource(inst); 00777 } 00778 00779 NyLPC_cStopwatch_initialize(&sw); 00780 00781 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec); 00782 if(sendWithRetransmit(inst,TCP_SYN,NULL,0,&sw,&sq)==0){ 00783 //ちょっと待つ。 00784 NyLPC_cThread_yield(); 00785 //キューにあるTXが消えるのを待つ。 00786 if(waitForTxRemove(inst,sq,&sw)){ 00787 //ACK受信に成功して、TXが消失 00788 NyLPC_cStopwatch_finalize(&sw); 00789 return NyLPC_TBool_TRUE; 00790 } 00791 } 00792 //ロックして、強制的なステータス遷移 00793 lockResource(inst); 00794 f=inst->tcpstateflags; 00795 if(f!=UIP_CLOSED){ 00796 //もし、強制CLOSE遷移であれば、RSTも送信。 00797 inst->tcpstateflags=UIP_CLOSED; 00798 unlockResource(inst); 00799 sendRst(inst); 00800 }else{ 00801 unlockResource(inst); 00802 } 00803 return NyLPC_TBool_FALSE; 00804 Error: 00805 unlockResource(inst); 00806 return NyLPC_TBool_FALSE; 00807 } 00808 00809 /** 00810 * この関数は、UIP_SYN_RCVDステータスのソケットを、ESTABLISHEDへ遷移させます。 00811 * cTcpListener_listen関数を通過したインスタンスに実行してください。 00812 * この関数は、アプリケーションが呼び出します。 00813 * @return 00814 * 00815 */ 00816 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec) 00817 { 00818 volatile NyLPC_TUInt8 f; 00819 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00820 NyLPC_TUInt32 sq; 00821 NyLPC_TcStopwatch_t sw; 00822 00823 NyLPC_cStopwatch_initialize(&sw); 00824 //ステータスチェック 00825 f=inst->tcpstateflags; 00826 switch(f) 00827 { 00828 case UIP_ESTABLISHED: 00829 return NyLPC_TBool_TRUE; 00830 case UIP_SYN_RCVD: 00831 //処理対象 00832 break; 00833 default: 00834 return NyLPC_TBool_FALSE; 00835 } 00836 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec); 00837 if(sendWithRetransmit(inst,TCP_SYN|TCP_ACK,NULL,0,&sw,&sq)==0){ 00838 //ちょっと待つ。 00839 NyLPC_cThread_yield(); 00840 //キューにあるTXが消えるのを待つ。 00841 if(waitForTxRemove(inst,sq,&sw)){ 00842 //ACK受信に成功して、TXが消失 00843 NyLPC_cStopwatch_finalize(&sw); 00844 return NyLPC_TBool_TRUE; 00845 } 00846 } 00847 //ロックして、強制的なステータス遷移 00848 lockResource(inst); 00849 f=inst->tcpstateflags; 00850 if(f!=UIP_CLOSED){ 00851 //もし、強制CLOSE遷移であれば、RSTも送信。 00852 inst->tcpstateflags=UIP_CLOSED; 00853 unlockResource(inst); 00854 sendRst(inst); 00855 }else{ 00856 unlockResource(inst); 00857 } 00858 return NyLPC_TBool_FALSE; 00859 } 00860 00861 00862 /** 00863 * この関数は、ソケットの受信バッファの読み取り位置と、読み出せるデータサイズを返却します。 00864 * 関数はポインターを返却するだけで、バッファの読み取り位置をシークしません。 00865 * シークするにはNyLPC_cTcpSocket_pseekを使います。 00866 */ 00867 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec) 00868 { 00869 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00870 volatile NyLPC_TUInt8 st; 00871 NyLPC_TUInt16 rlen; 00872 //タイマを生成 00873 NyLPC_TcStopwatch_t sw; 00874 NyLPC_cStopwatch_initialize(&sw); 00875 00876 //ESTABLISHED以外の場合は、エラー。 00877 NyLPC_cStopwatch_setNow(&sw); 00878 do{ 00879 //読み出しバッファ情報のコピー 00880 //MUTEX LOCK 00881 lockResource(inst); 00882 st=inst->tcpstateflags; 00883 rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf)); 00884 *o_buf_ptr=NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf)); 00885 //MUTEX UNLOCK 00886 unlockResource(inst); 00887 00888 //バッファが空の場合は、ステータスチェック。ESTABLISHEDでなければ、エラー(PASVCLOSE等の場合) 00889 switch(st){ 00890 case UIP_ESTABLISHED: 00891 if(rlen>0){ 00892 //バッファにパケットがあれば返却 00893 NyLPC_cStopwatch_finalize(&sw); 00894 return rlen; 00895 } 00896 break; 00897 case UIP_CLOSE_WAIT: 00898 if(rlen>0){ 00899 //バッファにパケットがあれば返却 00900 NyLPC_cStopwatch_finalize(&sw); 00901 return rlen; 00902 } 00903 //引き続きエラー処理 00904 default: 00905 //他の場合はエラー 00906 NyLPC_cStopwatch_finalize(&sw); 00907 return -1; 00908 } 00909 //タスクスイッチ 00910 NyLPC_cThread_yield(); 00911 }while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec); 00912 //規定時間内に受信が成功しなかった。 00913 NyLPC_cStopwatch_finalize(&sw); 00914 return 0; 00915 } 00916 /** 00917 * 受信バッファをシークします。 00918 * シーク後に、遅延ACKを送出します。 00919 */ 00920 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek) 00921 { 00922 void* buf; 00923 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00924 00925 NyLPC_ArgAssert(i_seek<=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf))); 00926 if(i_seek==0){ 00927 return; 00928 } 00929 00930 //ACK送信バッファの取得 00931 buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf(); 00932 00933 //MUTEX LOCK 00934 lockResource(inst); 00935 00936 //受信バッファを読み出しシーク 00937 NyLPC_cFifoBuffer_pop(&(inst->rxbuf),i_seek); 00938 //ACKパケットの生成 00939 setTxPacket(inst,buf,TCP_ACK,NULL,0); 00940 unlockResource(inst); 00941 //ACK送信 00942 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf); 00943 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf); 00944 00945 } 00946 00947 /** 00948 * See header file. 00949 */ 00950 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec) 00951 { 00952 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 00953 00954 NyLPC_TUInt16 s; 00955 void* buf; 00956 NyLPC_TcStopwatch_t sw; 00957 00958 NyLPC_cStopwatch_initialize(&sw); 00959 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec); 00960 00961 //送信バッファを取得 00962 //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。 00963 for(;;){ 00964 //ESTABLISHED以外に非同期遷移 00965 if(inst->tcpstateflags!=UIP_ESTABLISHED){ 00966 NyLPC_cStopwatch_finalize(&sw); 00967 return NULL; 00968 } 00969 buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_TCPIP_HEADER),&s); 00970 if(buf!=NULL){ 00971 break; 00972 } 00973 //タイムアウト時もエラー 00974 if(NyLPC_cStopwatch_isExpired(&sw)){ 00975 NyLPC_cStopwatch_finalize(&sw); 00976 return NULL; 00977 } 00978 } 00979 00980 //@todo 前段処理と順番を入れ替えて、要求サイズとpeerのwinのうち、小さいほうを割り当てたほうが良くない? 00981 //ここで相手のwin待ちをする理由は、相手に確実に受け取れるサイズを決定する為。 00982 lockResource(inst); 00983 //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。 00984 while(inst->uip_connr.peer_win==0){ 00985 unlockResource(inst); 00986 //ESTABLISHED以外に非同期遷移 orタイムアウト確認 00987 if(NyLPC_cStopwatch_isExpired(&sw)||(inst->tcpstateflags!=UIP_ESTABLISHED)){ 00988 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf); 00989 NyLPC_cStopwatch_finalize(&sw); 00990 return NULL; 00991 } 00992 NyLPC_cThread_yield(); 00993 lockResource(inst); 00994 } 00995 //送信バッファを基準とした送信サイズを計算 00996 s-=SIZE_OF_IPv4_TCPIP_HEADER; 00997 //送信サイズよりMMSが小さければ、送信サイズを修正 00998 if(inst->uip_connr.peer_mss<s){ 00999 s=inst->uip_connr.peer_mss; 01000 } 01001 //送信サイズよりpeerのウインドウサイズが小さければ修正 01002 if(inst->uip_connr.peer_win<s){ 01003 s=inst->uip_connr.peer_win; 01004 } 01005 unlockResource(inst); 01006 //バッファサイズ確定。 01007 *o_buf_size=s; 01008 NyLPC_cStopwatch_finalize(&sw); 01009 return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_TCPIP_HEADER; 01010 } 01011 /** 01012 * See Header file. 01013 */ 01014 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr) 01015 { 01016 NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER); 01017 } 01018 01019 01020 /** 01021 * 事前にAllocしたTxパケットを送信します。 01022 * このAPIはゼロコピー送信をサポートするためのものです。 01023 * @param i_buf_ptr 01024 * allocSendBufで取得したメモリを指定します。 01025 * @return 01026 * 関数が失敗した場合、i_buf_ptrは「開放されません。」 01027 */ 01028 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec) 01029 { 01030 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 01031 struct NyLPC_TcTcpSocket_TxQItem* txq; 01032 void* buf; 01033 NyLPC_TcStopwatch_t sw; 01034 //ESTABLISHEDでなければエラー 01035 if(inst->tcpstateflags!=UIP_ESTABLISHED){ 01036 //ESTABLISHEDでなければエラー 01037 return NyLPC_TBool_FALSE; 01038 } 01039 //送信データ0なら何もしない。 01040 if(i_len<1){ 01041 releaseSendBuf(i_inst,i_buf_ptr); 01042 return NyLPC_TBool_TRUE; 01043 } 01044 NyLPC_cStopwatch_initialize(&sw); 01045 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec); 01046 01047 //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定 01048 buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER; 01049 lockResource(inst); 01050 //送信キューの取得 01051 txq=getTxQ(inst,&sw); 01052 //送信キューが取れなかった。 01053 if(txq==NULL){ 01054 //シーケンス番号をロールバックできないので、エラーとする。 01055 unlockResource(inst); 01056 NyLPC_cStopwatch_finalize(&sw); 01057 return NyLPC_TBool_FALSE; 01058 } 01059 //ここから先はi_bufの所有権はインスタンスになってる。 01060 01061 //IPv4ペイロードの書き込み 01062 01063 //allocをした時点でwin,mssは考慮されているので、そのままそうしんしる。 01064 01065 //ACK番号の計算 01066 txq->rto32=inst->uip_connr.current_rto32; 01067 txq->tick_of_sent=NyLPC_cStopwatch_now(); 01068 //パケットヘッダの生成(ヘッダ長はpreadで定義した値(4+6)*4=40です。) 01069 setTxPacketHeader(inst,buf,TCP_ACK|TCP_PSH,i_len); 01070 txq->packet=buf; 01071 01072 //シーケンス番号の更新 01073 inst->uip_connr.snd_nxt32=inst->uip_connr.snd_nxt32+i_len; 01074 //Peerのウインドウサイズを更新 01075 inst->uip_connr.peer_win-=i_len; 01076 //ACK番号の返却 01077 txq->ackno=NyLPC_HTONL(inst->uip_connr.snd_nxt32); 01078 unlockResource(inst); 01079 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf); 01080 NyLPC_cStopwatch_finalize(&sw); 01081 return NyLPC_TBool_TRUE; 01082 } 01083 01084 /** 01085 * See header file. 01086 */ 01087 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec) 01088 { 01089 NyLPC_TInt16 hint; 01090 NyLPC_TUInt16 s; 01091 void* buf; 01092 if(i_len<1){ 01093 return 0; 01094 } 01095 hint=(i_len>32767)?32767:i_len; 01096 buf=allocSendBuf(i_inst,hint,&s,i_wait_in_msec); 01097 if(buf==NULL){ 01098 return -1; 01099 } 01100 //送信サイズの計算 01101 s=((NyLPC_TInt32)s<i_len)?s:(NyLPC_TUInt16)i_len; 01102 memcpy(buf,i_buf_ptr,s); 01103 if(!psend(i_inst,buf,s,i_wait_in_msec)){ 01104 releaseSendBuf(i_inst,buf); 01105 return -1;//error 01106 } 01107 return s; 01108 } 01109 01110 01111 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec) 01112 { 01113 NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst; 01114 NyLPC_TcStopwatch_t sw; 01115 volatile NyLPC_TUInt8 f; 01116 NyLPC_TUInt32 sq; 01117 NyLPC_cStopwatch_initialize(&sw); 01118 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec); 01119 lockResource(inst); 01120 01121 f=inst->tcpstateflags; 01122 //ステータスチェック 01123 switch(f) 01124 { 01125 case UIP_CLOSED: 01126 //閉じている。 01127 goto ReturnWithUnlock; 01128 case UIP_ESTABLISHED: 01129 //アクティブクローズ。 01130 inst->tcpstateflags=UIP_FIN_WAIT_1; 01131 //送信のために一旦解除 01132 unlockResource(inst); 01133 //FINの送信 01134 if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){ 01135 //ちょっと待つ。 01136 NyLPC_cThread_yield(); 01137 //TXの消去待ち 01138 if(waitForTxRemove(inst,sq,&sw)){ 01139 //再ロック 01140 lockResource(inst); 01141 //タイムアウトするか、UIP_CLOSED、もしくはTIME_WAITに遷移するのを待つ。(遷移はRxprocで自動的に実行。) 01142 do{ 01143 switch(inst->tcpstateflags) 01144 { 01145 case UIP_TIME_WAIT: 01146 inst->tcpstateflags=UIP_CLOSED; 01147 case UIP_CLOSED: 01148 NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp); 01149 //成功。 01150 goto ReturnWithUnlock; 01151 case UIP_FIN_WAIT_1: 01152 case UIP_FIN_WAIT_2: 01153 case UIP_CLOSING: 01154 //一時的なアンロック 01155 unlockResource(inst); 01156 NyLPC_cThread_yield(); 01157 lockResource(inst); 01158 default: 01159 break; 01160 } 01161 }while(!NyLPC_cStopwatch_isExpired(&sw)); 01162 unlockResource(inst); 01163 } 01164 } 01165 break; 01166 case UIP_CLOSE_WAIT: 01167 //LAST_ACKへ遷移 01168 inst->tcpstateflags=UIP_LAST_ACK; 01169 //送信のために一旦解除 01170 unlockResource(inst); 01171 if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){ 01172 //ちょっと待つ。 01173 NyLPC_cThread_yield(); 01174 //TXの消去待ち 01175 if(waitForTxRemove(inst,sq,&sw)){ 01176 //再ロック 01177 lockResource(inst); 01178 //TX消去後にCLOSEDに遷移していればOK 01179 if(inst->tcpstateflags==UIP_CLOSED) 01180 { 01181 NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp); 01182 goto ReturnWithUnlock; 01183 } 01184 unlockResource(inst); 01185 } 01186 } 01187 //エラー。RSTで切断。 01188 break; 01189 default: 01190 unlockResource(inst); 01191 NyLPC_Warning(); 01192 break; 01193 } 01194 // if(i_inst->_smutex._lock_count>0){ 01195 // NyLPC_Warning(); 01196 // } 01197 //このパスに到達するのは、FIN送信/ACKに成功したにも拘らず、規定時間内にCLOSEDに遷移しなかった場合。 01198 //コネクションを強制遷移して、RST 01199 lockResource(inst); 01200 f=inst->tcpstateflags; 01201 if(f!=UIP_CLOSED){ 01202 //もし、強制CLOSE遷移であれば、RSTも送信。 01203 inst->tcpstateflags=UIP_CLOSED; 01204 unlockResource(inst); 01205 sendRst(inst); 01206 }else{ 01207 unlockResource(inst); 01208 } 01209 NyLPC_cStopwatch_finalize(&sw); 01210 return; 01211 ReturnWithUnlock: 01212 unlockResource(inst); 01213 NyLPC_cStopwatch_finalize(&sw); 01214 return; 01215 } 01216 01217 /** 01218 * uipサービスタスクが実行する関数です。 01219 * 定期的に実行する関数。最低でも1s単位で実行してください。 01220 */ 01221 void NyLPC_cMiMicIpTcpSocket_periodic( 01222 NyLPC_TcMiMicIpTcpSocket_t* i_inst) 01223 { 01224 int i; 01225 struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq; 01226 NyLPC_TcStopwatch_t sw; 01227 NyLPC_TUInt32 now; 01228 int rp; 01229 NyLPC_cStopwatch_initialize(&sw); 01230 now=NyLPC_cStopwatch_now(); 01231 //MUTEX LOCK 01232 lockResource(i_inst); 01233 if(i_inst->tcpstateflags==UIP_CLOSED) 01234 { 01235 //CLOSEDなら、バッファ開放。 01236 resetTxQWithUnlock(i_inst); 01237 }else if(i_inst->txbuf.rp==i_inst->txbuf.wp){ 01238 //再送信パケットがなければ何もしないよ。 01239 unlockResource(i_inst); 01240 }else if(i_inst->uip_connr.peer_win==0){ 01241 //peer_winが0の場合は何もしない。 01242 unlockResource(i_inst); 01243 }else{ 01244 //再送信処理 01245 rp=i_inst->txbuf.rp; 01246 NyLPC_cStopwatch_set(&sw,q[rp].tick_of_sent); 01247 if(NyLPC_cStopwatch_elapseInMsec(&sw)>q[rp].rto32){ 01248 //最古のパケットの送信時間をチェックして、タイムアウトが発生したら、再送時間と送信時刻をセット 01249 //最古パケットRTOを2倍。 01250 q[rp].rto32*=2; 01251 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){ 01252 q[i].tick_of_sent=now; 01253 } 01254 if(q[rp].rto32>UIP_IP_RTO_MAX_RTO){ 01255 //最古のRTOが64秒を超えたら、CLOSED 01256 i_inst->tcpstateflags =UIP_CLOSED; 01257 resetTxQWithUnlock(i_inst); 01258 sendRst(i_inst); 01259 }else{ 01260 //規定時間内なら、再送処理 01261 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){ 01262 // NyLPC_cUipService_sendIPv4Tx(NyLPC_cIPv4Payload_getBuf(&(q[i].data))); 01263 NyLPC_cMiMicIpNetIf_sendIPv4Tx(q[i].packet); 01264 } 01265 unlockResource(i_inst); 01266 } 01267 }else{ 01268 unlockResource(i_inst); 01269 } 01270 } 01271 NyLPC_cStopwatch_finalize(&sw); 01272 return; 01273 } 01274 /** 01275 * uipサービスタスクが実行する関数です。 01276 * サービスの開始を通知します。 01277 */ 01278 void NyLPC_cMiMicIpTcpSocket_startService(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config) 01279 { 01280 NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);//閉じてなければおかしい。 01281 i_inst->uip_connr.lipaddr=&(i_config->ip_addr); 01282 i_inst->uip_connr.default_mss=i_config->default_mss; 01283 //NyLPC_cTcpSocket_setSynPayload関数でも実行するけど、IFのリセット時なのでここでもやる。 01284 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf)); 01285 return; 01286 } 01287 /** 01288 * uipサービスタスクが実行する関数です。 01289 * サービスの停止を通知します。 01290 */ 01291 void NyLPC_cMiMicIpTcpSocket_stopService(NyLPC_TcMiMicIpTcpSocket_t* i_inst) 01292 { 01293 lockResource(i_inst); 01294 if(i_inst->tcpstateflags==UIP_CLOSED) 01295 { 01296 unlockResource(i_inst); 01297 }else{ 01298 i_inst->tcpstateflags=UIP_CLOSED; 01299 resetTxQWithUnlock(i_inst); 01300 sendRst(i_inst); 01301 } 01302 return; 01303 } 01304 01305 01306 void* NyLPC_cMiMicIpTcpSocket_parseRx( 01307 NyLPC_TcMiMicIpTcpSocket_t* i_inst, 01308 const NyLPC_TcIPv4Payload_t* i_ipp) 01309 { 01310 int i,s; 01311 NyLPC_TUInt16 tmp16; 01312 NyLPC_TUInt16 data_size; 01313 NyLPC_TUInt8 in_tcpflag=i_ipp->payload.tcp->flags; 01314 const void* tcp_data_offset; 01315 NyLPC_TBool is_new_packet; 01316 int num_of_noack; 01317 void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ]; 01318 void* ret; 01319 01320 //パラメータの計算 01321 01322 tmp16=NyLPC_TTcpHeader_getHeaderLength(i_ipp->payload.tcp); 01323 //TCPペイロードの長さは、IPパケットの長さ-(IPヘッダ+TCPヘッダ) 01324 data_size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16; 01325 //TCPデータオフセット 01326 tcp_data_offset=i_ipp->payload.rawbuf+tmp16; 01327 01328 //インスタンスをロックする。 01329 lockResource(i_inst); 01330 01331 //RSTのチェック。RST受信時は、状態にかかわらず、CLOSEDステータスに移行する。 01332 if (in_tcpflag & TCP_RST) 01333 { 01334 i_inst->tcpstateflags =UIP_CLOSED; 01335 goto DROP; 01336 } 01337 01338 01339 is_new_packet=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)==i_inst->uip_connr.rcv_nxt32; 01340 01341 01342 //OPTIONの反映 01343 01344 //MSSの取得 01345 if(NyLPC_TTcpHeader_getTcpMmsOpt(i_ipp->payload.tcp,&tmp16)){ 01346 //取得で着たら更新 01347 i_inst->uip_connr.peer_mss=tmp16; 01348 } 01349 //受信パケットを元に、未ACKパケットの数を計算 01350 num_of_noack=getNumOfSending(i_inst,i_ipp->payload.tcp->ackno32);//i_inst->txbuf.num_of_txq; 01351 01352 //ステータス毎のACK応答 01353 switch(i_inst->tcpstateflags) 01354 { 01355 case UIP_SYN_RCVD: 01356 //ACKを受信したら、ESTABLISHEDへ。 01357 //すべてのパケットをACKしたかで判定。() 01358 if(num_of_noack==0){ 01359 i_inst->tcpstateflags=UIP_ESTABLISHED; 01360 }else{ 01361 //それ以外のパケットはドロップする。 01362 break;//goto DROP; 01363 } 01364 //新しいパケットがなければ、無応答 01365 if(!is_new_packet){ 01366 break;//goto DROP; 01367 } 01368 //引き続き、ESTABLISHEDの処理へ。 01369 case UIP_ESTABLISHED: 01370 if(data_size>0){ 01371 if(is_new_packet){ 01372 if(addRecvData(i_inst,tcp_data_offset,data_size)){ 01373 //通常のACK返却 01374 i_inst->uip_connr.rcv_nxt32+=data_size; 01375 }else{ 01376 //失敗したときは必要に応じて単純ACK 01377 } 01378 } 01379 } 01380 //どちらにしろ、ACK送信 01381 if(is_new_packet && (in_tcpflag & TCP_FIN)){ 01382 //FINがあるときは、ステータスをCLOSE_WAITへセットして、ACKを返す。 01383 i_inst->tcpstateflags = UIP_CLOSE_WAIT; 01384 i_inst->uip_connr.rcv_nxt32++; 01385 } 01386 break; 01387 case UIP_CLOSE_WAIT: 01388 //必要に応じたACK応答 01389 break; 01390 case UIP_LAST_ACK: 01391 //ACK(by FIN)が得られたなら、CLOSEDへ。 01392 if(num_of_noack==0){ 01393 i_inst->tcpstateflags=UIP_CLOSED; 01394 } 01395 //必要に応じたACK応答 01396 break; 01397 case UIP_FIN_WAIT_1: 01398 //FIN受信->CLOSINGへ 01399 if(is_new_packet){ 01400 i_inst->uip_connr.rcv_nxt32+=data_size; 01401 if(in_tcpflag & TCP_FIN){ 01402 i_inst->uip_connr.rcv_nxt32++; 01403 if(num_of_noack==0){ 01404 //FINとACKを受信 01405 i_inst->tcpstateflags=UIP_TIME_WAIT; 01406 }else{ 01407 //FINのみ 01408 i_inst->tcpstateflags=UIP_CLOSING; 01409 } 01410 } 01411 }else if(num_of_noack==0){ 01412 //ACKのみ 01413 i_inst->tcpstateflags=UIP_FIN_WAIT_2; 01414 } 01415 //必要に応じたACK応答 01416 break; 01417 case UIP_FIN_WAIT_2: 01418 //FIN受信->TIME_WAITへ(pureACK) 01419 if(is_new_packet && (in_tcpflag & TCP_FIN)){ 01420 i_inst->uip_connr.rcv_nxt32++; 01421 i_inst->tcpstateflags=UIP_TIME_WAIT; 01422 } 01423 break; 01424 case UIP_CLOSING: 01425 //ACK受信したら、TIME_WAITへ 01426 if(num_of_noack==0){ 01427 i_inst->tcpstateflags=UIP_TIME_WAIT; 01428 } 01429 break; 01430 case UIP_CLOSED: 01431 //何もできない。何もしない。 01432 break; 01433 case UIP_TIME_WAIT: 01434 //最終ACKを送り続ける。 01435 break; 01436 case UIP_SYN_SENT: 01437 //connect関数実行中しか起動しないステータス 01438 if(num_of_noack==0){ 01439 i_inst->tcpstateflags=UIP_ESTABLISHED; 01440 i_inst->uip_connr.rcv_nxt32=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)+1; 01441 }else{ 01442 //それ以外のパケットはドロップする。 01443 break;//goto DROP; 01444 } 01445 //ACKを送る。 01446 break; 01447 default: 01448 goto DROP; 01449 } 01450 //ウインドウサイズを更新 01451 i_inst->uip_connr.peer_win=NyLPC_ntohs(i_ipp->payload.tcp->wnd16); 01452 01453 //送信キューから、Peerが受信したデータを削除する。 01454 if(in_tcpflag & TCP_ACK){ 01455 //再送パケットキューから送信済みのデータを回収(後で開放) 01456 NyLPC_Trace(); 01457 s=updateTxQByIndex(i_inst,i_ipp->payload.tcp->ackno32,dlist); 01458 NyLPC_Trace(); 01459 }else{ 01460 s=0; 01461 } 01462 //新しいパケットがきた場合は、再送キューのACKを更新する。 01463 if(is_new_packet){ 01464 //再送キューのACKを更新 01465 updateTxAck(i_inst,NyLPC_htonl(i_inst->uip_connr.rcv_nxt32)); 01466 } 01467 01468 //送信キューのない 01469 if(((in_tcpflag&(TCP_FIN|TCP_SYN))!=0x00) || 01470 ((!is_new_packet) && (data_size>0))) 01471 { 01472 //ソケットからPureACKを生成 as setPacket(i_inst,i_ipp,TCP_ACK,NULL,0); 01473 ret=NyLPC_cMiMicIpNetIf_allocSysTxBuf(); 01474 setTxPacket(i_inst,ret,TCP_ACK,NULL,0); 01475 }else{ 01476 ret=NULL; 01477 } 01478 unlockResource(i_inst); 01479 //取り外したTXメモリの開放 01480 for(i=0;i<s;i++){ 01481 //取り外したTXメモリを開放 01482 NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]); 01483 } 01484 NyLPC_Trace(); 01485 return ret; 01486 DROP: 01487 //ACKしたパケットを送信キューから削除 01488 unlockResource(i_inst); 01489 NyLPC_Trace(); 01490 return NULL; 01491 } 01492 01493 01494 /** 01495 * 入力されたパケットからRSTパケットを生成して返す。 01496 */ 01497 void* NyLPC_cMiMicIpTcpSocket_allocTcpReverseRstAck( 01498 const NyLPC_TcIPv4Payload_t* i_src) 01499 { 01500 struct NyLPC_TIPv4Header* iph; 01501 struct NyLPC_TTcpHeader* tcph; 01502 NyLPC_TUInt8 iph_word=0x05; 01503 NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4; 01504 void* txb=NyLPC_cMiMicIpNetIf_allocSysTxBuf(); 01505 //IPヘッダの更新 01506 iph=(struct NyLPC_TIPv4Header*)txb; 01507 iph->vhl=0x40|(0x0f&iph_word); 01508 iph->destipaddr=i_src->header->srcipaddr; 01509 iph->srcipaddr =i_src->header->destipaddr; 01510 NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP); 01511 01512 //TCPヘッダの更新 01513 tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)txb)+NyLPC_TIPv4Header_getHeaderLength(iph)); 01514 01515 tcph->tcpoffset=(tcph_word<<4); 01516 01517 tcph->flags = TCP_RST | TCP_ACK; 01518 //sorce & destination port 01519 tcph->srcport = i_src->payload.tcp->destport; 01520 tcph->destport = i_src->payload.tcp->srcport; 01521 //ACK number 01522 tcph->ackno32 = NyLPC_htonl(NyLPC_ntohl(i_src->payload.tcp->seqno32)+1); 01523 //Seq Number 01524 tcph->seqno32 = i_src->payload.tcp->ackno32; 01525 //uip_func_tcp_send_noconn(BUF); 01526 tcph->urgp[0] = tcph->urgp[1] = 0; 01527 tcph->tcpchksum= 0; 01528 01529 01530 //最終的なパケットサイズと必要ならペイロードを書き込み 01531 iph->len16=NyLPC_htons((iph_word+tcph_word)*4); 01532 //WND設定 01533 tcph->wnd16=0; 01534 //Checksumの生成 01535 tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph)); 01536 iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph)); 01537 return txb; 01538 } 01539 01540 01541 01542
Generated on Tue Jul 12 2022 16:22:58 by
