Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of libMiMic by
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
Generated on Tue Jul 12 2022 16:22:58 by
1.7.2
