This is Webservice SDK for mbed. LPCXpresso1769/LPC1768/FRDM-K64F/LPC4088

Dependents:   MbedFileServer_1768MiniDK2 RedWireBridge IssueDebug_gcc MiMicRemoteMCU-for-Mbed ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NyLPC_cMiMicIpUdpSocket.c Source File

NyLPC_cMiMicIpUdpSocket.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  * Parts of this file were leveraged from uIP:
00027  *
00028  * Copyright (c) 2001-2003, Adam Dunkels.
00029  * All rights reserved.
00030  *
00031  * Redistribution and use in source and binary forms, with or without
00032  * modification, are permitted provided that the following conditions
00033  * are met:
00034  * 1. Redistributions of source code must retain the above copyright
00035  *    notice, this list of conditions and the following disclaimer.
00036  * 2. Redistributions in binary form must reproduce the above copyright
00037  *    notice, this list of conditions and the following disclaimer in the
00038  *    documentation and/or other materials provided with the distribution.
00039  * 3. The name of the author may not be used to endorse or promote
00040  *    products derived from this software without specific prior
00041  *    written permission.
00042  *
00043  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00044  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00045  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00046  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00047  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00048  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00049  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00050  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00051  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00052  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00053  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00054  */
00055 #include "NyLPC_cMiMicIpUdpSocket_protected.h"
00056 #include "NyLPC_cIPv4Payload_protected.h"
00057 #include "NyLPC_cMiMicIpNetIf_protected.h"
00058 
00059 /**
00060  * フラグ値
00061  */
00062 #define NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST 0
00063 /**
00064  * UDP/IPヘッダのサイズ
00065  */
00066 #define SIZE_OF_IPv4_UDPIP_HEADER 28
00067 
00068 #define lockResource(i_inst) NyLPC_cMutex_lock(((i_inst)->_smutex))
00069 #define unlockResource(i_inst) NyLPC_cMutex_unlock(((i_inst)->_smutex))
00070 
00071 /*
00072  *   関数テーブル
00073  */
00074 static void joinMulticast(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr);
00075 static void setBroadcast(NyLPC_TiUdpSocket_t* i_inst);
00076 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);
00077 static void pseek(NyLPC_TiUdpSocket_t* i_inst);
00078 static void* allocSendBuf(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec);
00079 static void releaseSendBuf(NyLPC_TiUdpSocket_t* i_inst,void* i_buf_ptr);
00080 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);
00081 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);
00082 static void setOnRxHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onRxHandler i_handler);
00083 static void setOnPeriodicHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onPeriodicHandler i_handler);
00084 static const struct NyLPC_TIPv4Addr* getSockIP(const NyLPC_TiUdpSocket_t* i_inst);
00085 static void finalize(NyLPC_TiUdpSocket_t* i_inst);
00086 
00087 static const struct NyLPC_TiUdpSocket_Interface interface=
00088 {
00089     joinMulticast,
00090     setBroadcast,
00091     precv,
00092     pseek,
00093     allocSendBuf,
00094     releaseSendBuf,
00095     psend,
00096     send,
00097     setOnRxHandler,
00098     setOnPeriodicHandler,
00099     getSockIP,
00100     finalize
00101 };
00102 
00103 
00104 
00105 
00106 /*
00107  *  Initializer/Finalizer
00108  */
00109 
00110 
00111 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_initialize(NyLPC_TcMiMicIpUdpSocket_t* i_inst,NyLPC_TUInt16 i_port,void* i_rbuf,NyLPC_TUInt16 i_rbuf_len)
00112 {
00113     NyLPC_TcMiMicIpNetIf_t* srv=_NyLPC_TcMiMicIpNetIf_inst;
00114     i_inst->_super._interface=&interface;
00115     i_inst->_super._tag=NULL;
00116     //uipサービスは初期化済であること。
00117     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
00118     i_inst->_smutex=NyLPC_cIPv4_getSockMutex(&(srv->_tcpv4));
00119     i_inst->uip_udp_conn.lport=NyLPC_htons(i_port);
00120     i_inst->uip_udp_conn.mcastaddr=NyLPC_TIPv4Addr_ZERO;
00121     i_inst->uip_udp_conn.flags=0x00;
00122     i_inst->as_handler.rx=NULL;
00123     i_inst->as_handler.periodic=NULL;
00124 
00125     NyLPC_cFifoBuffer_initialize(&(i_inst->rxbuf),i_rbuf,i_rbuf_len);
00126     //管理リストへ登録。
00127     return NyLPC_TBool_TRUE;
00128 }
00129 
00130 
00131 
00132 /**
00133  * IP+UDPヘッダサイズを0x05*4+8バイトとして、UDPの送信バッファをセットします。
00134  */
00135 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)
00136 {
00137     struct NyLPC_TIPv4Header* header=(struct NyLPC_TIPv4Header*)i_buf;
00138     struct NyLPC_TUdpHeader* udp    =(struct NyLPC_TUdpHeader*)(((NyLPC_TUInt8*)i_buf)+i_iph_word*4);
00139 
00140     header->vhl=0x40|(0x0f&i_iph_word);
00141     header->len16=NyLPC_htons(i_payload_size+(i_iph_word*4+8));
00142     udp->udplen=NyLPC_htons(i_payload_size+(8));
00143     //IPv4のTxヘッダを書き込む。
00144     header->destipaddr=*i_dest_ip;
00145     header->srcipaddr =i_inst->uip_udp_conn.lipaddr;
00146 
00147     NyLPC_TIPv4Header_writeTxIpHeader(header,UIP_PROTO_UDP);
00148 
00149     //UDPのTxヘッダを書き込む
00150     //sorce & destination port
00151     udp->srcport  = i_inst->uip_udp_conn.lport;
00152     udp->destport = NyLPC_htons(i_dest_port);
00153     udp->udpchksum= 0;
00154 
00155     udp->udpchksum=~(NyLPC_TIPv4Header_makeTcpChecksum(header));
00156     header->ipchksum = ~(NyLPC_TIPv4Header_makeIpChecksum(header));
00157 }
00158 
00159 
00160 
00161 
00162 /**
00163  * この関数は、rxパケットを処理して、ソケットの状態を更新します。
00164  * uipサービスタスクが実行する関数です。
00165  * この関数はNyLPC_cTcpSocket_periodicと排他実行すること。
00166  */
00167 NyLPC_TBool NyLPC_cMiMicIpUdpSocket_parseRx(
00168     NyLPC_TcMiMicIpUdpSocket_t* i_inst,
00169     const NyLPC_TcIPv4Payload_t* i_ipp)
00170 {
00171     NyLPC_TUInt16 tmp16;
00172     struct NyLPC_TIPv4RxInfo dheader;
00173     const void* data_offset;
00174     //ブロードキャストの場合、フラグを確認
00175     if(NyLPC_TIPv4Addr_isEqual(&(i_ipp->header->destipaddr),&NyLPC_TIPv4Addr_BROADCAST)){
00176         if(!NyLPC_TUInt8_isBitOn(i_inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST)){
00177             goto DROP;
00178         }
00179     }
00180     //パラメータの計算
00181     tmp16=NyLPC_TUdpHeader_getHeaderLength(i_ipp->payload.tcp);
00182     //UDPペイロードの長さは、IPパケットの長さ-(IPヘッダ+UDPヘッダ)
00183     dheader.size=NyLPC_TIPv4Header_getPacketLength(i_ipp->header)-NyLPC_TIPv4Header_getHeaderLength(i_ipp->header)-tmp16;
00184     dheader.peer_ip=i_ipp->header->srcipaddr;
00185     dheader.peer_port=NyLPC_ntohs(i_ipp->payload.udp->srcport);
00186     dheader.ip=i_ipp->header->destipaddr;
00187     dheader.port=NyLPC_ntohs(i_ipp->payload.udp->destport);
00188     if(i_inst->as_handler.rx!=NULL){
00189         if(!i_inst->as_handler.rx((NyLPC_TiUdpSocket_t*)(i_inst),i_ipp->payload.rawbuf+tmp16,&dheader)){
00190             return NyLPC_TBool_FALSE;//UDPはReturnパケットなし
00191         }
00192     }
00193     //TCPデータオフセット
00194     data_offset=i_ipp->payload.rawbuf+tmp16;
00195 
00196     //インスタンスをロックする。
00197     lockResource(i_inst);
00198     //受信キューへ追加(データ構造はsize[2]+data[n]).sizeに16ビットの受信サイズ,後続にデータ
00199 
00200     //受信データサイズを確認
00201     if(NyLPC_cFifoBuffer_getSpace(&(i_inst->rxbuf))<dheader.size+sizeof(struct NyLPC_TIPv4RxInfo)){
00202         goto DROP;
00203     }
00204     //バッファに格納可能なら、格納。
00205     NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),&dheader,sizeof(struct NyLPC_TIPv4RxInfo));
00206     NyLPC_cFifoBuffer_push(&(i_inst->rxbuf),data_offset,dheader.size);
00207     unlockResource(i_inst);
00208     return NyLPC_TBool_FALSE;//UDPはReturnパケットなし
00209 DROP:
00210     unlockResource(i_inst);
00211     return NyLPC_TBool_FALSE;
00212 }
00213 
00214 
00215 
00216 
00217 static void finalize(NyLPC_TiUdpSocket_t* i_inst)
00218 {
00219     NyLPC_Assert(NyLPC_cMiMicIpNetIf_isInitService());
00220 
00221     NyLPC_cFifoBuffer_finalize(&(i_inst->rxbuf));
00222     NyLPC_cMiMicIpNetIf_releaseUdpSocketMemory((NyLPC_TcMiMicIpUdpSocket_t*)i_inst);
00223     return;
00224 }
00225 
00226 
00227 static void joinMulticast(NyLPC_TiUdpSocket_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr)
00228 {
00229     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00230     inst->uip_udp_conn.mcastaddr=*i_addr;
00231 }
00232 static void setBroadcast(NyLPC_TiUdpSocket_t* i_inst)
00233 {
00234     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00235     NyLPC_TUInt8_setBit(inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST);
00236 }
00237 
00238 
00239 
00240 /**
00241  * see Header file
00242  */
00243 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)
00244 {
00245     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00246     NyLPC_TUInt16 rlen;
00247     //タイマを生成
00248     NyLPC_TcStopwatch_t sw;
00249     NyLPC_cStopwatch_initialize(&sw);
00250     const char* b;
00251     const struct NyLPC_TIPv4RxInfo* rh;
00252 
00253     //ESTABLISHED以外の場合は、エラー。
00254     NyLPC_cStopwatch_setNow(&sw);
00255     while(NyLPC_cStopwatch_elapseInMsec(&sw)<i_wait_msec)
00256     {
00257         //MUTEX LOCK
00258         lockResource(inst);
00259         rlen=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
00260         //MUTEX UNLOCK
00261         if(rlen>0){
00262             //受信キューにデータがあれば返す。
00263             b=(char*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
00264             rh=(const struct NyLPC_TIPv4RxInfo*)b;
00265             *o_buf_ptr=b+sizeof(struct NyLPC_TIPv4RxInfo);
00266             if(o_info!=NULL){
00267                 *o_info=rh;
00268             }
00269             unlockResource(inst);
00270             NyLPC_cStopwatch_finalize(&sw);
00271             return rh->size;
00272         }
00273         unlockResource(inst);
00274         //タスクスイッチ
00275         NyLPC_cThread_yield();
00276     };
00277     NyLPC_cStopwatch_finalize(&sw);
00278     return 0;
00279 }
00280 /**
00281  * See header file
00282  */
00283 static void pseek(NyLPC_TiUdpSocket_t* i_inst)
00284 {
00285     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00286     NyLPC_TUInt16 s;
00287     const struct NyLPC_TIPv4RxInfo* rh;
00288     //シークサイズを決定
00289     lockResource(inst);
00290     s=NyLPC_cFifoBuffer_getLength(&(inst->rxbuf));
00291     if(s>0){
00292         rh=(const struct NyLPC_TIPv4RxInfo*)NyLPC_cFifoBuffer_getPtr(&(inst->rxbuf));
00293         NyLPC_cFifoBuffer_pop(&(inst->rxbuf),rh->size+sizeof(struct NyLPC_TIPv4RxInfo));
00294     }
00295     unlockResource(inst);
00296 }
00297 
00298 /**
00299  * See header file.
00300  */
00301 static void* allocSendBuf(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_buf_size,NyLPC_TUInt32 i_wait_in_msec)
00302 {
00303     NyLPC_TUInt16 s;
00304     void* buf;
00305     NyLPC_TcStopwatch_t sw;
00306 
00307     NyLPC_cStopwatch_initialize(&sw);
00308     NyLPC_cStopwatch_startExpire(&sw,i_wait_in_msec);
00309 
00310     //送信バッファを取得
00311     //@bug バッファが取れるまで通信がブロックするの。ここはなんとかしないと。
00312     for(;;){
00313         buf=NyLPC_cMiMicIpNetIf_allocTxBuf(i_hint+(SIZE_OF_IPv4_UDPIP_HEADER),&s);
00314         if(buf!=NULL){
00315             break;
00316         }
00317         //タイムアウト確認
00318         if(NyLPC_cStopwatch_isExpired(&sw)){
00319             return NULL;
00320         }
00321     }
00322     //バッファサイズ確定。
00323     *o_buf_size=s;
00324     NyLPC_cStopwatch_finalize(&sw);
00325     return (NyLPC_TUInt8*)buf+SIZE_OF_IPv4_UDPIP_HEADER;
00326 }
00327 /**
00328  * See Header file.
00329  */
00330 static void releaseSendBuf(NyLPC_TiUdpSocket_t* i_inst,void* i_buf_ptr)
00331 {
00332     NyLPC_cMiMicIpNetIf_releaseTxBuf((NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER);
00333 }
00334 
00335 /**
00336  * See header file
00337  */
00338 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)
00339 {
00340     void* buf;
00341     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00342      //ブロードキャストの場合、フラグを確認
00343     if(NyLPC_TIPv4Addr_isEqual(i_addr,&NyLPC_TIPv4Addr_BROADCAST)){
00344         if(!NyLPC_TUInt8_isBitOn(inst->uip_udp_conn.flags,NyLPC_cMiMicIpUdpSocket_FLAG_BROADCAST)){
00345             return NyLPC_TBool_FALSE;
00346         }
00347     }
00348 
00349     //先頭ポインタは、i_buf-sizeof(SIZE_OF_IPv4_TCPIP_HEADER)固定
00350     buf=(NyLPC_TUInt8*)i_buf_ptr-SIZE_OF_IPv4_UDPIP_HEADER;
00351 
00352     lockResource(inst);
00353     //IPv4ペイロードの書き込み
00354     setUdpTxBufHeader(inst,buf,i_addr,i_port,0x05,i_len);
00355     unlockResource(inst);
00356     // !(BroadCast || Multicast)の場合は送信前にARPテーブルをチェックする。
00357     if(!(NyLPC_TIPv4Addr_isEqual(i_addr,&NyLPC_TIPv4Addr_BROADCAST) || NyLPC_TIPv4Addr_isEqualWithMask(i_addr,&NyLPC_TIPv4Addr_MULTICAST,&NyLPC_TIPv4Addr_MULTICAST_MASK))){
00358         if(!NyLPC_cMiMicIpNetIf_hasArpInfo(i_addr)){
00359             NyLPC_cMiMicIpNetIf_sendArpRequest(i_addr);
00360             NyLPC_cThread_sleep(30);
00361         }
00362     }
00363     NyLPC_cMiMicIpNetIf_sendIPv4Tx(buf);
00364     NyLPC_cMiMicIpNetIf_releaseTxBuf(buf);
00365     return NyLPC_TBool_TRUE;
00366 }
00367 
00368 /**
00369  * See header file.
00370  */
00371 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)
00372 {
00373     NyLPC_TUInt16 s;
00374     int i;
00375     void* buf;
00376     if(i_len<1 || i_len>1200){
00377         return 0;
00378     }
00379     //バッファの取得確率を上げるために2倍のサイズを要求
00380     for(i=0;i<3;i++){
00381         buf=allocSendBuf(i_inst,i_len*2,&s,i_wait_in_msec);
00382         if(buf==NULL || s<i_len){
00383             continue;
00384         }
00385         break;
00386     }
00387     if(buf==NULL){
00388         return -1;
00389     }
00390     //送信サイズの計算
00391     memcpy(buf,i_buf_ptr,i_len);
00392     if(!psend(i_inst,i_addr,i_port,buf,i_len)){
00393         releaseSendBuf(i_inst,buf);
00394         return -1;
00395     }
00396     return i_len;
00397 }
00398 
00399 static void setOnRxHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onRxHandler i_handler)
00400 {
00401     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00402     inst->as_handler.rx=i_handler;
00403 }
00404 static void setOnPeriodicHandler(NyLPC_TiUdpSocket_t* i_inst,NyLPC_TiUdpSocket_onPeriodicHandler i_handler)
00405 {
00406     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00407     inst->as_handler.periodic=i_handler;
00408 }
00409 static const struct NyLPC_TIPv4Addr* getSockIP(const NyLPC_TiUdpSocket_t* i_inst)
00410 {
00411     NyLPC_TcMiMicIpUdpSocket_t* inst=(NyLPC_TcMiMicIpUdpSocket_t*)i_inst;
00412     return &inst->uip_udp_conn.lipaddr;
00413 }
00414 
00415 
00416 void NyLPC_cMiMicIpUdpSocket_startService(NyLPC_TcMiMicIpUdpSocket_t* i_inst,const NyLPC_TcIPv4Config_t* i_config)
00417 {
00418     i_inst->uip_udp_conn.lipaddr=i_config->ip_addr;
00419     //受信バッファのクリア
00420     NyLPC_cFifoBuffer_clear(&(i_inst->rxbuf));
00421     return;
00422 }
00423 
00424 
00425 void NyLPC_cMiMicIpUdpSocket_stopService(NyLPC_TcMiMicIpUdpSocket_t* i_inst)
00426 {
00427     //停止処理?
00428 }
00429 
00430