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_cSsdpSocket.c Source File

NyLPC_cSsdpSocket.c

00001 /*********************************************************************************
00002  * PROJECT: MiMic
00003  * --------------------------------------------------------------------------------
00004  *
00005  * This file is part of MiMic
00006  * Copyright (C)2011 Ryo Iizuka
00007  *
00008  * MiMic is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU Lesser General Public License as published
00010  * by the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public License
00019  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  *
00021  * For further information please contact.
00022  *  http://nyatla.jp/
00023  *  <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
00024  *
00025  *********************************************************************************/
00026 #include "NyLPC_cSsdpSocket.h"
00027 #include "NyLPC_http.h"
00028 #include "NyLPC_netif.h"
00029 
00030 
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 
00035 
00036 
00037 
00038 #define HTTP_SP 0x20
00039 
00040 #define PARSE_NULL  0
00041 #define PARSE_ST    0x01
00042 #define PARSE_MAN   0x11
00043 #define PARSE_UNKNOWN 0xff
00044 
00045 static const struct NyLPC_TIPv4Addr SSDP_MCAST_IPADDR=NyLPC_TIPv4Addr_pack(239,255,255,250);
00046 static const char* STR_UPNP_ROOT_DEVICE="upnp:rootdevice";
00047 
00048 struct TMSearchHeader
00049 {
00050     struct NyLPC_THttpBasicHeader super;
00051 
00052     const struct NyLPC_TUPnPDeviceRecord* _ref_devices;
00053     /**
00054      * パーサのステータス
00055      */
00056     NyLPC_TUInt8 st;
00057     /**
00058      * メモリ位置
00059      */
00060     const NyLPC_TChar* _rpos;
00061     struct{
00062         const NyLPC_TChar* st_str;
00063         const NyLPC_TChar* man_str;
00064         NyLPC_TUInt16 st_len;
00065         NyLPC_TUInt16 man_len;
00066     }result;
00067 };
00068 
00069 //とりあえずprivate
00070 void NyLPC_cSsdpSocket_notify(NyLPC_TcSsdpSocket_t* i_inst);
00071 
00072 
00073 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
00074 {
00075 // *であるかを確認 未実装
00076     return NyLPC_TBool_TRUE;
00077 }
00078 
00079 #define TIMEOUT_IN_MS 100
00080 
00081 /**
00082  * SERVER MessageHeaderの値
00083  * 40文字以内であること。
00084  */
00085 #define SERVER_MESSAGE_HEADER "MiMic/1.4 UPnP/1.0 MiMicUPnP/0.2"
00086 
00087 
00088 /**
00089  * MsearchResponseを格納したTxパケットをAllocする。
00090  * @param i_st
00091  * ST値
00092  * @param i_udn
00093  * DDESCのUDNの値
00094  * @param i_usn
00095  * USNのサフィックスパラメータ
00096  * @return
00097  * MsearchResponseを格納したTXメモリ
00098  */
00099 static void* allocMsearchResponeTx(
00100     NyLPC_TcSsdpSocket_t* i_inst,
00101     const NyLPC_TChar* i_st,
00102     const NyLPC_TChar* i_udn,
00103     const NyLPC_TChar* i_usn,
00104     NyLPC_TUInt16 i_st_len,
00105     NyLPC_TInt16* o_len)
00106 {
00107     NyLPC_TChar* obuf;
00108     NyLPC_TUInt16 l;
00109     NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)((i_usn!=NULL)?strlen(i_usn):0);
00110     NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);
00111     NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);
00112 
00113     //  //161Byte
00114     //  "HTTP/1.1 200 OK\r\n"                           //15+2=17
00115     //  "CACHE-CONTROL: max-age = nnnn\r\n"             //29+2=31
00116     //  "SERVER: [:40byte:]\r\n"                        //8+40+2=50
00117     //  "EXT: \r\n"                                     //5+2 = 7
00118     //  "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"   //34+2=46
00119     //  "USN: %s%s\r\n"                                 //5+2=7
00120     //  "ST: %s\r\n\r\n"                                //4+4=8
00121     l=166+len_location+len_usn+len_udn+i_st_len;
00122     obuf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,l,&l,TIMEOUT_IN_MS);
00123 
00124     if(obuf==NULL){
00125         return NULL;
00126     }
00127     //必要なメモリサイズを確保できた?
00128     if(l<161+len_location+len_usn+len_udn+i_st_len)
00129     {
00130         NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,obuf);
00131         return NULL;
00132     }
00133     //ワーク変数lの再初期化
00134     l=0;
00135     strcpy(obuf,
00136         "HTTP/1.1 200 OK\r\n"
00137         "CACHE-CONTROL: max-age = 300\r\n"
00138         "SERVER: "SERVER_MESSAGE_HEADER"\r\n"
00139         "EXT: \r\n"
00140         "LOCATION: http://");
00141     l+=strlen(obuf);
00142     //IP addr:port\r\n
00143     l+=NyLPC_TIPv4Addr_toString(NyLPC_iUdpSocket_getSockIP(i_inst->_socket),obuf+l);
00144     *(obuf+l)=':';
00145     l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);
00146     *(obuf+l)='/';l++;
00147     memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;
00148     memcpy(obuf+l,"/d.xml",6);l+=6;
00149     *(obuf+l+0)='\r';
00150     *(obuf+l+1)='\n';
00151     l+=2;
00152     //USN: uuid:xxx
00153     memcpy(obuf+l,"USN: ",5);       l+=5;
00154     memcpy(obuf+l,i_udn,len_udn);   l+=len_udn; //uuid:xxx
00155     if(i_usn!=NULL){
00156         *(obuf+l+0)=':';
00157         *(obuf+l+1)=':';
00158         l+=2;
00159         memcpy(obuf+l,i_usn,len_usn);l+=len_usn;    //usn:xxx
00160     }
00161     *(obuf+l+0)='\r';
00162     *(obuf+l+1)='\n';
00163     l+=2;
00164     //ST
00165     memcpy(obuf+l,"ST: ",4);    l+=4;
00166     memcpy(obuf+l,i_st,i_st_len);l+=i_st_len;
00167     memcpy(obuf+l,"\r\n\r\n",4);    l+=4;
00168     *o_len=l;
00169     return obuf;
00170 }
00171 
00172 
00173 /**
00174  * MsearchResponseを格納したTxパケットをAllocする。
00175  * @param i_udn
00176  * udn
00177  * @param i_udn
00178  * DDESCのUDNの値
00179  * @param i_usn
00180  * USNのサフィックスパラメータ
00181  * @return
00182  * MsearchResponseを格納したTXメモリ
00183  */
00184 static void* allocNotifyTx(
00185     NyLPC_TcSsdpSocket_t* i_inst,
00186     const NyLPC_TChar* i_udn,
00187     const NyLPC_TChar* i_usn,
00188     NyLPC_TInt16* o_len)
00189 {
00190     NyLPC_TChar* obuf;
00191     NyLPC_TUInt16 l,l2;
00192     NyLPC_TUInt16 len_usn=(NyLPC_TUInt16)((i_usn!=NULL)?strlen(i_usn):0);
00193     NyLPC_TUInt16 len_udn=(NyLPC_TUInt16)strlen(i_udn);
00194     NyLPC_TUInt16 len_location=(NyLPC_TUInt16)strlen(i_inst->location_path);
00195 
00196     //  //193Byte
00197     //  "NOTIFY * HTTP/1.1\r\n"                         //15+2=17
00198     //  "HOST: 239.255.255.250:1900\r\n"                //26+2=28
00199     //  "CACHE-CONTROL: max-age = 1800\r\n"             //29+2=31
00200     //  "SERVER: [:40byte:]\r\n"                        //8+40+2=50
00201     //  "NTS: ssdp:alive\r\n"                           //14+2 =17
00202     //  "LOCATION: http://xxx.xxx.xxx.xxx:nnnnn/%s/d.xml\r\n"//44+2=46
00203     //  "USN: %s%s\r\n"                                 //5+2=7
00204     //  "NT: %s\r\n\r\n"                                //4+4=8
00205     l2=204+len_location+len_usn+len_udn+((len_usn>0)?len_usn:len_udn);
00206     obuf=NyLPC_iUdpSocket_allocSendBuf(i_inst->_socket,l2,&l,TIMEOUT_IN_MS);
00207     if(obuf==NULL){
00208         return NULL;
00209     }
00210     //必要なメモリサイズを確保できた?
00211     if(l<l2)
00212     {
00213         NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,obuf);
00214         return NULL;
00215     }
00216     //ワーク変数lの再初期化
00217     l=0;
00218     strcpy(obuf,
00219         "NOTIFY * HTTP/1.1\r\n"
00220         "HOST: 239.255.255.250:1900\r\n"
00221         "CACHE-CONTROL: max-age = 300\r\n"
00222         "SERVER: "SERVER_MESSAGE_HEADER"\r\n"
00223         "NTS: ssdp:alive\r\n"
00224         "LOCATION: http://");
00225     l+=strlen(obuf);
00226     //IP addr:port\r\n
00227     l+=NyLPC_TIPv4Addr_toString(NyLPC_iUdpSocket_getSockIP(i_inst->_socket),obuf+l);
00228     *(obuf+l)=':';
00229     l+=1+NyLPC_itoa(i_inst->location_port,obuf+l+1,10);
00230     *(obuf+l)='/';l++;
00231     memcpy(obuf+l,i_inst->location_path,len_location);l+=len_location;
00232     memcpy(obuf+l,"/d.xml",6);l+=6;
00233     *(obuf+l+0)='\r';
00234     *(obuf+l+1)='\n';
00235     l+=2;
00236     //USN: uuid:xxx
00237     memcpy(obuf+l,"USN: ",5);   l+=5;
00238     memcpy(obuf+l,i_udn,len_udn);   l+=len_udn; //uuid:xxx
00239     if(i_usn!=NULL){
00240         *(obuf+l+0)=':';
00241         *(obuf+l+1)=':';
00242         l+=2;
00243         memcpy(obuf+l,i_usn,len_usn);l+=len_usn;    //usn:xxx
00244     }
00245     *(obuf+l+0)='\r';
00246     *(obuf+l+1)='\n';
00247     l+=2;
00248     //NT
00249     memcpy(obuf+l,"NT: ",4);    l+=4;
00250     if(len_usn>0){
00251         memcpy(obuf+l,i_usn,len_usn);l+=len_usn;
00252     }else{
00253         memcpy(obuf+l,i_udn,len_udn);l+=len_udn;
00254     }
00255     memcpy(obuf+l,"\r\n\r\n",4);    l+=4;
00256     *o_len=l;
00257     return obuf;
00258 }
00259 
00260 
00261 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
00262 {
00263     struct TMSearchHeader* header=(struct TMSearchHeader*)o_out;
00264     switch(header->st)
00265     {
00266         case PARSE_NULL:
00267             if(NyLPC_stricmp(i_name,"ST")==0){
00268                 //mode==ST
00269                 header->st=PARSE_ST;
00270                 header->result.st_str=NULL;
00271             }else if(NyLPC_stricmp(i_name,"MAN")==0){
00272                 //mode=MAN
00273                 header->st=PARSE_MAN;
00274                 header->result.man_str=NULL;
00275             }else{
00276                 header->st=PARSE_UNKNOWN;
00277                 //無視
00278             }
00279             break;
00280         case PARSE_ST:
00281             if((header->result.st_str==NULL) && (i_c!=HTTP_SP)){
00282                 header->result.st_str=header->_rpos;
00283             }
00284             if(i_c=='\0')
00285             {
00286                 header->result.st_len=header->_rpos-header->result.st_str-1;
00287                 header->st=PARSE_NULL;
00288             }
00289             break;
00290         case PARSE_MAN:
00291             if((header->result.man_str==NULL) && (i_c!=HTTP_SP)){
00292                 header->result.man_str=header->_rpos;
00293             }
00294             if(i_c=='\0'){
00295                 header->result.man_len=header->_rpos-header->result.man_str-1;
00296                 header->st=PARSE_NULL;
00297             }
00298             break;
00299         case PARSE_UNKNOWN:
00300         default:
00301             if(i_c=='\0'){
00302                 header->st=PARSE_NULL;
00303             }
00304             break;
00305     }
00306     return NyLPC_TBool_TRUE;
00307 }
00308 
00309 /**
00310  * デフォルトハンドラ
00311  */
00312 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=
00313 {
00314     messageHandler,
00315     urlHandler
00316 };
00317 
00318 static NyLPC_TBool parseHeader(struct TMSearchHeader* i_out,const void* i_rx,NyLPC_TInt16 i_rx_size)
00319 {
00320     NyLPC_TInt16 i;
00321     NyLPC_TcHttpBasicHeaderParser_t parser;
00322     //headerの初期化
00323     i_out->st=PARSE_NULL;
00324     i_out->result.st_str=NULL;
00325     i_out->result.man_str=NULL;
00326     NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);
00327     NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(i_out->super));
00328     for(i=0;i<i_rx_size;i++){
00329         i_out->_rpos=((const char*)(i_rx))+i;
00330         if(NyLPC_cHttpBasicHeaderParser_parseChar(&parser,i_out->_rpos,1,&(i_out->super))<0){
00331             NyLPC_cHttpBasicHeaderParser_finalize(&parser);
00332             return NyLPC_TBool_FALSE;//ERROR
00333         }
00334     }
00335     NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(i_out->super));
00336     NyLPC_cHttpBasicHeaderParser_finalize(&parser);
00337     return NyLPC_TBool_TRUE;//OK
00338 }
00339 
00340 static NyLPC_TBool onPacket(NyLPC_TiUdpSocket_t* i_sock,const void* i_buf,const struct NyLPC_TIPv4RxInfo* i_info)
00341 {
00342     //パケット解析
00343     void* tx;
00344     struct TMSearchHeader header;
00345     NyLPC_TInt16 tx_len;
00346     NyLPC_TInt8 i,i2;
00347     NyLPC_TcSsdpSocket_t* inst=((NyLPC_TcSsdpSocket_t*)i_sock->_tag);
00348     if(!parseHeader(&header,i_buf,i_info->size)){
00349         NyLPC_OnErrorGoto(ERROR1);
00350     }
00351     //resultチェック
00352     if(header.result.man_str==NULL || header.result.st_str==NULL){
00353         NyLPC_OnErrorGoto(ERROR1);
00354     }
00355     //Methodチェック
00356     if(header.super.startline.req.method!=NyLPC_THttpMethodType_M_SEARCH){
00357         NyLPC_OnErrorGoto(ERROR1);
00358     }
00359 
00360     //MANチェック
00361     if(strncmp("\"ssdp:discover\"",header.result.man_str,15)!=0){
00362         NyLPC_OnErrorGoto(ERROR1);
00363     }
00364     //STによる処理分岐
00365     if(strncmp("ssdp:all",header.result.st_str,8)==0){
00366         tx=allocMsearchResponeTx(
00367             inst,header.result.st_str,
00368             inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,
00369             header.result.st_len,
00370             &tx_len);
00371         if(tx==NULL){
00372             NyLPC_OnErrorGoto(ERROR1);
00373         }
00374         if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00375             NyLPC_OnErrorGoto(ERROR2);
00376         }
00377         //全デバイスの送信
00378         for(i=0;i<inst->number_of_device;i++){
00379             tx=allocMsearchResponeTx(
00380                 inst,header.result.st_str,
00381                 inst->ref_device_record[i]->udn,inst->ref_device_record[i]->device_type,
00382                 header.result.st_len,
00383                 &tx_len);
00384             if(tx==NULL){
00385                 NyLPC_OnErrorGoto(ERROR1);
00386             }
00387             if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00388                 NyLPC_OnErrorGoto(ERROR2);
00389             }
00390             for(i2=0;i2<inst->ref_device_record[i]->number_of_service;i2++){
00391                 //serviceに一致
00392                 tx=allocMsearchResponeTx(
00393                     inst,header.result.st_str,
00394                     inst->ref_device_record[i]->udn,inst->ref_device_record[i]->services[i2].service_type,
00395                     header.result.st_len,
00396                     &tx_len);
00397                 if(tx==NULL){
00398                     NyLPC_OnErrorGoto(ERROR1);
00399                 }
00400                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00401                     NyLPC_OnErrorGoto(ERROR2);
00402                 }
00403             }
00404         }
00405     }else if(strncmp("uuid:",header.result.st_str,5)==0){
00406         //UDNの一致するデバイスの送信
00407         NyLPC_TInt16 i;
00408         for(i=inst->number_of_device-1;i>=0;i--){
00409             if(strncmp(header.result.st_str,inst->ref_device_record[i]->udn,header.result.st_len)==0){
00410                 //UDN一致
00411                 tx=allocMsearchResponeTx(
00412                     inst,header.result.st_str,
00413                     inst->ref_device_record[i]->udn,NULL,
00414                     header.result.st_len,
00415                     &tx_len);
00416                 if(tx==NULL){
00417                     NyLPC_OnErrorGoto(ERROR1);
00418                 }
00419                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00420                     NyLPC_OnErrorGoto(ERROR2);
00421                 }
00422                 break;//送信処理終了
00423             }
00424         }
00425     }else if(strncmp(STR_UPNP_ROOT_DEVICE,header.result.st_str,15)==0){
00426         //rootDeviceはSTR_UPNP_ROOT_DEVICE
00427         tx=allocMsearchResponeTx(
00428             inst,header.result.st_str,
00429             inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,
00430             header.result.st_len,
00431             &tx_len);
00432         if(tx==NULL){
00433             NyLPC_OnErrorGoto(ERROR1);
00434         }
00435         if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00436             NyLPC_OnErrorGoto(ERROR2);
00437         }
00438     }else if(strncmp("urn:",header.result.st_str,4)==0){
00439         for(i=0;i<inst->number_of_device;i++){
00440             //urn一致チェック
00441             if(strncmp(inst->ref_device_record[i]->device_type,header.result.st_str,header.result.st_len)==0){
00442                 //deviceに一致
00443                 tx=allocMsearchResponeTx(
00444                     inst,header.result.st_str,
00445                     inst->ref_device_record[i]->udn,inst->ref_device_record[i]->device_type,
00446                     header.result.st_len,
00447                     &tx_len);
00448                 if(tx==NULL){
00449                     NyLPC_OnErrorGoto(ERROR1);
00450                 }
00451                 if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00452                     NyLPC_OnErrorGoto(ERROR2);
00453                 }
00454                 continue;
00455             }
00456             for(i2=0;i2<inst->ref_device_record[i]->number_of_service;i2++){
00457                 if(strncmp(inst->ref_device_record[i]->services[i2].service_type,header.result.st_str,header.result.st_len)==0){
00458                     //serviceに一致
00459                     tx=allocMsearchResponeTx(
00460                         inst,header.result.st_str,
00461                         inst->ref_device_record[i]->udn,inst->ref_device_record[i]->services[i2].service_type,
00462                         header.result.st_len,
00463                         &tx_len);
00464                     if(tx==NULL){
00465                         NyLPC_OnErrorGoto(ERROR1);
00466                     }
00467                     if(!NyLPC_iUdpSocket_psend(i_sock,&i_info->peer_ip,i_info->peer_port,tx,tx_len)){
00468                         NyLPC_OnErrorGoto(ERROR2);
00469                     }
00470                 }
00471             }
00472         }
00473     }
00474     //正常終了
00475     return NyLPC_TBool_FALSE;
00476 ERROR2:
00477     NyLPC_iUdpSocket_releaseSendBuf(i_sock,tx);
00478 ERROR1:
00479     return NyLPC_TBool_FALSE;
00480 }
00481 
00482 #define SSDP_NOTIFY_INTERVAL 150*1000   //300*0.5*1000
00483 #define FLAG_ORDER_START_SERVICE    0
00484 #define FLAG_ORDER_STOP_SERVICE     1
00485 #define FLAG_IS_SERVICE_RUNNING     2
00486 
00487 static void onPeriodic(NyLPC_TiUdpSocket_t* i_sock)
00488 {
00489     NyLPC_TcSsdpSocket_t* inst=(NyLPC_TcSsdpSocket_t*)i_sock->_tag;
00490     if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_IS_SERVICE_RUNNING)){
00491     //実行中
00492         //停止要求着てる?
00493         if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_ORDER_STOP_SERVICE))
00494         {
00495             //状態変更
00496             NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_IS_SERVICE_RUNNING);
00497             //要求フラグクリア
00498             NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_ORDER_STOP_SERVICE);
00499             //@bug ByeBye送信しろ
00500         }else if(NyLPC_cStopwatch_isExpired(&inst->_periodic_sw)){
00501             //Notify送信
00502             NyLPC_cSsdpSocket_notify(inst);
00503             //タイマ再始動
00504             NyLPC_cStopwatch_startExpire(&inst->_periodic_sw,SSDP_NOTIFY_INTERVAL);
00505         }
00506     }else{
00507     //停止中
00508         //開始要求着てる?
00509         if(NyLPC_TUInt8_isBitOn(inst->_flags,FLAG_ORDER_START_SERVICE))
00510         {
00511             //状態変更
00512             NyLPC_TUInt8_setBit(inst->_flags,FLAG_IS_SERVICE_RUNNING);
00513             //要求フラグクリア
00514             NyLPC_TUInt8_unsetBit(inst->_flags,FLAG_ORDER_START_SERVICE);
00515             //次回expireするように
00516             NyLPC_cStopwatch_startExpire(&inst->_periodic_sw,SSDP_NOTIFY_INTERVAL);
00517         }
00518     }
00519 }
00520 
00521 /**
00522  * デバイスツリーを展開する。
00523  */
00524 static void expandDeviceTree(NyLPC_TcSsdpSocket_t* i_inst,const struct NyLPC_TUPnPDevDescDevice* i_dev)
00525 {
00526     NyLPC_TUInt16 i;
00527     if(i_inst->number_of_device>=NyLPC_TcSsdpSocket_MAX_DEVICES){
00528         NyLPC_Warning();//
00529     }
00530     i_inst->ref_device_record[i_inst->number_of_device]=i_dev;
00531     i_inst->number_of_device++;
00532     for(i=0;i<i_dev->number_of_devices;i++){
00533         expandDeviceTree(i_inst,i_dev->devices[i]);
00534     }
00535     return;
00536 }
00537 
00538 void NyLPC_cSsdpSocket_initialize(
00539         NyLPC_TcSsdpSocket_t* i_inst,
00540         const struct NyLPC_TUPnPDevDescDevice* i_ref_dev_record,
00541         NyLPC_TUInt16 i_server_port,const NyLPC_TChar* i_ref_location_path)
00542 {
00543     i_inst->_socket=NyLPC_cNet_createUdpSocketEx(1900,NyLPC_TSocketType_UDP_NOBUF);
00544     i_inst->_socket->_tag=i_inst;
00545 
00546     NyLPC_iUdpSocket_setOnRxHandler(i_inst->_socket,onPacket);
00547     NyLPC_iUdpSocket_setOnPeriodicHandler(i_inst->_socket,onPeriodic);
00548 
00549     NyLPC_iUdpSocket_joinMulticast(i_inst->_socket,&SSDP_MCAST_IPADDR);
00550     i_inst->_flags=0;
00551     NyLPC_cStopwatch_initialize(&(i_inst->_periodic_sw));
00552     i_inst->number_of_device=0;
00553     expandDeviceTree(i_inst,i_ref_dev_record);
00554     i_inst->location_port=i_server_port;
00555     i_inst->location_path=i_ref_location_path;
00556 }
00557 void NyLPC_cSsdpSocket_finalize(NyLPC_TcSsdpSocket_t* i_inst)
00558 {
00559     NyLPC_cStopwatch_finalize(&(i_inst->_periodic_sw));
00560     NyLPC_iUdpSocket_finalize(i_inst->_socket);
00561 }
00562 
00563 void NyLPC_cSsdpSocket_start(NyLPC_TcSsdpSocket_t* i_inst)
00564 {
00565     //Notifyを3回送信
00566     NyLPC_TInt16 i;
00567     NyLPC_cSsdpSocket_notify(i_inst);
00568     for(i=0;i<2;i++){
00569         NyLPC_cThread_sleep(800);
00570         NyLPC_cSsdpSocket_notify(i_inst);
00571     }
00572 
00573     //ストップウォッチの開始要求
00574     NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_START_SERVICE);
00575     do{
00576         NyLPC_cThread_sleep(10);
00577         //開始フラグがクリアされるまでループ
00578     }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_START_SERVICE));
00579 }
00580 void NyLPC_cSsdpSocket_stop(NyLPC_TcSsdpSocket_t* i_inst)
00581 {
00582     //今は使えない。
00583     NyLPC_Abort();
00584     NyLPC_TUInt8_setBit(i_inst->_flags,FLAG_ORDER_STOP_SERVICE);
00585     do{
00586         NyLPC_cThread_sleep(10);
00587         //開始フラグがクリアされるまでループ
00588     }while(NyLPC_TUInt8_isBitOn(i_inst->_flags,FLAG_ORDER_STOP_SERVICE));
00589 }
00590 void NyLPC_cSsdpSocket_notify(NyLPC_TcSsdpSocket_t* i_inst)
00591 {
00592     void* tx;
00593     NyLPC_TInt16 tx_len;
00594     NyLPC_TUInt8 i,i2;
00595     //rootdevice
00596     tx=allocNotifyTx(
00597         i_inst,
00598         i_inst->ref_device_record[0]->udn,STR_UPNP_ROOT_DEVICE,
00599         &tx_len);
00600     if(tx==NULL){
00601         NyLPC_OnErrorGoto(ERROR1);
00602     }
00603     if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){
00604         NyLPC_OnErrorGoto(ERROR2);
00605     }
00606     //all device
00607     for(i=0;i<i_inst->number_of_device;i++){
00608         //uuid
00609         tx=allocNotifyTx(
00610             i_inst,
00611             i_inst->ref_device_record[i]->udn,NULL,
00612             &tx_len);
00613         if(tx==NULL){
00614             NyLPC_OnErrorGoto(ERROR1);
00615         }
00616         if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){
00617             NyLPC_OnErrorGoto(ERROR2);
00618         }
00619         //devicatype
00620         tx=allocNotifyTx(
00621             i_inst,
00622             i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->device_type,
00623             &tx_len);
00624         if(tx==NULL){
00625             NyLPC_OnErrorGoto(ERROR1);
00626         }
00627         if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){
00628             NyLPC_OnErrorGoto(ERROR2);
00629         }
00630         for(i2=0;i2<i_inst->ref_device_record[i]->number_of_service;i2++){
00631             tx=allocNotifyTx(
00632                 i_inst,
00633                 i_inst->ref_device_record[i]->udn,i_inst->ref_device_record[i]->services[i2].service_type,
00634                 &tx_len);
00635             if(tx==NULL){
00636                 NyLPC_OnErrorGoto(ERROR1);
00637             }
00638             if(!NyLPC_iUdpSocket_psend(i_inst->_socket,&SSDP_MCAST_IPADDR,1900,tx,tx_len)){
00639                 NyLPC_OnErrorGoto(ERROR2);
00640             }
00641         }
00642     }
00643     return;
00644 ERROR2:
00645     NyLPC_iUdpSocket_releaseSendBuf(i_inst->_socket,tx);
00646 ERROR1:
00647     return;
00648 }
00649