This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088
Dependents: MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more
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 15:46:16 by 1.7.2