OSDN Git Service

update libMiMic
[mimic/MiMicSDK.git] / lib / src / netif / mimicip / NyLPC_cMiMicIpUdpSocket.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  * Parts of this file were leveraged from uIP:
27  *
28  * Copyright (c) 2001-2003, Adam Dunkels.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the author may not be used to endorse or promote
40  *    products derived from this software without specific prior
41  *    written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55 #include "NyLPC_cMiMicIpUdpSocket_protected.h"
56 #include "NyLPC_cIPv4Payload_protected.h"
57 #include "NyLPC_cMiMicIpNetIf_protected.h"
58
59 /**
60  * フラグ値
61  */
62 #define NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST 0
63 /**
64  * UDP/IPヘッダのサイズ
65  */
66 #define SIZE_OF_IPv4_UDPIP_HEADER 28
67
68 #define lockResource(i_inst) NyLPC_cMutex_lock(((i_inst)->_smutex))
69 #define unlockResource(i_inst) NyLPC_cMutex_unlock(((i_inst)->_smutex))
70
71 /*
72  *       関数テーブル
73  */
74 static void joinMulticast(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr);
75 static void setBroadcast(NyLPC_TiUdpSocket_t* i_inst);
76 static NyLPC_TInt32 precv(NyLPC_TiUdpSocket_t* i_inst,const void** o_buf_ptr,const struct NyLPC_TIPv4RxInfo** o_info,NyLPC_TUInt32 i_wait_msec);
77 static void pseek(NyLPC_TiUdpSocket_t* i_inst);
78 static void* allocSendBuf(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec);
79 static void releaseSendBuf(NyLPC_TiUdpSocket_t* i_inst,void* i_buf_ptr);
80 static NyLPC_TBool psend(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_port,void* i_buf_ptr,int i_len);
81 static NyLPC_TInt32 send(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_port,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec);
82 static void setOnRxHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onRxHandler i_handler);
83 static void setOnPeriodicHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onPeriodicHandler i_handler);
84 static const struct NyLPC_TIPv4Addr* getSockIP(const NyLPC_TiUdpSocket_t* i_inst);
85 static void finalize(NyLPC_TiUdpSocket_t* i_inst);
86
87 static const struct NyLPC_TiUdpSocket_Interface interface=
88 {
89         joinMulticast,
90         setBroadcast,
91         precv,
92         pseek,
93         allocSendBuf,
94         releaseSendBuf,
95         psend,
96         send,
97         setOnRxHandler,
98         setOnPeriodicHandler,
99         getSockIP,
100         finalize
101 };
102
103
104
105
106 /*
107  *      Initializer/Finalizer
108  */
109
110
111 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_initialize(NyLPC_TcMiMicIpUdpSocket_t* i_inst,NyLPC_TUInt16 i_port,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
112 {
113         NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst;
114         i_inst->_super._interface=&interface;
115         i_inst->_super._tag=NULL;
116     //uipサービスは初期化済であること。
117     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
118     i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));
119     i_inst->uip_udp_conn.lport=NyLPC_htons(i_port);
120     i_inst->uip_udp_conn.mcastaddr=NyLPC_TIPv4Addr_ZERO;
121     i_inst->uip_udp_conn.flags=0x00;
122     i_inst->as_handler.rx=NULL;
123     i_inst->as_handler.periodic=NULL;
124
125     NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
126     //管理リストへ登録。
127     return NyLPC_TBool_TRUE;
128 }
129
130
131
132 /**
133  * IP+UDPヘッダサイズを0x05*4+8バイトとして、UDPの送信バッファをセットします。
134  */
135 static void setUdpTxBufHeader(const NyLPC_TcMiMicIpUdpSocket_t* i_inst,void*i_buf,const struct NyLPC_TIPv4Addr* i_dest_ip,NyLPC_TUInt16 i_dest_port,NyLPC_TUInt8 i_iph_word,NyLPC_TUInt16 i_payload_size)
136 {
137     struct NyLPC_TIPv4Header* header=(struct NyLPC_TIPv4Header*)i_buf;
138     struct NyLPC_TUdpHeader* udp    =(struct NyLPC_TUdpHeader*)(((NyLPC_TUInt8*)i_buf)+i_iph_word*4);
139
140     header->vhl=0x40|(0x0f&i_iph_word);
141     header->len16=NyLPC_htons(i_payload_size+(i_iph_word*4+8));
142     udp->udplen=NyLPC_htons(i_payload_size+(8));
143     //IPv4のTxヘッダを書き込む。
144     header->destipaddr=*i_dest_ip;
145     header->srcipaddr =i_inst->uip_udp_conn.lipaddr;
146
147     NyLPC_TIPv4Header_writeTxIpHeader(header,UIP_PROTO_UDP);
148
149     //UDPのTxヘッダを書き込む
150     //sorce & destination port
151     udp->srcport  = i_inst->uip_udp_conn.lport;
152     udp->destport = NyLPC_htons(i_dest_port);
153     udp->udpchksum= 0;
154
155     udp->udpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(header));
156     header->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(header));
157 }
158
159
160
161
162 /**
163  * この関数は、rxパケットを処理して、ソケットの状態を更新します。
164  * uipサービスタスクが実行する関数です。
165  * この関数はNyLPC_cTcpSocket_periodicと排他実行すること。
166  */
167 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_parseRx(
168         NyLPC_TcMiMicIpUdpSocket_t* i_inst,
169     const NyLPC_TcIPv4Payload_t* i_ipp)
170 {
171     NyLPC_TUInt16 tmp16;
172     struct NyLPC_TIPv4RxInfo dheader;
173     const void* data_offset;
174     //ブロードキャストの場合、フラグを確認
175     if(NyLPC_TIPv4Addr_isEqual(&(i_ipp->header->destipaddr),&NyLPC_TIPv4Addr_BROADCAST)){
176         if(!NyLPC_TUInt8_isBitOn(i_inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST)){
177             goto DROP;
178         }
179     }
180     //パラメータの計算
181     tmp16=NyLPC_TUdpHeader_getHeaderLength(i_ipp->payload.tcp);
182     //UDPペイロードの長さは、IPパケットの長さ-(IPヘッダ+UDPヘッダ)
183     dheader.size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16;
184     dheader.peer_ip=i_ipp->header->srcipaddr;
185     dheader.peer_port=NyLPC_ntohs(i_ipp->payload.udp->srcport);
186     dheader.ip=i_ipp->header->destipaddr;
187     dheader.port=NyLPC_ntohs(i_ipp->payload.udp->destport);
188     if(i_inst->as_handler.rx!=NULL){
189         if(!i_inst->as_handler.rx((NyLPC_TiUdpSocket_t*)(i_inst),i_ipp->payload.rawbuf+tmp16,&dheader)){
190             return NyLPC_TBool_FALSE;//UDPはReturnパケットなし
191         }
192     }
193     //TCPデータオフセット
194     data_offset=i_ipp->payload.rawbuf+tmp16;
195
196     //インスタンスをロックする。
197     lockResource(i_inst);
198     //受信キューへ追加(データ構造はsize[2]+data[n]).sizeに16ビットの受信サイズ,後続にデータ
199
200     //受信データサイズを確認
201     if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))<dheader.size+sizeof(struct NyLPC_TIPv4RxInfo)){
202         goto DROP;
203     }
204     //バッファに格納可能なら、格納。
205     NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),&dheader,sizeof(struct NyLPC_TIPv4RxInfo));
206     NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),data_offset,dheader.size);
207     unlockResource(i_inst);
208     return NyLPC_TBool_FALSE;//UDPはReturnパケットなし
209 DROP:
210     unlockResource(i_inst);
211     return NyLPC_TBool_FALSE;
212 }
213
214
215
216
217 static void finalize(NyLPC_TiUdpSocket_t* i_inst)
218 {
219     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
220
221     NyLPC_cFifoBuffer_finalize(&(i_inst->rxbuf));
222     NyLPC_cMiMicIpNetIf_releaseUdpSocketMemory((NyLPC_TcMiMicIpUdpSocket_t*)i_inst);
223     return;
224 }
225
226
227 static void joinMulticast(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr)
228 {
229         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
230         inst->uip_udp_conn.mcastaddr=*i_addr;
231 }
232 static void setBroadcast(NyLPC_TiUdpSocket_t* i_inst)
233 {
234         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
235     NyLPC_TUInt8_setBit(inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST);
236 }
237
238
239
240 /**
241  * see Header file
242  */
243 static NyLPC_TInt32 precv(NyLPC_TiUdpSocket_t* i_inst,const void** o_buf_ptr,const struct NyLPC_TIPv4RxInfo** o_info,NyLPC_TUInt32 i_wait_msec)
244 {
245         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
246     NyLPC_TUInt16 rlen;
247     //タイマを生成
248     NyLPC_TcStopwatch_t sw;
249     NyLPC_cStopwatch_initialize(&sw);
250     const char* b;
251     const struct NyLPC_TIPv4RxInfo* rh;
252
253     //ESTABLISHED以外の場合は、エラー。
254     NyLPC_cStopwatch_setNow(&sw);
255     while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec)
256     {
257         //MUTEX LOCK
258         lockResource(inst);
259         rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
260         //MUTEX UNLOCK
261         if(rlen>0){
262             //受信キューにデータがあれば返す。
263             b=(char*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
264             rh=(const struct NyLPC_TIPv4RxInfo*)b;
265             *o_buf_ptr=b+sizeof(struct NyLPC_TIPv4RxInfo);
266             if(o_info!=NULL){
267                 *o_info=rh;
268             }
269             unlockResource(inst);
270             NyLPC_cStopwatch_finalize(&sw);
271             return rh->size;
272         }
273         unlockResource(inst);
274         //タスクスイッチ
275         NyLPC_cThread_yield();
276     };
277     NyLPC_cStopwatch_finalize(&sw);
278     return 0;
279 }
280 /**
281  * See header file
282  */
283 static void pseek(NyLPC_TiUdpSocket_t* i_inst)
284 {
285         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
286     NyLPC_TUInt16 s;
287     const struct NyLPC_TIPv4RxInfo* rh;
288     //シークサイズを決定
289     lockResource(inst);
290     s=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
291     if(s>0){
292                 rh=(const struct NyLPC_TIPv4RxInfo*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
293                 NyLPC_cFifoBuffer_pop(&(inst->rxbuf),rh->size+sizeof(struct NyLPC_TIPv4RxInfo));
294     }
295     unlockResource(inst);
296 }
297
298 /**
299  * See header file.
300  */
301 static void* allocSendBuf(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
302 {
303     NyLPC_TUInt16 s;
304     void* buf;
305     NyLPC_TcStopwatch_t sw;
306
307     NyLPC_cStopwatch_initialize(&sw);
308     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
309
310     //送信バッファを取得
311     //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
312     for(;;){
313         buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_UDPIP_HEADER),&s);
314         if(buf!=NULL){
315             break;
316         }
317         //タイムアウト確認
318         if(NyLPC_cStopwatch_isExpired(&sw)){
319             return NULL;
320         }
321     }
322     //バッファサイズ確定。
323     *o_buf_size=s;
324     NyLPC_cStopwatch_finalize(&sw);
325     return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_UDPIP_HEADER;
326 }
327 /**
328  * See Header file.
329  */
330 static void releaseSendBuf(NyLPC_TiUdpSocket_t* i_inst,void* i_buf_ptr)
331 {
332     NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER);
333 }
334
335 /**
336  * See header file
337  */
338 static NyLPC_TBool psend(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_port,void* i_buf_ptr,int i_len)
339 {
340     void* buf;
341         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
342      //ブロードキャストの場合、フラグを確認
343     if(NyLPC_TIPv4Addr_isEqual(i_addr,&NyLPC_TIPv4Addr_BROADCAST)){
344         if(!NyLPC_TUInt8_isBitOn(inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST)){
345             return NyLPC_TBool_FALSE;
346         }
347     }
348
349     //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
350     buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER;
351
352     lockResource(inst);
353     //IPv4ペイロードの書き込み
354     setUdpTxBufHeader(inst,buf,i_addr,i_port,0x05,i_len);
355     unlockResource(inst);
356     // !(BroadCast || Multicast)の場合は送信前にARPテーブルをチェックする。
357     if(!(NyLPC_TIPv4Addr_isEqual(i_addr,&NyLPC_TIPv4Addr_BROADCAST) || NyLPC_TIPv4Addr_isEqualWithMask(i_addr,&NyLPC_TIPv4Addr_MULTICAST,&NyLPC_TIPv4Addr_MULTICAST_MASK))){
358         if(!NyLPC_cMiMicIpNetIf_hasArpInfo(i_addr)){
359             NyLPC_cMiMicIpNetIf_sendArpRequest(i_addr);
360             NyLPC_cThread_sleep(30);
361         }
362     }
363     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
364     NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
365     return NyLPC_TBool_TRUE;
366 }
367
368 /**
369  * See header file.
370  */
371 static NyLPC_TInt32 send(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_port,const void* i_buf_ptr,NyLPC_TInt32 i_len,NyLPC_TUInt32 i_wait_in_msec)
372 {
373     NyLPC_TUInt16 s;
374     int i;
375     void* buf;
376     if(i_len<1 || i_len>1200){
377         return 0;
378     }
379     //バッファの取得確率を上げるために2倍のサイズを要求
380     for(i=0;i<3;i++){
381         buf=allocSendBuf(i_inst,i_len*2,&s,i_wait_in_msec);
382         if(buf==NULL || s<i_len){
383             continue;
384         }
385         break;
386     }
387     if(buf==NULL){
388         return -1;
389     }
390     //送信サイズの計算
391     memcpy(buf,i_buf_ptr,i_len);
392     if(!psend(i_inst,i_addr,i_port,buf,i_len)){
393         releaseSendBuf(i_inst,buf);
394         return -1;
395     }
396     return i_len;
397 }
398
399 static void setOnRxHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onRxHandler i_handler)
400 {
401         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
402         inst->as_handler.rx=i_handler;
403 }
404 static void setOnPeriodicHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onPeriodicHandler i_handler)
405 {
406         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
407         inst->as_handler.periodic=i_handler;
408 }
409 static const struct NyLPC_TIPv4Addr* getSockIP(const NyLPC_TiUdpSocket_t* i_inst)
410 {
411         NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
412         return &inst->uip_udp_conn.lipaddr;
413 }
414
415
416 void NyLPC_cMiMicIpUdpSocket_startService(NyLPC_TcMiMicIpUdpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)
417 {
418     i_inst->uip_udp_conn.lipaddr=i_config->ip_addr;
419     //受信バッファのクリア
420     NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
421     return;
422 }
423
424
425 void NyLPC_cMiMicIpUdpSocket_stopService(NyLPC_TcMiMicIpUdpSocket_t* i_inst)
426 {
427     //停止処理?
428 }
429
430