1 /*********************************************************************************
3 * --------------------------------------------------------------------------------
5 * This file is part of MiMic
6 * Copyright (C)2011 Ryo Iizuka
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.
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.
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/>.
21 * For further information please contact.
23 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
26 * Parts of this file were leveraged from uIP:
28 * Copyright (c) 2001-2003, Adam Dunkels.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
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
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.
55 #include "NyLPC_cMiMicIpUdpSocket_protected.h"
56 #include "NyLPC_cIPv4Payload_protected.h"
57 #include "NyLPC_cMiMicIpNetIf_protected.h"
62 #define NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST 0
66 #define SIZE_OF_IPv4_UDPIP_HEADER 28
68 #define lockResource(i_inst) NyLPC_cMutex_lock(((i_inst)->_smutex))
69 #define unlockResource(i_inst) NyLPC_cMutex_unlock(((i_inst)->_smutex))
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);
87 static const struct NyLPC_TiUdpSocket_Interface interface=
107 * Initializer/Finalizer
111 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_initialize(NyLPC_TcMiMicIpUdpSocket_t* i_inst,NyLPC_TUInt16 i_port,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
113 NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst;
114 i_inst->_super._interface=&interface;
115 i_inst->_super._tag=NULL;
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;
125 NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
127 return NyLPC_TBool_TRUE;
133 * IP+UDPヘッダサイズを0x05*4+8バイトとして、UDPの送信バッファをセットします。
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)
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);
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));
144 header->destipaddr=*i_dest_ip;
145 header->srcipaddr =i_inst->uip_udp_conn.lipaddr;
147 NyLPC_TIPv4Header_writeTxIpHeader(header,UIP_PROTO_UDP);
150 //sorce & destination port
151 udp->srcport = i_inst->uip_udp_conn.lport;
152 udp->destport = NyLPC_htons(i_dest_port);
155 udp->udpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(header));
156 header->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(header));
163 * この関数は、rxパケットを処理して、ソケットの状態を更新します。
164 * uipサービスタスクが実行する関数です。
165 * この関数はNyLPC_cTcpSocket_periodicと排他実行すること。
167 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_parseRx(
168 NyLPC_TcMiMicIpUdpSocket_t* i_inst,
169 const NyLPC_TcIPv4Payload_t* i_ipp)
172 struct NyLPC_TIPv4RxInfo dheader;
173 const void* data_offset;
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)){
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パケットなし
194 data_offset=i_ipp->payload.rawbuf+tmp16;
197 lockResource(i_inst);
198 //受信キューへ追加(データ構造はsize[2]+data[n]).sizeに16ビットの受信サイズ,後続にデータ
201 if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))<dheader.size+sizeof(struct NyLPC_TIPv4RxInfo)){
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パケットなし
210 unlockResource(i_inst);
211 return NyLPC_TBool_FALSE;
217 static void finalize(NyLPC_TiUdpSocket_t* i_inst)
219 NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
221 NyLPC_cFifoBuffer_finalize(&(i_inst->rxbuf));
222 NyLPC_cMiMicIpNetIf_releaseUdpSocketMemory((NyLPC_TcMiMicIpUdpSocket_t*)i_inst);
227 static void joinMulticast(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr)
229 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
230 inst->uip_udp_conn.mcastaddr=*i_addr;
232 static void setBroadcast(NyLPC_TiUdpSocket_t* i_inst)
234 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
235 NyLPC_TUInt8_setBit(inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST);
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)
245 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
248 NyLPC_TcStopwatch_t sw;
249 NyLPC_cStopwatch_initialize(&sw);
251 const struct NyLPC_TIPv4RxInfo* rh;
253 //ESTABLISHED以外の場合は、エラー。
254 NyLPC_cStopwatch_setNow(&sw);
255 while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec)
259 rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
263 b=(char*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
264 rh=(const struct NyLPC_TIPv4RxInfo*)b;
265 *o_buf_ptr=b+sizeof(struct NyLPC_TIPv4RxInfo);
269 unlockResource(inst);
270 NyLPC_cStopwatch_finalize(&sw);
273 unlockResource(inst);
275 NyLPC_cThread_yield();
277 NyLPC_cStopwatch_finalize(&sw);
283 static void pseek(NyLPC_TiUdpSocket_t* i_inst)
285 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
287 const struct NyLPC_TIPv4RxInfo* rh;
290 s=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
292 rh=(const struct NyLPC_TIPv4RxInfo*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
293 NyLPC_cFifoBuffer_pop(&(inst->rxbuf),rh->size+sizeof(struct NyLPC_TIPv4RxInfo));
295 unlockResource(inst);
301 static void* allocSendBuf(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
305 NyLPC_TcStopwatch_t sw;
307 NyLPC_cStopwatch_initialize(&sw);
308 NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
311 //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
313 buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_UDPIP_HEADER),&s);
318 if(NyLPC_cStopwatch_isExpired(&sw)){
324 NyLPC_cStopwatch_finalize(&sw);
325 return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_UDPIP_HEADER;
330 static void releaseSendBuf(NyLPC_TiUdpSocket_t* i_inst,void* i_buf_ptr)
332 NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER);
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)
341 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
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;
349 //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
350 buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER;
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);
363 NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
364 NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
365 return NyLPC_TBool_TRUE;
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)
376 if(i_len<1 || i_len>1200){
379 //バッファの取得確率を上げるために2倍のサイズを要求
381 buf=allocSendBuf(i_inst,i_len*2,&s,i_wait_in_msec);
382 if(buf==NULL || s<i_len){
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);
399 static void setOnRxHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onRxHandler i_handler)
401 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
402 inst->as_handler.rx=i_handler;
404 static void setOnPeriodicHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onPeriodicHandler i_handler)
406 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
407 inst->as_handler.periodic=i_handler;
409 static const struct NyLPC_TIPv4Addr* getSockIP(const NyLPC_TiUdpSocket_t* i_inst)
411 NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
412 return &inst->uip_udp_conn.lipaddr;
416 void NyLPC_cMiMicIpUdpSocket_startService(NyLPC_TcMiMicIpUdpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)
418 i_inst->uip_udp_conn.lipaddr=i_config->ip_addr;
420 NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
425 void NyLPC_cMiMicIpUdpSocket_stopService(NyLPC_TcMiMicIpUdpSocket_t* i_inst)