OSDN Git Service

update libMiMic
[mimic/MiMicSDK.git] / lib / src / netif / mimicip / NyLPC_cMiMicIpTcpSocket.c
1 /*********************************************************************************
2  * PROJECT: MiMic
3  * --------------------------------------------------------------------------------
4  *
5  * This file is part of MiMic
6  * Copyright (C)2011 Ryo Iizuka
7  *
8  * MiMic is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  * For further information please contact.
22  *  http://nyatla.jp/
23  *  <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
24  *
25  *********************************************************************************/
26 #include "NyLPC_cMiMicIpTcpSocket_protected.h"
27 #include "NyLPC_stdlib.h"
28 #include "NyLPC_cMiMicIpNetIf_protected.h"
29
30
31 static NyLPC_TUInt32 iss32=3939;
32 #define SIZE_OF_IPv4_TCPIP_HEADER 40
33
34 /**
35  * TCPのRTOの最大値。
36  * ms単位である。
37  * defaultは64SEC
38  */
39 #define UIP_IP_RTO_MAX_RTO 64000
40 /**
41  * TCPのRTOの初期値。
42  * ms単位である。
43  * 伝送路の特性に合わせて調整すること。
44  */
45 #define UIP_TCP_RTO_INITIAL 3000
46
47 /**
48  * CONNECTION時のRTO
49  */
50 #define UIP_TCP_RTO_CONNECTION_INITIAL 200
51
52 /**
53  * 下限値
54  */
55 #define UIP_TCP_RTO_MINIMUM 100
56
57
58 /**
59  * for Debug
60  * RTOの情報をログ領域に取る。
61  */
62 #ifdef RTO_LOG
63     NyLPC_TUInt32 rto_log[256];
64     int rto_log_st=0;
65     #define DEBUG_RTO_LOG(i_inst) if(rto_log_st<256){rto_log[rto_log_st++]=i_inst->uip_connr.current_rto32;};
66 #else
67     #define DEBUG_RTO_LOG(i_inst)
68 #endif
69
70 //#define lockResource(i_inst) NyLPC_cMutex_lock(&((i_inst)->_smutex))
71 //#define unlockResource(i_inst) NyLPC_cMutex_unlock(&((i_inst)->_smutex))
72 #define lockResource(i_inst) NyLPC_cMutex_lock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4)))
73 #define unlockResource(i_inst) NyLPC_cMutex_unlock(NyLPC_cIPv4_getSockMutex(((i_inst)->_parent_ipv4)))
74
75 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst);
76
77
78
79
80 ////////////////////////////////////////////////////////////////////////////////////////////////////
81 //
82 //  Packet writer
83 //
84 ////////////////////////////////////////////////////////////////////////////////////////////////////
85
86
87 /**
88  * TCPヘッダに値をセットする。checksum,wndは0初期化する。
89  */
90 static void setTcpTxHeader(struct NyLPC_TTcpHeader* i_struct,NyLPC_TUInt8 i_flag,const struct uip_conn* i_conn)
91 {
92     i_struct->flags    = i_flag;
93     //sorce & destination port
94     i_struct->srcport  = i_conn->lport;
95     i_struct->destport = i_conn->rport;
96     //ACK number
97     i_struct->ackno32  = NyLPC_htonl(i_conn->rcv_nxt32);
98     //Seq Number
99     i_struct->seqno32  = NyLPC_htonl(i_conn->snd_nxt32);
100     //uip_func_tcp_send_noconn(BUF);
101     i_struct->urgp[0]  = i_struct->urgp[1] = 0;
102     i_struct->tcpchksum= 0;
103 }
104
105 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)
106 {
107     struct NyLPC_TIPv4Header*   iph;
108     struct NyLPC_TTcpHeader*    tcph;
109     NyLPC_TUInt8 iph_word=0x05;
110     NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
111     //IPヘッダの更新
112     iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
113     iph->vhl=0x40|(0x0f&iph_word);
114     iph->destipaddr=i_inst->uip_connr.ripaddr;
115     iph->srcipaddr =*(i_inst->uip_connr.lipaddr);
116     NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
117     //TCPヘッダの更新
118     tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
119
120
121     //SYNが有るならMSSの書き込み
122     if((TCP_SYN & i_tcpf)){
123         tcph_word+=((TCP_OPT_MSS_LEN) / 4);
124         NyLPC_TTcpHeader_setMmsOpt(((NyLPC_TUInt8*)(tcph+1)),i_inst->uip_connr.default_mss);
125     }
126     tcph->tcpoffset=(tcph_word<<4);
127     setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));
128
129     //最終的なパケットサイズと必要ならペイロードを書き込み
130     if(i_buf!=NULL){
131         iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);
132         memcpy(((NyLPC_TUInt8*)i_tx_buf)+((iph_word+tcph_word)*4),i_buf,i_len);
133     }else{
134         iph->len16=NyLPC_htons((iph_word+tcph_word)*4);
135     }
136     //WND設定
137     tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
138     //Checksumの生成
139     tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
140     iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));
141     return;
142 }
143
144 /**
145  * IP/TCPヘッダが40バイト固定として、i_tx_buf+40の位置にあるペイロードに対するIP/TCPヘッダを書き込みます。
146  */
147 static void setTxPacketHeader(const NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_tx_buf,NyLPC_TUInt8 i_tcpf,NyLPC_TUInt16 i_len)
148 {
149     struct NyLPC_TIPv4Header*   iph;
150     struct NyLPC_TTcpHeader*    tcph;
151     NyLPC_TUInt8 iph_word=0x05;
152     NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
153     //IPヘッダの更新
154     iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
155     iph->vhl=0x40|(0x0f&iph_word);
156     iph->destipaddr=i_inst->uip_connr.ripaddr;
157     iph->srcipaddr =*(i_inst->uip_connr.lipaddr);
158     NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
159
160     //TCPヘッダの更新
161     tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
162     tcph->tcpoffset=(tcph_word<<4);
163     setTcpTxHeader(tcph,i_tcpf,&(i_inst->uip_connr));
164
165     //最終的なパケットサイズと必要ならペイロードを書き込み
166     iph->len16=NyLPC_htons(i_len+(iph_word+tcph_word)*4);
167     //WND設定
168     tcph->wnd16=NyLPC_htons(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf)));
169     //Checksumの生成
170     tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
171     iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));
172     return;
173 }
174
175
176
177
178
179 ////////////////////////////////////////////////////////////////////////////////////////////////////
180 //
181 //  Mainclass::private
182 //
183 ////////////////////////////////////////////////////////////////////////////////////////////////////
184
185 /**
186  * ACK番号を更新する。
187  * @param i_ackno
188  * ネットワークオーダーのACK番号
189  */
190 static void updateAckNo(void* i_tx_buf,NyLPC_TUInt32 i_ackno)
191 {
192     struct NyLPC_TIPv4Header*   iph=(struct NyLPC_TIPv4Header*)i_tx_buf;
193     struct NyLPC_TTcpHeader*    tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)i_tx_buf)+NyLPC_TIPv4Header_getHeaderLength(iph));
194
195 /*  union{
196         NyLPC_TUInt32 l;
197         NyLPC_TUInt8 b[4];
198     }old_ack,new_ack;
199     NyLPC_TUInt16 v1;
200     //checksumの計算
201     old_ack.l=i_inst->payload.tcp->ackno32;//古いACK番号
202     new_ack.l=i_ackno;//新しいACK番号
203     v1=NyLPC_ntohs(~(i_inst->payload.tcp->tcpchksum));//1の補数を取って、ホストオーダーに戻す。
204     //減算
205     v1=sub16c(v1,(old_ack.b[0]<<8)+old_ack.b[1]);
206     v1=sub16c(v1,(old_ack.b[2]<<8)+old_ack.b[3]);
207     //加算
208     v1=add16c(v1,(new_ack.b[0]<<8)+new_ack.b[1]);
209     v1=add16c(v1,(new_ack.b[2]<<8)+new_ack.b[3]);
210     v1=~NyLPC_htons(v1);*/
211 NyLPC_Trace();
212     tcph->ackno32=i_ackno;
213 NyLPC_Trace();
214     tcph->tcpchksum = 0;
215 NyLPC_Trace();
216     tcph->tcpchksum = ~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
217 NyLPC_Trace();
218
219 /*
220     if((i_inst->payload.tcp->tcpchksum!=v1)){
221         NyLPC_Warning();
222     }*/
223 }
224
225
226
227 /**
228  * 指定した送信パケットがACK済であるか調べる。
229  */
230 static NyLPC_TBool isPacketAcked(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
231 {
232     int rp;
233     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
234     rp=i_inst->txbuf.rp;
235     while(rp!=i_inst->txbuf.wp){
236         if(q[rp].ackno==i_sq){
237             return NyLPC_TBool_FALSE;
238         }
239         rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
240     }
241     return NyLPC_TBool_TRUE;
242 }
243 /**
244  * 送信キューからi_sq以前に送信したパケットを除外して、残り個数を返却する。
245  */
246 static int getNumOfSending(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq)
247 {
248     int rp,n;
249     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
250     rp=i_inst->txbuf.rp;
251     n=0;
252     while(rp!=i_inst->txbuf.wp){
253         if(q[rp].ackno==i_sq){
254             return n;
255         }
256         n++;
257         rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
258     }
259     return n;
260 }
261 /**
262  * この関数は、コネクションをリセットします。
263  * ロック状態でコールしてください。
264  * 関数は、現在バッファにある再送信待ちデータを開放します。
265  */
266 static void resetTxQWithUnlock(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
267 {
268     int i,l;
269     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
270     void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
271
272     l=0;
273     while(i_inst->txbuf.rp!=i_inst->txbuf.wp){
274         dlist[l]=q[i_inst->txbuf.rp].packet;
275         l++;
276         i_inst->txbuf.rp=(i_inst->txbuf.rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
277     }
278     i_inst->txbuf.rp=i_inst->txbuf.wp=0;
279     //ロック解除
280     unlockResource(i_inst);
281     //セーブしたバッファを開放
282     for(i=0;i<l;i++){
283         NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]);
284     }
285     return;
286 }
287 /**
288  * TXバッファの再送パケットのACK番号を更新します。
289  * ロックして実行してください。
290  * @param i_ackno
291  * ネットワークオーダーのACK番号
292  */
293 static void updateTxAck(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_ackno)
294 {
295     NyLPC_TUInt8 rp;
296     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
297     NyLPC_ArgAssert(i_inst!=NULL);
298     rp=i_inst->txbuf.rp;
299     while(rp!=i_inst->txbuf.wp){
300         updateAckNo(q[rp].packet,i_ackno);
301         rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
302     }
303 }
304
305 /**
306  * RTOの予測関数
307  */
308 static void estimateRTO(NyLPC_TcMiMicIpTcpSocket_t* i_inst,int s,int n)
309 {
310     NyLPC_TcStopwatch_t sw;
311     NyLPC_TUInt32 cr_rtt_min,cr_rtt_max,sk_rto,new_rto,w;
312     int i;
313     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
314     NyLPC_cStopwatch_initialize(&sw);
315
316     sk_rto=i_inst->uip_connr.current_rto32;
317     //ACKされたパケットの個数は?
318     switch(n){
319     case 1:
320         NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
321         cr_rtt_min=NyLPC_cStopwatch_elapseInMsec(&sw);
322         if(sk_rto<cr_rtt_min){
323             //現在のRTOよりも大きい→再送があった。(再送の理由が回線遅延によるものかわからないので、基本RTOを25%増やす。)
324             new_rto=sk_rto*10/8;
325         }else if(sk_rto/4<cr_rtt_min){
326             //現在のRTOの1/4< n < 現在のRTO 想定内の変動。1/8
327             new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
328         }else{
329             //現在の1/4以下。RTOを再計算。 RTOが大きすぎるので再計算。(計測値を優先した現在値との平均値)
330             new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
331         }
332         break;
333     default:
334         //複数のパケットなら、最大と最小の時刻を得る。
335         NyLPC_cStopwatch_set(&sw,q[s].tick_of_sent);
336         cr_rtt_min=cr_rtt_max=NyLPC_cStopwatch_elapseInMsec(&sw);
337         for(i=1;i<n;i++){
338             NyLPC_cStopwatch_set(&sw,q[(s+i)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ].tick_of_sent);
339             w=NyLPC_cStopwatch_elapseInMsec(&sw);
340             if(cr_rtt_min>w){
341                 cr_rtt_min=w;
342             }
343             if(cr_rtt_max<w){
344                 cr_rtt_max=w;
345             }
346         }
347         if(sk_rto<cr_rtt_min && sk_rto<cr_rtt_max){
348             //最大値,最小値とも現在のRTTより大きい→低速な回線を検出。
349             new_rto=cr_rtt_max*10/8;//最大経過時間の25%増しの時間を設定。
350         }else if(sk_rto/4<cr_rtt_min){
351             //現在のRTOの1/4< n < 現在のRTO 想定範囲内。1/8の加重平均で速度計算。
352             new_rto=(sk_rto+(cr_rtt_min*3*7))/8;
353         }else{
354             //現在の1/4以下。RTOが大きすぎるので再計算。(計測値を優先した加重平均)
355             new_rto=(sk_rto+(cr_rtt_min*3*3))/4;
356         }
357         break;
358     }
359     NyLPC_cStopwatch_finalize(&sw);
360     if(new_rto<UIP_TCP_RTO_MINIMUM){
361         new_rto=UIP_TCP_RTO_MINIMUM;
362     }
363     i_inst->uip_connr.current_rto32=new_rto;
364 }
365
366 /**
367  * TXキューから、入力されたシーケンス番号より前のパケットを除外します。
368  * リングバッファのrp->wp-1までをチェックして、sqに等しいi_sq以前のパケットバッファをo_dlistへ返します。
369  *
370  */
371 static int updateTxQByIndex(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,void* o_dlist[])
372 {
373     int rp,n;
374     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
375     //ロック状態なう
376     rp=i_inst->txbuf.rp;
377     n=0;
378     //This is debug
379     DEBUG_RTO_LOG(i_inst);
380
381     while(rp!=i_inst->txbuf.wp){
382         o_dlist[n]=q[rp].packet;
383         if(q[rp].ackno==i_sq){
384             //i_inst->txbuf.rp->rpのパケットのRTOからbaseRTOの値を再計算。
385             estimateRTO(i_inst,i_inst->txbuf.rp,n+1);
386             i_inst->txbuf.rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
387             return n+1;
388         }
389         n++;
390         rp=(rp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
391     }
392     return 0;
393 }
394
395
396
397 /**
398  * 空きキューを1個返します。
399  * 空きキューの
400  */
401 static struct NyLPC_TcTcpSocket_TxQItem* getTxQ(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TcStopwatch_t* i_timer)
402 {
403     int i;
404     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
405     do{
406         //クローズドに遷移してしまったら、エラーである。
407         if(i_inst->tcpstateflags==UIP_CLOSED){
408             return NULL;
409         }
410         //キューの空きをチェック。wp+1==rpなら、キューがいっぱい。rp==wpなら、キューが空。
411         if(((i_inst->txbuf.wp+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ)==i_inst->txbuf.rp){
412             //一時的なアンロック
413             unlockResource(i_inst);
414             //タスクスイッチ
415             NyLPC_cThread_yield();
416             //ロック
417             lockResource(i_inst);
418             continue;
419         }
420         i=i_inst->txbuf.wp;
421         i_inst->txbuf.wp=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ;
422         return &(q[i]);
423     }while(!NyLPC_cStopwatch_isExpired(i_timer));
424     //失敗。タイムアウト。
425     return NULL;
426 }
427
428
429
430
431
432
433 /**********************************************************************
434  * public 関数
435  **********************************************************************/
436 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst);
437 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst);
438 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec);
439 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec);
440 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek);
441 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec);
442 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec);
443 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec);
444 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr);
445 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec);
446 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);
447 static void finalize(NyLPC_TiTcpSocket_t* i_inst);
448
449 const static struct NyLPC_TiTcpSocket_Interface _interface=
450 {
451         getPeerAddr,
452         getPeerPort,
453         accept,
454         precv,
455         pseek,
456         send,
457         close,
458         allocSendBuf,
459         releaseSendBuf,
460         psend,
461         connect,
462         finalize
463 };
464
465 static const struct NyLPC_TIPv4Addr* getPeerAddr(const NyLPC_TiTcpSocket_t* i_inst)
466 {
467         const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
468         return &inst->uip_connr.ripaddr;
469 }
470 static NyLPC_TUInt16 getPeerPort(const NyLPC_TiTcpSocket_t* i_inst)
471 {
472         const NyLPC_TcMiMicIpTcpSocket_t* inst=(const NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
473         return inst->uip_connr.rport;
474 }
475
476
477
478
479 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_initialize(NyLPC_TcMiMicIpTcpSocket_t* i_inst,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
480 {
481     int i;
482     NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst;
483     i_inst->_super._interface=&_interface;
484     i_inst->_parent_ipv4=&srv->_tcpv4;
485
486     //uipサービスは初期化済であること。
487     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
488
489     NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
490     //  NyLPC_AbortIfNot(NyLPC_cMutex_initialize(&(i_inst->_smutex)));//個別Mutex
491 //  i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));//共有Mutex
492     i_inst->tcpstateflags=UIP_CLOSED;
493     i_inst->txbuf.rp=i_inst->txbuf.wp=0;
494     for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
495         i_inst->txbuf.txq[i].packet=NULL;
496     }
497     //管理リストへ登録。
498     return NyLPC_TBool_TRUE;
499 }
500
501
502
503 NyLPC_TBool NyLPC_cMiMicIpTcpSocket_listenSyn(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const struct NyLPC_TTcpSocketSynParam* i_lq,NyLPC_TUInt16 i_lport)
504 {
505 //  NyLPC_Assert(NyLPC_cMutex_isLocked(i_inst->_smutex));
506     lockResource(i_inst);
507     //ソケットが無効であること。
508     if(i_inst->tcpstateflags==UIP_CLOSED)
509     {
510         //localipとdefault_mmsは別枠で設定
511         /* Fill in the necessary fields for the new connection. */
512         i_inst->uip_connr.current_rto32 = UIP_TCP_RTO_INITIAL;
513         i_inst->uip_connr.lport = i_lport;
514         i_inst->uip_connr.rport = i_lq->rport;
515         i_inst->uip_connr.ripaddr=i_lq->srcaddr;
516         i_inst->uip_connr.snd_nxt32=iss32;
517         /* rcv_nxt should be the seqno from the incoming packet + 1. */
518         i_inst->uip_connr.rcv_nxt32= i_lq->rcv_nxt32;
519         //MSSの設定
520         i_inst->uip_connr.peer_mss=(i_lq->mss!=0)?i_lq->mss:i_inst->uip_connr.default_mss;
521         i_inst->uip_connr.peer_win=0;
522         NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
523         //ここでステータスがかわる。
524         i_inst->tcpstateflags = UIP_SYN_RCVD;
525         //前回のデータが残っていた場合の保険
526         if(i_inst->txbuf.rp!=i_inst->txbuf.wp){
527             resetTxQWithUnlock(i_inst);
528         }else{
529             unlockResource(i_inst);
530         }
531         return NyLPC_TBool_TRUE;
532     }
533     unlockResource(i_inst);
534     return NyLPC_TBool_FALSE;
535 }
536
537
538 /**
539  * sq番のTxがキューから消え去るのを待ちます。
540  * この関数は、アンロック状態でコールしてください。
541  * <div>
542  * パケットがキューからなくなる条件は、以下の2つです。
543  * <ul>
544  * <li>ACKを受信してパケットキューが更新された。</li>
545  * <li>RSTを受信して(CLOSEDに遷移して)、キューがクリアされた。</li>
546  * <li>送信タイムアウトで関数が(CLOSEDに遷移させて)キューをクリアした。</li>
547  * </ul>
548  * </div>
549  * @param i_wait_msec
550  * @return
551  * 1番目の条件でパケットが消失したときのみ、TRUEを返します。
552  * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
553  */
554 static NyLPC_TBool waitForTxRemove(NyLPC_TcMiMicIpTcpSocket_t* i_inst,NyLPC_TUInt32 i_sq,NyLPC_TcStopwatch_t* i_timer)
555 {
556     NyLPC_TUInt8 f;
557     lockResource(i_inst);
558     do{
559         //パケットが送信中か調べる。
560         if(!isPacketAcked(i_inst,i_sq)){
561             //まだある場合は、タスクスイッチを繰り返して消失を待つ。
562             unlockResource(i_inst);
563             NyLPC_cThread_yield();
564             lockResource(i_inst);
565             continue;
566         }
567         //なくなった場合は、原因を調べる。
568         f=i_inst->tcpstateflags;
569         unlockResource(i_inst);
570         return (f==UIP_CLOSED)?NyLPC_TBool_FALSE:NyLPC_TBool_TRUE;
571     }while(!NyLPC_cStopwatch_isExpired(i_timer));
572     unlockResource(i_inst);
573     return NyLPC_TBool_FALSE;
574 }
575
576
577 /**
578  * 再送信処理をセットして、パケットを送信します。
579  * この関数は「アンロック状態で」実行してください。
580  * @param i_len
581  * 送信データサイズを指定します。
582  * この番号は、シーケンス番号の加算値ではありませんので、注意をしてください。
583  * @return
584  * <ul>
585  * <li>n=-1:送信キューへの投入に失敗した。</li>
586  * <li>n>=0:nバイトのデータを送信キューへの投入することに成功した。</li>
587  * </ul>
588  * 送信キューに失敗する理由は2つあります。1つは、TXバッファがフルでタイムアウト。もうひとつは、非同期なコネクリョンのリセットです。
589  * 失敗した場合、TCPステータスがCLOSEDでなければ、RSTを送信してステータスをCLOSEDにします。
590  */
591 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)
592 {
593     struct NyLPC_TcTcpSocket_TxQItem* txq;
594     NyLPC_TUInt16 s;
595     void* buf;
596     NyLPC_TUInt32 next_ack;
597     //送信バッファを取得
598     //@bug オブションパケット送信時に4バイト足りないメモリ要求しない?問題になってないけど。
599     for(;;){
600         buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_len+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
601         if(buf!=NULL){
602             break;
603         }
604         //タイムアウト確認
605         if(NyLPC_cStopwatch_isExpired(i_timer)){
606             return -1;
607         }
608     };
609     lockResource(i_inst);
610     //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
611     if(i_len>0){
612         while(i_inst->uip_connr.peer_win==0){
613             unlockResource(i_inst);
614             //時間切れならエラー。
615             if(NyLPC_cStopwatch_isExpired(i_timer)){
616                 return -1;
617             }
618             NyLPC_cThread_yield();
619             lockResource(i_inst);
620         }
621     }
622     //送信キューの取得
623     txq=getTxQ(i_inst,i_timer);
624     //送信キューが取れなかった。
625     if(txq==NULL){
626         //シーケンス番号をロールバックできないので、エラーとする。
627         unlockResource(i_inst);
628         NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
629         return -1;
630     }
631
632     //送信バッファを基準とした送信サイズを計算
633     s-=SIZE_OF_IPv4_TCPIP_HEADER;
634     //送信サイズよりMMSが小さければ、送信サイズを修正
635     if(i_inst->uip_connr.peer_mss<s){
636         s=i_inst->uip_connr.peer_mss;
637     }
638     //送信サイズよりpeerのウインドウサイズが小さければ修正
639     if(i_inst->uip_connr.peer_win<s){
640         s=i_inst->uip_connr.peer_win;
641     }
642     //送信サイズより、データサイズが小さければ、送信サイズを修正
643     if(i_len<s){
644         s=i_len;
645     }
646     //ACK番号の計算
647     next_ack=i_inst->uip_connr.snd_nxt32+s+(((i_tcpf&(TCP_FIN|TCP_SYN))!=0x00)?1:0);
648     txq->rto32=i_inst->uip_connr.current_rto32;
649     txq->tick_of_sent=NyLPC_cStopwatch_now();
650
651     //パケットの書き込み
652     setTxPacket(i_inst,buf,i_tcpf,i_buf,s);
653     txq->packet=buf;
654
655     //シーケンス番号の更新
656     i_inst->uip_connr.snd_nxt32=next_ack;
657     //Peerのウインドウサイズを更新
658     i_inst->uip_connr.peer_win-=s;
659     //ACK番号の返却
660     *o_ack=txq->ackno=NyLPC_HTONL(next_ack);
661     unlockResource(i_inst);
662     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
663     return s;
664 }
665 /**
666  * RSTを1フレームだけ送信します。
667  * この関数は、クローズドステータスのソケットにしてからコールします。
668  * この関数は、アンロック状態でコールしてね。
669  */
670 static void sendRst(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
671 {
672     void* buf;
673
674     NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);
675     //ペイロードライタの初期化
676
677     //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
678     buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
679     lockResource(i_inst);
680     i_inst->uip_connr.snd_nxt32++;
681     unlockResource(i_inst);
682     setTxPacket(i_inst,buf,TCP_RST|TCP_ACK,NULL,0);
683     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
684     NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
685     NyLPC_cIPv4Payload_finalize(&ipv4);
686     return;
687 }
688
689
690
691 /**
692  * 受信データをバッファに書き込む。
693  * 十分な空き領域がない場合、失敗する。
694  * この関数は、ロックして実行してください。
695  */
696 static NyLPC_TBool addRecvData(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const void* i_data,NyLPC_TUInt16 i_data_size)
697 {
698     //受信データサイズを確認
699     if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))>=i_data_size){
700         //バッファに格納可能なら、格納。
701         NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),i_data,i_data_size);
702     }else{
703         //エラー:ドロップする。
704         return NyLPC_TBool_FALSE;
705     }
706
707     return NyLPC_TBool_TRUE;
708 }
709
710
711
712
713
714 /**
715  * Public function
716  */
717 static void finalize(NyLPC_TiTcpSocket_t* i_inst)
718 {
719     int i;
720         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
721     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
722     //開放漏れの保険
723     if(inst->txbuf.rp!=inst->txbuf.wp){
724         lockResource(inst);
725         resetTxQWithUnlock(inst);
726     }
727     for(i=0;i<NyLPC_TcTcpSocket_NUMBER_OF_TXQ;i++){
728         inst->txbuf.txq[i].packet=NULL;
729     }
730     NyLPC_cFifoBuffer_finalize(&(inst->rxbuf));
731 //  NyLPC_cMutex_finalize(&(i_inst->_smutex));
732     NyLPC_cMiMicIpNetIf_releaseTcpSocketMemory(inst);
733
734     return;
735 }
736
737 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)
738 {
739     volatile NyLPC_TUInt8 f;
740         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
741     NyLPC_TUInt32 sq;
742     NyLPC_TcStopwatch_t sw;
743     NyLPC_TUInt16 lport;
744     lockResource(inst);
745     //ソケットが無効であること。
746     if(inst->tcpstateflags!=UIP_CLOSED)
747     {
748         NyLPC_OnErrorGoto(Error);
749     }
750     //ポート番号の取得(lockResourceが他のソケットと共有なので、重複ポートの割当は起こりえない。でもちょっと注意して)
751     lport=NyLPC_htons(NyLPC_cIPv4_getNewPortNumber(inst->_parent_ipv4));
752     if(lport==0){
753         NyLPC_OnErrorGoto(Error);
754     }
755     //connectの為の準備
756
757     //localipとdefault_mmsは別枠で設定
758     /* Fill in the necessary fields for the new connection. */
759     inst->uip_connr.current_rto32 = UIP_TCP_RTO_CONNECTION_INITIAL;//RTOを短くしてARP発行時の再接続短縮を期待する。
760     inst->uip_connr.lport = lport;
761     inst->uip_connr.rport = NyLPC_htons(i_peer_port);
762     inst->uip_connr.ripaddr=*i_addr;
763     inst->uip_connr.snd_nxt32=iss32;//should be random
764     /* rcv_nxt should be the seqno from the incoming packet + 1. */
765     inst->uip_connr.rcv_nxt32=0;
766     //MSSの設定
767     inst->uip_connr.peer_mss=inst->uip_connr.default_mss;
768     inst->uip_connr.peer_win=1;//periodicの再送信を期待するために相手のWindowサイズは1と仮定する。
769     NyLPC_cFifoBuffer_clear(&(inst->rxbuf));
770     //ここでステータスがかわる。
771     inst->tcpstateflags = UIP_SYN_SENT;
772     //前回のデータが残っていた場合の保険
773     if(inst->txbuf.rp!=inst->txbuf.wp){
774         resetTxQWithUnlock(inst);
775     }else{
776         unlockResource(inst);
777     }
778
779     NyLPC_cStopwatch_initialize(&sw);
780
781     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
782     if(sendWithRetransmit(inst,TCP_SYN,NULL,0,&sw,&sq)==0){
783         //ちょっと待つ。
784         NyLPC_cThread_yield();
785         //キューにあるTXが消えるのを待つ。
786         if(waitForTxRemove(inst,sq,&sw)){
787             //ACK受信に成功して、TXが消失
788             NyLPC_cStopwatch_finalize(&sw);
789             return NyLPC_TBool_TRUE;
790         }
791     }
792     //ロックして、強制的なステータス遷移
793     lockResource(inst);
794     f=inst->tcpstateflags;
795     if(f!=UIP_CLOSED){
796         //もし、強制CLOSE遷移であれば、RSTも送信。
797         inst->tcpstateflags=UIP_CLOSED;
798         unlockResource(inst);
799         sendRst(inst);
800     }else{
801         unlockResource(inst);
802     }
803     return NyLPC_TBool_FALSE;
804 Error:
805     unlockResource(inst);
806     return NyLPC_TBool_FALSE;
807 }
808
809 /**
810  * この関数は、UIP_SYN_RCVDステータスのソケットを、ESTABLISHEDへ遷移させます。
811  * cTcpListener_listen関数を通過したインスタンスに実行してください。
812  * この関数は、アプリケーションが呼び出します。
813  * @return
814  *
815  */
816 static NyLPC_TBool accept(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
817 {
818     volatile NyLPC_TUInt8 f;
819         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
820         NyLPC_TUInt32 sq;
821     NyLPC_TcStopwatch_t sw;
822
823     NyLPC_cStopwatch_initialize(&sw);
824     //ステータスチェック
825     f=inst->tcpstateflags;
826     switch(f)
827     {
828     case UIP_ESTABLISHED:
829         return NyLPC_TBool_TRUE;
830     case UIP_SYN_RCVD:
831         //処理対象
832         break;
833     default:
834         return NyLPC_TBool_FALSE;
835     }
836     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
837     if(sendWithRetransmit(inst,TCP_SYN|TCP_ACK,NULL,0,&sw,&sq)==0){
838         //ちょっと待つ。
839         NyLPC_cThread_yield();
840         //キューにあるTXが消えるのを待つ。
841         if(waitForTxRemove(inst,sq,&sw)){
842             //ACK受信に成功して、TXが消失
843             NyLPC_cStopwatch_finalize(&sw);
844             return NyLPC_TBool_TRUE;
845         }
846     }
847     //ロックして、強制的なステータス遷移
848     lockResource(inst);
849     f=inst->tcpstateflags;
850     if(f!=UIP_CLOSED){
851         //もし、強制CLOSE遷移であれば、RSTも送信。
852         inst->tcpstateflags=UIP_CLOSED;
853         unlockResource(inst);
854         sendRst(inst);
855     }else{
856         unlockResource(inst);
857     }
858     return NyLPC_TBool_FALSE;
859 }
860
861
862 /**
863  * この関数は、ソケットの受信バッファの読み取り位置と、読み出せるデータサイズを返却します。
864  * 関数はポインターを返却するだけで、バッファの読み取り位置をシークしません。
865  * シークするにはNyLPC_cTcpSocket_pseekを使います。
866  */
867 static NyLPC_TInt32 precv(NyLPC_TiTcpSocket_t* i_inst,const void** o_buf_ptr,NyLPC_TUInt32 i_wait_msec)
868 {
869         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
870     volatile NyLPC_TUInt8 st;
871     NyLPC_TUInt16 rlen;
872     //タイマを生成
873     NyLPC_TcStopwatch_t sw;
874     NyLPC_cStopwatch_initialize(&sw);
875
876     //ESTABLISHED以外の場合は、エラー。
877     NyLPC_cStopwatch_setNow(&sw);
878     do{
879         //読み出しバッファ情報のコピー
880         //MUTEX LOCK
881         lockResource(inst);
882         st=inst->tcpstateflags;
883         rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
884         *o_buf_ptr=NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
885         //MUTEX UNLOCK
886         unlockResource(inst);
887
888         //バッファが空の場合は、ステータスチェック。ESTABLISHEDでなければ、エラー(PASVCLOSE等の場合)
889         switch(st){
890         case UIP_ESTABLISHED:
891             if(rlen>0){
892                 //バッファにパケットがあれば返却
893                 NyLPC_cStopwatch_finalize(&sw);
894                 return rlen;
895             }
896             break;
897         case UIP_CLOSE_WAIT:
898             if(rlen>0){
899                 //バッファにパケットがあれば返却
900                 NyLPC_cStopwatch_finalize(&sw);
901                 return rlen;
902             }
903             //引き続きエラー処理
904         default:
905             //他の場合はエラー
906             NyLPC_cStopwatch_finalize(&sw);
907             return -1;
908         }
909         //タスクスイッチ
910         NyLPC_cThread_yield();
911     }while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec);
912     //規定時間内に受信が成功しなかった。
913     NyLPC_cStopwatch_finalize(&sw);
914     return 0;
915 }
916 /**
917  * 受信バッファをシークします。
918  * シーク後に、遅延ACKを送出します。
919  */
920 static void pseek(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_seek)
921 {
922     void* buf;
923     NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
924
925     NyLPC_ArgAssert(i_seek<=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf)));
926     if(i_seek==0){
927         return;
928     }
929
930     //ACK送信バッファの取得
931     buf=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
932
933     //MUTEX LOCK
934     lockResource(inst);
935
936     //受信バッファを読み出しシーク
937     NyLPC_cFifoBuffer_pop(&(inst->rxbuf),i_seek);
938     //ACKパケットの生成
939     setTxPacket(inst,buf,TCP_ACK,NULL,0);
940     unlockResource(inst);
941     //ACK送信
942     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
943     NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
944
945 }
946
947 /**
948  * See header file.
949  */
950 static void* allocSendBuf(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
951 {
952         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
953
954     NyLPC_TUInt16 s;
955     void* buf;
956     NyLPC_TcStopwatch_t sw;
957
958     NyLPC_cStopwatch_initialize(&sw);
959     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
960
961     //送信バッファを取得
962     //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
963     for(;;){
964         //ESTABLISHED以外に非同期遷移
965         if(inst->tcpstateflags!=UIP_ESTABLISHED){
966             NyLPC_cStopwatch_finalize(&sw);
967             return NULL;
968         }
969         buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_TCPIP_HEADER),&s);
970         if(buf!=NULL){
971             break;
972         }
973         //タイムアウト時もエラー
974         if(NyLPC_cStopwatch_isExpired(&sw)){
975             NyLPC_cStopwatch_finalize(&sw);
976             return NULL;
977         }
978     }
979
980 //@todo 前段処理と順番を入れ替えて、要求サイズとpeerのwinのうち、小さいほうを割り当てたほうが良くない?
981 //ここで相手のwin待ちをする理由は、相手に確実に受け取れるサイズを決定する為。
982     lockResource(inst);
983     //ペイロードがある場合のみ、相手のwindowサイズが0以上になるのを待つ。
984     while(inst->uip_connr.peer_win==0){
985         unlockResource(inst);
986         //ESTABLISHED以外に非同期遷移 orタイムアウト確認
987         if(NyLPC_cStopwatch_isExpired(&sw)||(inst->tcpstateflags!=UIP_ESTABLISHED)){
988             NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
989             NyLPC_cStopwatch_finalize(&sw);
990             return NULL;
991         }
992         NyLPC_cThread_yield();
993         lockResource(inst);
994     }
995     //送信バッファを基準とした送信サイズを計算
996     s-=SIZE_OF_IPv4_TCPIP_HEADER;
997     //送信サイズよりMMSが小さければ、送信サイズを修正
998     if(inst->uip_connr.peer_mss<s){
999         s=inst->uip_connr.peer_mss;
1000     }
1001     //送信サイズよりpeerのウインドウサイズが小さければ修正
1002     if(inst->uip_connr.peer_win<s){
1003         s=inst->uip_connr.peer_win;
1004     }
1005     unlockResource(inst);
1006     //バッファサイズ確定。
1007     *o_buf_size=s;
1008     NyLPC_cStopwatch_finalize(&sw);
1009     return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_TCPIP_HEADER;
1010 }
1011 /**
1012  * See Header file.
1013  */
1014 static void releaseSendBuf(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr)
1015 {
1016     NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER);
1017 }
1018
1019
1020 /**
1021  * 事前にAllocしたTxパケットを送信します。
1022  * このAPIはゼロコピー送信をサポートするためのものです。
1023  * @param i_buf_ptr
1024  * allocSendBufで取得したメモリを指定します。
1025  * @return
1026  * 関数が失敗した場合、i_buf_ptrは「開放されません。」
1027  */
1028 static NyLPC_TBool psend(NyLPC_TiTcpSocket_t* i_inst,void* i_buf_ptr,int i_len,NyLPC_TUInt32 i_wait_in_msec)
1029 {
1030         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
1031     struct NyLPC_TcTcpSocket_TxQItem* txq;
1032     void* buf;
1033     NyLPC_TcStopwatch_t sw;
1034     //ESTABLISHEDでなければエラー
1035     if(inst->tcpstateflags!=UIP_ESTABLISHED){
1036         //ESTABLISHEDでなければエラー
1037         return NyLPC_TBool_FALSE;
1038     }
1039     //送信データ0なら何もしない。
1040     if(i_len<1){
1041         releaseSendBuf(i_inst,i_buf_ptr);
1042         return NyLPC_TBool_TRUE;
1043     }
1044     NyLPC_cStopwatch_initialize(&sw);
1045     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
1046
1047     //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
1048     buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_TCPIP_HEADER;
1049     lockResource(inst);
1050     //送信キューの取得
1051     txq=getTxQ(inst,&sw);
1052     //送信キューが取れなかった。
1053     if(txq==NULL){
1054         //シーケンス番号をロールバックできないので、エラーとする。
1055         unlockResource(inst);
1056         NyLPC_cStopwatch_finalize(&sw);
1057         return NyLPC_TBool_FALSE;
1058     }
1059     //ここから先はi_bufの所有権はインスタンスになってる。
1060
1061     //IPv4ペイロードの書き込み
1062
1063     //allocをした時点でwin,mssは考慮されているので、そのままそうしんしる。
1064
1065     //ACK番号の計算
1066     txq->rto32=inst->uip_connr.current_rto32;
1067     txq->tick_of_sent=NyLPC_cStopwatch_now();
1068     //パケットヘッダの生成(ヘッダ長はpreadで定義した値(4+6)*4=40です。)
1069     setTxPacketHeader(inst,buf,TCP_ACK|TCP_PSH,i_len);
1070     txq->packet=buf;
1071
1072     //シーケンス番号の更新
1073     inst->uip_connr.snd_nxt32=inst->uip_connr.snd_nxt32+i_len;
1074     //Peerのウインドウサイズを更新
1075     inst->uip_connr.peer_win-=i_len;
1076     //ACK番号の返却
1077     txq->ackno=NyLPC_HTONL(inst->uip_connr.snd_nxt32);
1078     unlockResource(inst);
1079     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
1080     NyLPC_cStopwatch_finalize(&sw);
1081     return NyLPC_TBool_TRUE;
1082 }
1083
1084 /**
1085  * See header file.
1086  */
1087 static NyLPC_TInt32 send(NyLPC_TiTcpSocket_t* i_inst,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec)
1088 {
1089     NyLPC_TInt16 hint;
1090     NyLPC_TUInt16 s;
1091     void* buf;
1092     if(i_len<1){
1093         return 0;
1094     }
1095     hint=(i_len>32767)?32767:i_len;
1096     buf=allocSendBuf(i_inst,hint,&s,i_wait_in_msec);
1097     if(buf==NULL){
1098         return -1;
1099     }
1100     //送信サイズの計算
1101     s=((NyLPC_TInt32)s<i_len)?s:(NyLPC_TUInt16)i_len;
1102     memcpy(buf,i_buf_ptr,s);
1103     if(!psend(i_inst,buf,s,i_wait_in_msec)){
1104         releaseSendBuf(i_inst,buf);
1105         return -1;//error
1106     }
1107     return s;
1108 }
1109
1110
1111 static void close(NyLPC_TiTcpSocket_t* i_inst,NyLPC_TUInt32 i_wait_in_msec)
1112 {
1113         NyLPC_TcMiMicIpTcpSocket_t* inst=(NyLPC_TcMiMicIpTcpSocket_t*)i_inst;
1114     NyLPC_TcStopwatch_t sw;
1115     volatile NyLPC_TUInt8 f;
1116     NyLPC_TUInt32 sq;
1117     NyLPC_cStopwatch_initialize(&sw);
1118     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
1119     lockResource(inst);
1120
1121     f=inst->tcpstateflags;
1122     //ステータスチェック
1123     switch(f)
1124     {
1125     case UIP_CLOSED:
1126         //閉じている。
1127         goto ReturnWithUnlock;
1128     case UIP_ESTABLISHED:
1129         //アクティブクローズ。
1130         inst->tcpstateflags=UIP_FIN_WAIT_1;
1131         //送信のために一旦解除
1132         unlockResource(inst);
1133         //FINの送信
1134         if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
1135             //ちょっと待つ。
1136             NyLPC_cThread_yield();
1137             //TXの消去待ち
1138             if(waitForTxRemove(inst,sq,&sw)){
1139                 //再ロック
1140                 lockResource(inst);
1141                 //タイムアウトするか、UIP_CLOSED、もしくはTIME_WAITに遷移するのを待つ。(遷移はRxprocで自動的に実行。)
1142                 do{
1143                     switch(inst->tcpstateflags)
1144                     {
1145                     case UIP_TIME_WAIT:
1146                         inst->tcpstateflags=UIP_CLOSED;
1147                     case UIP_CLOSED:
1148                         NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp);
1149                         //成功。
1150                         goto ReturnWithUnlock;
1151                     case UIP_FIN_WAIT_1:
1152                     case UIP_FIN_WAIT_2:
1153                     case UIP_CLOSING:
1154                         //一時的なアンロック
1155                         unlockResource(inst);
1156                         NyLPC_cThread_yield();
1157                         lockResource(inst);
1158                     default:
1159                         break;
1160                     }
1161                 }while(!NyLPC_cStopwatch_isExpired(&sw));
1162                 unlockResource(inst);
1163             }
1164         }
1165         break;
1166     case UIP_CLOSE_WAIT:
1167         //LAST_ACKへ遷移
1168         inst->tcpstateflags=UIP_LAST_ACK;
1169         //送信のために一旦解除
1170         unlockResource(inst);
1171         if(sendWithRetransmit(inst,TCP_FIN|TCP_ACK,NULL,0,&sw,&sq)==0){
1172             //ちょっと待つ。
1173             NyLPC_cThread_yield();
1174             //TXの消去待ち
1175             if(waitForTxRemove(inst,sq,&sw)){
1176                 //再ロック
1177                 lockResource(inst);
1178                 //TX消去後にCLOSEDに遷移していればOK
1179                 if(inst->tcpstateflags==UIP_CLOSED)
1180                 {
1181                     NyLPC_Assert(inst->txbuf.rp==inst->txbuf.wp);
1182                     goto ReturnWithUnlock;
1183                 }
1184                 unlockResource(inst);
1185             }
1186         }
1187         //エラー。RSTで切断。
1188         break;
1189     default:
1190         unlockResource(inst);
1191         NyLPC_Warning();
1192         break;
1193     }
1194 //  if(i_inst->_smutex._lock_count>0){
1195 //      NyLPC_Warning();
1196 //  }
1197     //このパスに到達するのは、FIN送信/ACKに成功したにも拘らず、規定時間内にCLOSEDに遷移しなかった場合。
1198     //コネクションを強制遷移して、RST
1199     lockResource(inst);
1200     f=inst->tcpstateflags;
1201     if(f!=UIP_CLOSED){
1202         //もし、強制CLOSE遷移であれば、RSTも送信。
1203         inst->tcpstateflags=UIP_CLOSED;
1204         unlockResource(inst);
1205         sendRst(inst);
1206     }else{
1207         unlockResource(inst);
1208     }
1209     NyLPC_cStopwatch_finalize(&sw);
1210     return;
1211 ReturnWithUnlock:
1212     unlockResource(inst);
1213     NyLPC_cStopwatch_finalize(&sw);
1214     return;
1215 }
1216
1217 /**
1218  * uipサービスタスクが実行する関数です。
1219  * 定期的に実行する関数。最低でも1s単位で実行してください。
1220  */
1221 void NyLPC_cMiMicIpTcpSocket_periodic(
1222         NyLPC_TcMiMicIpTcpSocket_t* i_inst)
1223 {
1224     int i;
1225     struct NyLPC_TcTcpSocket_TxQItem* q=i_inst->txbuf.txq;
1226     NyLPC_TcStopwatch_t sw;
1227     NyLPC_TUInt32 now;
1228     int rp;
1229     NyLPC_cStopwatch_initialize(&sw);
1230     now=NyLPC_cStopwatch_now();
1231     //MUTEX LOCK
1232     lockResource(i_inst);
1233     if(i_inst->tcpstateflags==UIP_CLOSED)
1234     {
1235         //CLOSEDなら、バッファ開放。
1236         resetTxQWithUnlock(i_inst);
1237     }else if(i_inst->txbuf.rp==i_inst->txbuf.wp){
1238         //再送信パケットがなければ何もしないよ。
1239         unlockResource(i_inst);
1240     }else if(i_inst->uip_connr.peer_win==0){
1241         //peer_winが0の場合は何もしない。
1242         unlockResource(i_inst);
1243     }else{
1244         //再送信処理
1245         rp=i_inst->txbuf.rp;
1246         NyLPC_cStopwatch_set(&sw,q[rp].tick_of_sent);
1247         if(NyLPC_cStopwatch_elapseInMsec(&sw)>q[rp].rto32){
1248             //最古のパケットの送信時間をチェックして、タイムアウトが発生したら、再送時間と送信時刻をセット
1249             //最古パケットRTOを2倍。
1250             q[rp].rto32*=2;
1251             for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
1252                 q[i].tick_of_sent=now;
1253             }
1254             if(q[rp].rto32>UIP_IP_RTO_MAX_RTO){
1255                 //最古のRTOが64秒を超えたら、CLOSED
1256                 i_inst->tcpstateflags =UIP_CLOSED;
1257                 resetTxQWithUnlock(i_inst);
1258                 sendRst(i_inst);
1259             }else{
1260                 //規定時間内なら、再送処理
1261                 for(i=rp;i!=i_inst->txbuf.wp;i=(i+1)%NyLPC_TcTcpSocket_NUMBER_OF_TXQ){
1262 //                  NyLPC_cUipService_sendIPv4Tx(NyLPC_cIPv4Payload_getBuf(&(q[i].data)));
1263                     NyLPC_cMiMicIpNetIf_sendIPv4Tx(q[i].packet);
1264                 }
1265                 unlockResource(i_inst);
1266             }
1267         }else{
1268             unlockResource(i_inst);
1269         }
1270     }
1271     NyLPC_cStopwatch_finalize(&sw);
1272     return;
1273 }
1274 /**
1275  * uipサービスタスクが実行する関数です。
1276  * サービスの開始を通知します。
1277  */
1278 void NyLPC_cMiMicIpTcpSocket_startService(NyLPC_TcMiMicIpTcpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)
1279 {
1280     NyLPC_Assert(i_inst->tcpstateflags==UIP_CLOSED);//閉じてなければおかしい。
1281     i_inst->uip_connr.lipaddr=&(i_config->ip_addr);
1282     i_inst->uip_connr.default_mss=i_config->default_mss;
1283     //NyLPC_cTcpSocket_setSynPayload関数でも実行するけど、IFのリセット時なのでここでもやる。
1284     NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
1285     return;
1286 }
1287 /**
1288  * uipサービスタスクが実行する関数です。
1289  * サービスの停止を通知します。
1290  */
1291 void NyLPC_cMiMicIpTcpSocket_stopService(NyLPC_TcMiMicIpTcpSocket_t* i_inst)
1292 {
1293     lockResource(i_inst);
1294     if(i_inst->tcpstateflags==UIP_CLOSED)
1295     {
1296         unlockResource(i_inst);
1297     }else{
1298         i_inst->tcpstateflags=UIP_CLOSED;
1299         resetTxQWithUnlock(i_inst);
1300         sendRst(i_inst);
1301     }
1302     return;
1303 }
1304
1305
1306 void* NyLPC_cMiMicIpTcpSocket_parseRx(
1307         NyLPC_TcMiMicIpTcpSocket_t* i_inst,
1308     const NyLPC_TcIPv4Payload_t* i_ipp)
1309 {
1310     int i,s;
1311     NyLPC_TUInt16 tmp16;
1312     NyLPC_TUInt16 data_size;
1313     NyLPC_TUInt8 in_tcpflag=i_ipp->payload.tcp->flags;
1314     const void* tcp_data_offset;
1315     NyLPC_TBool is_new_packet;
1316     int num_of_noack;
1317     void* dlist[NyLPC_TcTcpSocket_NUMBER_OF_TXQ];
1318     void* ret;
1319
1320     //パラメータの計算
1321
1322     tmp16=NyLPC_TTcpHeader_getHeaderLength(i_ipp->payload.tcp);
1323     //TCPペイロードの長さは、IPパケットの長さ-(IPヘッダ+TCPヘッダ)
1324     data_size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16;
1325     //TCPデータオフセット
1326     tcp_data_offset=i_ipp->payload.rawbuf+tmp16;
1327
1328     //インスタンスをロックする。
1329     lockResource(i_inst);
1330
1331     //RSTのチェック。RST受信時は、状態にかかわらず、CLOSEDステータスに移行する。
1332     if (in_tcpflag & TCP_RST)
1333     {
1334         i_inst->tcpstateflags =UIP_CLOSED;
1335         goto DROP;
1336     }
1337
1338
1339     is_new_packet=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)==i_inst->uip_connr.rcv_nxt32;
1340
1341
1342     //OPTIONの反映
1343
1344     //MSSの取得
1345     if(NyLPC_TTcpHeader_getTcpMmsOpt(i_ipp->payload.tcp,&tmp16)){
1346         //取得で着たら更新
1347         i_inst->uip_connr.peer_mss=tmp16;
1348     }
1349     //受信パケットを元に、未ACKパケットの数を計算
1350     num_of_noack=getNumOfSending(i_inst,i_ipp->payload.tcp->ackno32);//i_inst->txbuf.num_of_txq;
1351
1352     //ステータス毎のACK応答
1353     switch(i_inst->tcpstateflags)
1354     {
1355     case UIP_SYN_RCVD:
1356         //ACKを受信したら、ESTABLISHEDへ。
1357         //すべてのパケットをACKしたかで判定。()
1358         if(num_of_noack==0){
1359             i_inst->tcpstateflags=UIP_ESTABLISHED;
1360         }else{
1361             //それ以外のパケットはドロップする。
1362             break;//goto DROP;
1363         }
1364         //新しいパケットがなければ、無応答
1365         if(!is_new_packet){
1366             break;//goto DROP;
1367         }
1368         //引き続き、ESTABLISHEDの処理へ。
1369     case UIP_ESTABLISHED:
1370         if(data_size>0){
1371             if(is_new_packet){
1372                 if(addRecvData(i_inst,tcp_data_offset,data_size)){
1373                     //通常のACK返却
1374                     i_inst->uip_connr.rcv_nxt32+=data_size;
1375                 }else{
1376                     //失敗したときは必要に応じて単純ACK
1377                 }
1378             }
1379         }
1380         //どちらにしろ、ACK送信
1381         if(is_new_packet && (in_tcpflag & TCP_FIN)){
1382             //FINがあるときは、ステータスをCLOSE_WAITへセットして、ACKを返す。
1383             i_inst->tcpstateflags = UIP_CLOSE_WAIT;
1384             i_inst->uip_connr.rcv_nxt32++;
1385         }
1386         break;
1387     case UIP_CLOSE_WAIT:
1388         //必要に応じたACK応答
1389         break;
1390     case UIP_LAST_ACK:
1391         //ACK(by FIN)が得られたなら、CLOSEDへ。
1392         if(num_of_noack==0){
1393             i_inst->tcpstateflags=UIP_CLOSED;
1394         }
1395         //必要に応じたACK応答
1396         break;
1397     case UIP_FIN_WAIT_1:
1398         //FIN受信->CLOSINGへ
1399         if(is_new_packet){
1400             i_inst->uip_connr.rcv_nxt32+=data_size;
1401             if(in_tcpflag & TCP_FIN){
1402                 i_inst->uip_connr.rcv_nxt32++;
1403                 if(num_of_noack==0){
1404                     //FINとACKを受信
1405                     i_inst->tcpstateflags=UIP_TIME_WAIT;
1406                 }else{
1407                     //FINのみ
1408                     i_inst->tcpstateflags=UIP_CLOSING;
1409                 }
1410             }
1411         }else if(num_of_noack==0){
1412             //ACKのみ
1413             i_inst->tcpstateflags=UIP_FIN_WAIT_2;
1414         }
1415         //必要に応じたACK応答
1416         break;
1417     case UIP_FIN_WAIT_2:
1418         //FIN受信->TIME_WAITへ(pureACK)
1419         if(is_new_packet && (in_tcpflag & TCP_FIN)){
1420             i_inst->uip_connr.rcv_nxt32++;
1421             i_inst->tcpstateflags=UIP_TIME_WAIT;
1422         }
1423         break;
1424     case UIP_CLOSING:
1425         //ACK受信したら、TIME_WAITへ
1426         if(num_of_noack==0){
1427             i_inst->tcpstateflags=UIP_TIME_WAIT;
1428         }
1429         break;
1430     case UIP_CLOSED:
1431         //何もできない。何もしない。
1432         break;
1433     case UIP_TIME_WAIT:
1434         //最終ACKを送り続ける。
1435         break;
1436     case UIP_SYN_SENT:
1437         //connect関数実行中しか起動しないステータス
1438         if(num_of_noack==0){
1439             i_inst->tcpstateflags=UIP_ESTABLISHED;
1440             i_inst->uip_connr.rcv_nxt32=NyLPC_ntohl(i_ipp->payload.tcp->seqno32)+1;
1441         }else{
1442             //それ以外のパケットはドロップする。
1443             break;//goto DROP;
1444         }
1445         //ACKを送る。
1446         break;
1447     default:
1448         goto DROP;
1449     }
1450     //ウインドウサイズを更新
1451     i_inst->uip_connr.peer_win=NyLPC_ntohs(i_ipp->payload.tcp->wnd16);
1452
1453     //送信キューから、Peerが受信したデータを削除する。
1454     if(in_tcpflag & TCP_ACK){
1455         //再送パケットキューから送信済みのデータを回収(後で開放)
1456         NyLPC_Trace();
1457         s=updateTxQByIndex(i_inst,i_ipp->payload.tcp->ackno32,dlist);
1458         NyLPC_Trace();
1459     }else{
1460         s=0;
1461     }
1462     //新しいパケットがきた場合は、再送キューのACKを更新する。
1463     if(is_new_packet){
1464         //再送キューのACKを更新
1465         updateTxAck(i_inst,NyLPC_htonl(i_inst->uip_connr.rcv_nxt32));
1466     }
1467
1468     //送信キューのない
1469     if(((in_tcpflag&(TCP_FIN|TCP_SYN))!=0x00) ||
1470         ((!is_new_packet) && (data_size>0)))
1471     {
1472         //ソケットからPureACKを生成 as setPacket(i_inst,i_ipp,TCP_ACK,NULL,0);
1473         ret=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
1474         setTxPacket(i_inst,ret,TCP_ACK,NULL,0);
1475     }else{
1476         ret=NULL;
1477     }
1478     unlockResource(i_inst);
1479     //取り外したTXメモリの開放
1480     for(i=0;i<s;i++){
1481         //取り外したTXメモリを開放
1482         NyLPC_cMiMicIpNetIf_releaseTxBuf(dlist[i]);
1483     }
1484 NyLPC_Trace();
1485     return ret;
1486 DROP:
1487     //ACKしたパケットを送信キューから削除
1488     unlockResource(i_inst);
1489 NyLPC_Trace();
1490     return NULL;
1491 }
1492
1493
1494 /**
1495  * 入力されたパケットからRSTパケットを生成して返す。
1496  */
1497 void* NyLPC_cMiMicIpTcpSocket_allocTcpReverseRstAck(
1498     const NyLPC_TcIPv4Payload_t* i_src)
1499 {
1500     struct NyLPC_TIPv4Header*   iph;
1501     struct NyLPC_TTcpHeader*    tcph;
1502     NyLPC_TUInt8 iph_word=0x05;
1503     NyLPC_TUInt8 tcph_word=(UIP_TCPH_LEN) / 4;
1504     void* txb=NyLPC_cMiMicIpNetIf_allocSysTxBuf();
1505     //IPヘッダの更新
1506     iph=(struct NyLPC_TIPv4Header*)txb;
1507     iph->vhl=0x40|(0x0f&iph_word);
1508     iph->destipaddr=i_src->header->srcipaddr;
1509     iph->srcipaddr =i_src->header->destipaddr;
1510     NyLPC_TIPv4Header_writeTxIpHeader(iph,UIP_PROTO_TCP);
1511
1512     //TCPヘッダの更新
1513     tcph=(struct NyLPC_TTcpHeader*)(((NyLPC_TUInt8*)txb)+NyLPC_TIPv4Header_getHeaderLength(iph));
1514
1515     tcph->tcpoffset=(tcph_word<<4);
1516
1517     tcph->flags    = TCP_RST | TCP_ACK;
1518     //sorce & destination port
1519     tcph->srcport  = i_src->payload.tcp->destport;
1520     tcph->destport = i_src->payload.tcp->srcport;
1521     //ACK number
1522     tcph->ackno32  = NyLPC_htonl(NyLPC_ntohl(i_src->payload.tcp->seqno32)+1);
1523     //Seq Number
1524     tcph->seqno32  = i_src->payload.tcp->ackno32;
1525     //uip_func_tcp_send_noconn(BUF);
1526     tcph->urgp[0]  = tcph->urgp[1] = 0;
1527     tcph->tcpchksum= 0;
1528
1529
1530     //最終的なパケットサイズと必要ならペイロードを書き込み
1531     iph->len16=NyLPC_htons((iph_word+tcph_word)*4);
1532     //WND設定
1533     tcph->wnd16=0;
1534     //Checksumの生成
1535     tcph->tcpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(iph));
1536     iph->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(iph));
1537     return txb;
1538 }
1539
1540
1541
1542