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

NyLPC_cModUPnPDevice.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_cModUPnPDevice.h"
00027 #include "../NyLPC_cHttpdConnection_protected.h"
00028 #include "NyLPC_net.h"
00029 #include "NyLPC_stdlib.h"
00030 #include "NyLPC_http.h"
00031 #include <string.h>
00032 #include <ctype.h>
00033 
00034 
00035 
00036 #define SIZE_OF_STRBUF 16
00037 struct TUPnPDeviceHeader
00038 {
00039     struct NyLPC_THttpBasicHeader super;
00040     //解析用
00041     NyLPC_TUInt8 _content_id;
00042     NyLPC_TUInt8 _astate;
00043     NyLPC_TInt16 _prefix_len;
00044     NyLPC_TcStr_t _tstr;
00045     NyLPC_TChar _tstr_buf[SIZE_OF_STRBUF];
00046     /** 文字列のパーサ*/
00047     union{
00048         NyLPC_TInt16 service_idx;
00049     }content;
00050 };
00051 
00052 #define ST_PARSE_PATH 1
00053 #define ST_PARSE_QUERY_NAME 2
00054 
00055 /**
00056  * コンテンツID定義(コンテンツ名に対応)
00057  */
00058 #define CONTENT_ID_UNKNOWN      1
00059 #define CONTENT_ID_DEVICE_XML   2
00060 #define CONTENT_ID_CONTROL      3
00061 #define CONTENT_ID_EVENT        4
00062 
00063 #define QNAME_ID_UNKNOWN 1
00064 #define QNAME_IDX 2
00065 
00066 #define CONTENT_STR_DEVICE_XML "d.xml"
00067 #define CONTENT_STR_CONTROL_PATH "control"
00068 #define CONTENT_STR_EVENT_PATH  "event"
00069 #define CONTENT_STR_XML_MIME_TYPE  "text/xml"
00070 
00071 
00072 
00073 
00074 
00075 static void writeDeviceNode(const struct NyLPC_TUPnPDevDescDevice* i_dev,NyLPC_TcHttpdConnection_t* i_connection,NyLPC_TUInt16* sidx)
00076 {
00077     //Required
00078     NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00079         "<device>"
00080         "<deviceType>%s</deviceType>"
00081         "<friendlyName>%s</friendlyName>"
00082         "<manufacturer>%s</manufacturer>",
00083         i_dev->device_type,
00084         i_dev->frendly_name,
00085         i_dev->manufacturer);
00086     NyLPC_TInt16 i;
00087     //Optional
00088     if(i_dev->manufacturer_url!=NULL){
00089         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00090             "<manufacturerURL>%s</manufacturerURL>",
00091             i_dev->manufacturer_url);
00092     }
00093     //Recommended
00094     if(i_dev->model_descriprion!=NULL){
00095         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00096             "<modelDescription>%s</modelDescription>",
00097             i_dev->model_descriprion);
00098     }else{
00099         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00100             "<modelDescription/>"); //Recommended
00101     }
00102     //Required
00103     NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00104         "<modelName>%s</modelName>",
00105         i_dev->model_name);
00106     //Recommended
00107     if(i_dev->model_number!=NULL){
00108         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00109             "<modelNumber>%s</modelNumber>",
00110             i_dev->model_number);
00111     }else{
00112         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00113             "<modelNumber/>");
00114     }
00115     //Optional
00116     if(i_dev->model_url!=NULL){
00117         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00118             "<modelURL>%s</modelURL>",
00119             i_dev->model_url);
00120     }
00121     //Recommended
00122     if(i_dev->serial_number!=NULL){
00123         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00124             "<serialNumber>%s</serialNumber>",
00125             i_dev->serial_number);
00126     }else{
00127         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00128             "<serialNumber/>");
00129     }
00130     //Required
00131     NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00132         "<UDN>%s</UDN>",
00133         i_dev->udn);
00134     //Oprional
00135     if(i_dev->upc!=NULL){
00136         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00137             "<UPC>%s</UPC>",
00138             i_dev->upc);
00139     }
00140     if(i_dev->number_of_icon>0){
00141         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00142             "<iconList>");
00143         for(i=0;i<i_dev->number_of_icon;i++){
00144             NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00145                 "<icon>"
00146                 "<mimetype>%s</mimetype>"
00147                 "<width>%d</width>"
00148                 "<height>%d</height>"
00149                 "<depth>%d</depth>"
00150                 "<url>%s</url>"
00151                 "</icon>",
00152                 i_dev->icons[i].mimetype,
00153                 i_dev->icons[i].width,
00154                 i_dev->icons[i].height,
00155                 i_dev->icons[i].depth,
00156                 i_dev->icons[i].url);
00157         }
00158         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00159             "</iconList>");
00160     }else{
00161         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00162             "<iconList/>");
00163     }
00164     //Optional
00165     if(i_dev->number_of_service>0){
00166         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00167             "<serviceList>");
00168         for(i=0;i<i_dev->number_of_service;i++){
00169             NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00170                 "<service>"
00171                 "<serviceType>%s</serviceType>"
00172                 "<serviceId>%s</serviceId>"
00173                 "<SCPDURL>%s</SCPDURL>"
00174                 "<controlURL>./control/%d</controlURL>"
00175                 "<eventSubURL>./event/%d</eventSubURL>"
00176                 "</service>",
00177                 i_dev->services[i].scpd_url,
00178                 i_dev->services[i].service_type,
00179                 i_dev->services[i].service_id,
00180                 (*sidx)+i,
00181                 (*sidx)+i);
00182         }
00183         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00184             "</serviceList>");
00185     }
00186     if(i_dev->number_of_devices>0){
00187         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00188             "<deviceList>");
00189         for(i=0;i<i_dev->number_of_devices;i++){
00190             (*sidx)=(*sidx)+0x10;
00191             writeDeviceNode(i_dev->devices[i],i_connection,sidx);
00192         }
00193         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00194             "</deviceList>");
00195     }
00196     if(i_dev->presentation_url!=NULL){
00197         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00198             "<presentationURL>%s</presentationURL></device>",
00199             i_dev->presentation_url);
00200     }
00201     else{
00202         NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00203             "</device>");
00204     }
00205 }
00206 NyLPC_TBool writeDeviceDescription(const struct NyLPC_TUPnPDevDescDevice* i_dev,NyLPC_TcHttpdConnection_t* i_connection)
00207 {
00208     NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,
00209         "<?xml version=\"1.0\"?>"
00210         "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
00211         "<specVersion><major>1</major><minor>0</minor></specVersion>");
00212     writeDeviceNode(i_dev,i_connection,0);
00213     return NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"</root>");
00214 }
00215 
00216 
00217 
00218 
00219 
00220 /**
00221  * control,eventのServiceIndex部分をパースする。
00222  * [:str:]/[:HEX8:][:HEX8:]
00223  */
00224 static NyLPC_TInt16 parseSidx(const NyLPC_TChar* i_str)
00225 {
00226     //先頭は/であること
00227     if(*i_str!='/'){
00228         return -1;
00229     }
00230     //2桁の16進数であること
00231     if(!isxdigit((int)(*(i_str+1))) || !isxdigit((int)(*(i_str+2)))){
00232         return -1;
00233     }
00234     //サービスID化
00235     return NyLPC_ctox(*(i_str+1))<<8 | NyLPC_ctox(*(i_str+2));
00236 }
00237 
00238 
00239 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
00240 {
00241 
00242     struct TUPnPDeviceHeader* out=(struct TUPnPDeviceHeader*)o_out;
00243     //読み飛ばし
00244     if(out->_prefix_len<0){
00245         out->_prefix_len++;
00246         return NyLPC_TBool_TRUE;//読み飛ばし
00247     }
00248     if(out->_astate==ST_PARSE_PATH){
00249         if(i_c!='\0' && i_c!='?'){
00250             if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
00251                 NyLPC_OnErrorGoto(ERROR);
00252             }
00253             return NyLPC_TBool_TRUE;
00254         }
00255         if(strcmp(NyLPC_cStr_str(&(out->_tstr)),CONTENT_STR_DEVICE_XML)==0){
00256             out->_content_id=CONTENT_ID_DEVICE_XML;
00257         }else if(strncmp(CONTENT_STR_CONTROL_PATH,NyLPC_cStr_str(&(out->_tstr)),7)==0){
00258             out->_content_id=CONTENT_ID_CONTROL;
00259             parseSidx(NyLPC_cStr_str(&(out->_tstr))+7);
00260         }else if(strncmp(CONTENT_STR_EVENT_PATH,NyLPC_cStr_str(&(out->_tstr)),5)==0){
00261             out->_content_id=CONTENT_ID_EVENT;
00262             parseSidx(NyLPC_cStr_str(&(out->_tstr))+5);
00263         }else{
00264             NyLPC_OnErrorGoto(ERROR);
00265         }
00266         NyLPC_cStr_clear(&(out->_tstr));
00267         out->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ
00268         return NyLPC_TBool_TRUE;
00269     }
00270     return NyLPC_TBool_TRUE;
00271 ERROR:
00272     return NyLPC_TBool_FALSE;
00273 }
00274 /**
00275  * デフォルトハンドラ
00276  */
00277 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=
00278 {
00279     NULL,
00280     urlHandler
00281 };
00282 
00283 
00284 
00285 
00286 
00287 
00288 /**
00289  * コンストラクタ。
00290  */
00291 void NyLPC_cModUPnPDevice_initialize(NyLPC_TcModUPnPDevice_t* i_inst,const NyLPC_TcUPnP_t* i_ref_upnp)
00292 {
00293     NyLPC_cModRomFiles_initialize(&i_inst->super,i_ref_upnp->_ref_root_path,NULL,0);
00294     i_inst->_ref_upnp=i_ref_upnp;
00295 }
00296 void NyLPC_cModUPnPDevice_finalize(NyLPC_TcModUPnPDevice_t* i_inst)
00297 {
00298     NyLPC_cModRomFiles_finalize(&i_inst->super);
00299 }
00300 /**
00301  * モジュールがコネクションをハンドリングできるかを返します。
00302  */
00303 NyLPC_TBool NyLPC_cModUPnPDevice_canHandle(NyLPC_TcModUPnPDevice_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
00304 {
00305     return NyLPC_cModRomFiles_canHandle(&i_inst->super,i_connection);
00306 }
00307 
00308 /**
00309  * モジュールを実行します。
00310  */
00311 NyLPC_TBool NyLPC_cModUPnPDevice_execute(NyLPC_TcModUPnPDevice_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
00312 {
00313     NyLPC_TUInt8 method_type;
00314     struct TUPnPDeviceHeader header;
00315     NyLPC_TcHttpBasicHeaderParser_t parser;
00316 
00317     //リクエストParse済へ遷移(この関数の後はModが責任を持ってリクエストを返却)
00318     NyLPC_cHttpdConnection_setReqStatusParsed(i_connection);
00319     NyLPC_cStr_initialize(&header._tstr,header._tstr_buf,SIZE_OF_STRBUF);
00320 
00321     //URL解析の準備
00322     header._prefix_len=-((NyLPC_TInt16)strlen(i_inst->super._ref_root_path)+2);
00323     header._astate=ST_PARSE_PATH;
00324 
00325     NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);
00326     NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(header.super));
00327     //プリフェッチしたデータを流す
00328     NyLPC_cHttpdConnection_pushPrefetchInfo(i_connection,&parser,&header.super);
00329     //後続をストリームから取り込む
00330     if(!NyLPC_cHttpBasicHeaderParser_parseStream(&parser,NyLPC_cHttpdConnection_refStream(i_connection),&(header.super))){
00331         NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500);
00332         NyLPC_OnErrorGoto(Error2);
00333     }
00334     if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(header.super))){
00335         NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500);
00336         NyLPC_OnErrorGoto(Error2);
00337     }
00338     //GETかHEADに制限(Descriptionの場合だけ)
00339     method_type=NyLPC_cHttpdConnection_getMethod(i_connection);
00340     if(method_type!=NyLPC_THttpMethodType_GET && method_type!=NyLPC_THttpMethodType_HEAD)
00341     {
00342         NyLPC_cHttpdUtils_sendErrorResponse(i_connection,405);
00343         NyLPC_OnErrorGoto(Error2);
00344     }
00345     //Request::ConnectionがClose設定,又はHTTP1.1では無い場合,CLOSE
00346     if(header.super.connection==NyLPC_THttpMessgeHeader_Connection_CLOSE || header.super.startline.req.version!=NyLPC_THttpVersion_11)
00347     {
00348         NyLPC_cHttpdConnection_setConnectionMode(i_connection,NyLPC_TcHttpdConnection_CONNECTION_MODE_CLOSE);
00349     }
00350     //CGIの実行
00351     switch(header._content_id)
00352     {
00353     case CONTENT_ID_DEVICE_XML:
00354         NyLPC_cHttpdConnection_sendResponseHeader(i_connection,200,CONTENT_STR_XML_MIME_TYPE,NULL);
00355         writeDeviceDescription(i_inst->_ref_upnp->ref_root_device,i_connection);
00356         //DeviceXML
00357         break;
00358     case CONTENT_ID_CONTROL:
00359         //SoapHandler 未実装
00360     case CONTENT_ID_EVENT:
00361         //EventHandler 未実装
00362     default:
00363         NyLPC_cHttpdUtils_sendErrorResponse(i_connection,500);
00364         NyLPC_OnErrorGoto(Error2);
00365     }
00366     NyLPC_cHttpBasicHeaderParser_finalize(&parser);
00367     NyLPC_cStr_finalize(&header._tstr);
00368     return NyLPC_TBool_TRUE;
00369 Error2:
00370     NyLPC_cHttpBasicHeaderParser_finalize(&parser);
00371     NyLPC_cStr_finalize(&header._tstr);
00372     return NyLPC_TBool_FALSE;
00373 }
00374