1 /*********************************************************************************
\r
3 * --------------------------------------------------------------------------------
\r
5 * This file is part of MiMic
\r
6 * Copyright (C)2011 Ryo Iizuka
\r
8 * MiMic is free software: you can redistribute it and/or modify
\r
9 * it under the terms of the GNU Lesser General Public License as published
\r
10 * by the Free Software Foundation, either version 3 of the License, or
\r
11 * (at your option) any later version.
\r
13 * This program is distributed in the hope that it will be useful,
\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 * GNU General Public License for more details.
\r
18 * You should have received a copy of the GNU Lesser General Public License
\r
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
21 * For further information please contact.
\r
23 * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
\r
25 *********************************************************************************/
\r
26 #include "NyLPC_cModRemoteMcu.h"
\r
27 #include "NyLPC_stdlib.h"
\r
28 #include "../http/NyLPC_cHttpShortRequestHeaderParser.h"
\r
29 #include "../NyLPC_cHttpdConnection_protected.h"
\r
30 #include "../../../mimicvm/NyLPC_cMiMicDbCompiler.h"
\r
31 #include "../../../mimicvm/NyLPC_cMiMicTxtCompiler.h"
\r
32 #include "NyLPC_cHttpmodUtils_protected.h"
\r
33 #include "../../../mimicvm/NyLPC_cMiMicVM_protected.h"
\r
36 #define MVM_VERSION "MiMicVM/1.0;Json/1.0"
\r
37 #define SIZE_OF_IBUF 256
\r
38 struct TModMiMicRemoteMcuHeader
\r
40 struct NyLPC_THttpBasicHeader super;
\r
41 NyLPC_TUInt8 _content_id;
\r
43 NyLPC_TUInt8 _qery_name_id;
\r
44 NyLPC_TUInt16 _prefix_len;
\r
45 NyLPC_TUInt8 _astate;
\r
46 NyLPC_TcStr_t _tstr;
\r
47 NyLPC_TChar _tstr_buf[16];
\r
48 struct NyLPC_TUInt32ArrayPtr _binarray;
\r
50 NyLPC_TcMiMicDbCompiler_t _binparser;
\r
51 NyLPC_TcMiMicTxtCompiler_t _txtcmp;
\r
54 NyLPC_TUInt8 v;//バージョン
\r
55 NyLPC_TUInt8 o;//outputスタイル
\r
57 * il_bufはbcとdbの2パートのデータを格納します。
\r
58 * 先頭からbc_lenの長さのBCパートと、db_partからdb_lenの長さのデータです。
\r
61 /** MiMicVMインストラクションの蓄積用。前半にTXT,後半にDBを格納する。 */
\r
62 NyLPC_TUInt32 bc_buf[SIZE_OF_IBUF];
\r
63 /** MiMicVM入力ストリーム(MimicDB)の開始位置(bufの一部を指す) */
\r
64 const NyLPC_TUInt32* db_part;
\r
65 /** MiMicTXTのワード長(1ワード32bit)*/
\r
66 NyLPC_TUInt16 txt_len;
\r
67 /** MiMicDBのワード長(1ワード32bit)*/
\r
68 NyLPC_TUInt16 db_len;
\r
73 * 不明な名前の場合は、ここに名前をコピー
\r
75 NyLPC_TChar path[32];
\r
81 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh);
\r
84 static NyLPC_TBool messageHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
\r
89 return NyLPC_TBool_TRUE;
\r
92 #define ST_PARSE_PATH 1
\r
93 #define ST_PARSE_QUERY_NAME 2
\r
94 #define ST_PARSE_QUERY_VALUE 3 //Query読み出し中
\r
95 #define ST_PARSE_QUERY_VALUE_V 4
\r
96 #define ST_PARSE_QUERY_VALUE_O 5
\r
97 #define ST_PARSE_QUERY_VALUE_BC 6
\r
98 #define ST_PARSE_QUERY_VALUE_DB 7
\r
100 * コンテンツID定義(コンテンツ名に対応)
\r
102 #define CONTENT_ID_MVM 2
\r
103 #define CONTENT_ID_STATUS 3
\r
104 #define CONTENT_ID_UNKNOWN 0
\r
107 #define QNAME_ID_V 1
\r
108 #define QNAME_ID_O 2
\r
109 #define QNAME_ID_BC 3
\r
110 #define QNAME_ID_UNKNOWN 0
\r
113 * TRemoteMcuRequest.content.mvm.oの値
\r
115 #define QVAL_O_UNKNOWN 0 //default
\r
116 #define QVAL_O_XML 1
\r
117 #define QVAL_O_JSON 2
\r
119 #define QVAL_V_UNKNOWN 0
\r
123 const struct NyLPC_TTextIdTbl url_tbl[]=
\r
125 {"mvm.api",CONTENT_ID_MVM},
\r
126 {"status.api",CONTENT_ID_STATUS},
\r
127 {NULL,CONTENT_ID_UNKNOWN}
\r
130 const struct NyLPC_TTextIdTbl qname_id_table[]=
\r
133 {"bc",QNAME_ID_BC},
\r
135 {NULL,QNAME_ID_UNKNOWN}
\r
140 static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)
\r
143 struct TModMiMicRemoteMcuHeader* out=(struct TModMiMicRemoteMcuHeader*)o_out;
\r
145 if(out->_prefix_len<0){
\r
146 out->_prefix_len++;
\r
147 return NyLPC_TBool_TRUE;//読み飛ばし
\r
149 if(out->_astate==ST_PARSE_PATH){
\r
153 out->_content_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),url_tbl);
\r
154 switch(out->_content_id)
\r
156 case CONTENT_ID_MVM:
\r
157 out->content.mvm.vm_instruction.txt_len=0;
\r
158 out->content.mvm.vm_instruction.db_len=0;
\r
159 out->content.mvm.vm_instruction.db_part=NULL;
\r
160 NyLPC_TUInt32ArrayPtr_setBuf(&out->_binarray,out->content.mvm.vm_instruction.bc_buf,SIZE_OF_IBUF);
\r
161 out->content.mvm.o=QVAL_O_UNKNOWN;
\r
162 out->content.mvm.v=QVAL_V_UNKNOWN;
\r
168 NyLPC_cStr_clear(&(out->_tstr));
\r
169 out->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ
\r
170 return NyLPC_TBool_TRUE;
\r
174 return NyLPC_TBool_TRUE;
\r
176 switch(out->_content_id)
\r
178 case CONTENT_ID_MVM:
\r
179 switch(out->_astate){
\r
180 case ST_PARSE_QUERY_NAME:
\r
181 if(i_c!='\0' && i_c!='&' && i_c!='='){
\r
182 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
183 NyLPC_OnErrorGoto(ERROR);
\r
185 return NyLPC_TBool_TRUE;
\r
188 out->_qery_name_id=NyLPC_TTextIdTbl_getMatchId(NyLPC_cStr_str(&(out->_tstr)),qname_id_table);
\r
189 NyLPC_cStr_clear(&(out->_tstr));
\r
191 switch(out->_qery_name_id){
\r
193 out->_astate=ST_PARSE_QUERY_VALUE_O;//MIMICBCのDBパラメータパーサを借用。
\r
196 out->_astate=ST_PARSE_QUERY_VALUE_V;
\r
199 out->_astate=ST_PARSE_QUERY_VALUE_BC;
\r
202 out->_astate=ST_PARSE_QUERY_VALUE;
\r
205 return NyLPC_TBool_TRUE;
\r
206 case ST_PARSE_QUERY_VALUE:
\r
208 if(i_c!='\0' || i_c!='&'){
\r
209 return NyLPC_TBool_TRUE;
\r
212 out->_astate=ST_PARSE_QUERY_NAME;
\r
213 return NyLPC_TBool_TRUE;
\r
214 case ST_PARSE_QUERY_VALUE_O:
\r
215 if(i_c!='\0' || i_c!='&'){
\r
216 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
217 NyLPC_OnErrorGoto(ERROR);
\r
219 return NyLPC_TBool_TRUE;
\r
221 if(NyLPC_cStr_isEqual(&(out->_tstr),"j")){
\r
222 out->content.mvm.o=QVAL_O_JSON;
\r
223 }else if(NyLPC_cStr_isEqual(&(out->_tstr),"x")){
\r
224 out->content.mvm.o=QVAL_O_XML;
\r
226 out->_astate=ST_PARSE_QUERY_NAME;
\r
227 return NyLPC_TBool_TRUE;
\r
228 case ST_PARSE_QUERY_VALUE_V:
\r
229 if(i_c!='\0' || i_c!='&'){
\r
230 if(!NyLPC_cStr_put(&(out->_tstr),i_c)){
\r
231 NyLPC_OnErrorGoto(ERROR);
\r
233 return NyLPC_TBool_TRUE;
\r
235 if(NyLPC_cStr_isEqual(&(out->_tstr),"1")){
\r
236 out->content.mvm.v=QVAL_V_1;
\r
238 out->_astate=ST_PARSE_QUERY_NAME;
\r
239 return NyLPC_TBool_TRUE;
\r
240 case ST_PARSE_QUERY_VALUE_BC:
\r
241 if(i_c!='\0' || i_c!='&'){
\r
243 switch(NyLPC_cMiMicTxtCompiler_compileFragment2(&(out->_txtcmp),i_c,&(out->_binarray),&ol))
\r
245 case NyLPC_TcMiMicTxtCompiler_RET_OK:
\r
248 case NyLPC_TcMiMicTxtCompiler_RET_OK_END:
\r
250 out->content.mvm.vm_instruction.txt_len=SIZE_OF_IBUF-out->_binarray.len+ol;
\r
251 out->content.mvm.vm_instruction.db_part=out->content.mvm.vm_instruction.bc_buf+out->content.mvm.vm_instruction.txt_len;
\r
252 out->_astate=ST_PARSE_QUERY_VALUE_DB;
\r
254 case NyLPC_TcMiMicTxtCompiler_RET_CONTINUE:
\r
257 case NyLPC_TcMiMicTxtCompiler_RET_NG:
\r
260 NyLPC_OnErrorGoto(ERROR);
\r
262 return NyLPC_TBool_TRUE;
\r
264 //フラグメント終端が検出できない終了はエラー
\r
265 NyLPC_OnErrorGoto(ERROR);
\r
266 case ST_PARSE_QUERY_VALUE_DB:
\r
267 if(i_c!='\0' || i_c!='&'){
\r
268 switch(NyLPC_cMiMicDbCompiler_compileFragment2(&(out->_binparser),i_c,out->_binarray.ptr))
\r
270 case NyLPC_TcMiMicDbCompiler_RET_CONTINUE:
\r
272 case NyLPC_TcMiMicDbCompiler_RET_OK:
\r
274 if(!NyLPC_TUInt32ArrayPtr_seek(&(out->_binarray),1)){
\r
276 NyLPC_OnErrorGoto(ERROR);
\r
279 case NyLPC_TcMiMicDbCompiler_RET_ERROR:
\r
282 NyLPC_OnErrorGoto(ERROR);
\r
284 return NyLPC_TBool_TRUE;
\r
287 if(NyLPC_cMiMicDbCompiler_hasFragment(&(out->_binparser))){
\r
289 NyLPC_OnErrorGoto(ERROR);
\r
292 out->_astate=ST_PARSE_QUERY_NAME;
\r
293 return NyLPC_TBool_TRUE;
\r
297 NyLPC_OnErrorGoto(ERROR);
\r
299 NyLPC_OnErrorGoto(ERROR);
\r
301 return NyLPC_TBool_TRUE;
\r
303 return NyLPC_TBool_FALSE;
\r
308 static const struct NyLPC_TcHttpBasicHeaderParser_Handler handler=
\r
318 void NyLPC_cModMiMicSetting_initialize(NyLPC_TcModRemoteMcu_t* i_inst,const NyLPC_TChar* i_ref_root_path)
\r
320 NyLPC_cModRomFiles_initialize(&i_inst->super,i_ref_root_path,NULL,0);
\r
322 void NyLPC_cModMiMicSetting_finalize(NyLPC_TcModRemoteMcu_t* i_inst)
\r
324 NyLPC_cModRomFiles_finalize(&i_inst->super);
\r
327 * モジュールがコネクションをハンドリングできるかを返します。
\r
329 NyLPC_TBool NyLPC_cModMiMicSetting_canHandle(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection)
\r
331 return NyLPC_cModRomFiles_canHandle(&i_inst->super,i_connection);
\r
337 NyLPC_TBool NyLPC_cModMiMicSetting_execute(NyLPC_TcModRemoteMcu_t* i_inst,NyLPC_TcHttpdConnection_t* i_connection,const NyLPC_TChar* i_root_path)
\r
339 struct TModMiMicRemoteMcuHeader header;
\r
340 NyLPC_TcHttpBasicHeaderParser_t parser;
\r
342 if(!NyLPC_cHttpdConnection_getReqStatus(i_connection)==NyLPC_cHttpdConnection_ReqStatus_REQPARSE)
\r
344 NyLPC_OnErrorGoto(Error1);
\r
348 NyLPC_cHttpdConnection_lock(i_connection);
\r
352 header._prefix_len=-(NyLPC_TInt16)strlen(i_inst->super._ref_root_path);
\r
353 header._astate=ST_PARSE_PATH;
\r
354 NyLPC_cStr_initialize(&header._tstr,header._tstr_buf,16);
\r
355 NyLPC_cMiMicDbCompiler_initialize(&header._binparser);
\r
356 NyLPC_cMiMicTxtCompiler_initialize(&header._txtcmp);
\r
358 NyLPC_cHttpBasicHeaderParser_initialize(&parser,&handler);
\r
361 NyLPC_cHttpBasicHeaderParser_parseInit(&parser,&(header.super));
\r
362 NyLPC_cHttpdConnection_pushPrefetchInfo(i_connection,&parser,&header.super);
\r
364 if(!NyLPC_cHttpBasicHeaderParser_parseStream(&parser,NyLPC_cHttpdConnection_refStream(i_connection),&(header.super))){
\r
365 NyLPC_OnErrorGoto(Error2);
\r
367 if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&parser,&(header.super))){
\r
368 NyLPC_OnErrorGoto(Error2);
\r
370 //Connection Modeの設定 1.1 && !closeの場合はCONTINUE
\r
371 if(header.super.connection!=NyLPC_THttpMessgeHeader_Connection_CLOSE && header.super.startline.req.version==NyLPC_THttpVersion_11)
\r
373 NyLPC_cHttpdConnection_setConnectionMode(i_connection,NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE);
\r
376 switch(header._content_id)
\r
378 case CONTENT_ID_MVM:
\r
379 mvm(i_connection,&header);
\r
382 NyLPC_OnErrorGoto(Error2);
\r
384 NyLPC_cStr_finalize(&header._tstr);
\r
385 NyLPC_cMiMicDbCompiler_finalize(&header._binparser);
\r
386 NyLPC_cMiMicTxtCompiler_finalize(&header._txtcmp);
\r
387 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
389 NyLPC_cHttpdConnection_unlock(i_connection);
\r
390 return NyLPC_TBool_TRUE;
\r
392 NyLPC_cHttpdConnection_sendResponseHeader2(i_connection,500,"text/html",0,NULL);
\r
393 NyLPC_cStr_finalize(&header._tstr);
\r
394 NyLPC_cMiMicDbCompiler_finalize(&header._binparser);
\r
395 NyLPC_cMiMicTxtCompiler_finalize(&header._txtcmp);
\r
396 NyLPC_cHttpBasicHeaderParser_finalize(&parser);
\r
398 NyLPC_cHttpdConnection_unlock(i_connection);
\r
400 return NyLPC_TBool_FALSE;
\r
407 struct TVmEventHandler
\r
409 struct NyLPC_TcMiMicVM_TEvent super;
\r
410 const struct TModMiMicRemoteMcuHeader* req;
\r
411 NyLPC_TcHttpdConnection_t* connection;
\r
412 NyLPC_TUInt16 db_pos;
\r
413 /** ストリームへ出力したデータの数*/
\r
414 NyLPC_TUInt16 st_len;
\r
420 static NyLPC_TBool mvmputs_json(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_val)
\r
422 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
425 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,",%u",i_val);
\r
428 return NyLPC_cHttpdConnection_sendResponseBodyF(eh->connection,"%u",i_val);
\r
435 static NyLPC_TBool mvmgets(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32* o_val)
\r
437 struct TVmEventHandler* eh=(struct TVmEventHandler*)i_eh;
\r
439 if(eh->req->content.mvm.vm_instruction.db_len<=eh->db_pos){
\r
441 return NyLPC_TBool_FALSE;
\r
443 *o_val=eh->req->content.mvm.vm_instruction.db_part[eh->db_pos];
\r
445 return NyLPC_TBool_TRUE;
\r
450 static NyLPC_TUInt32 nativeCall(struct NyLPC_TcMiMicVM_TEvent* i_evh,NyLPC_TUInt32 i_id,NyLPC_TcMiMicVM_t* i_vm)
\r
453 // NyLPC_TNativeFunction f=getNativeFunctionById(i_id);
\r
455 // return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_UNKNOWN_CALL;
\r
457 // return f(i_vm)?NyLPC_cMiMicVM_RESULT_OK:NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
458 return NyLPC_cMiMicVM_RESULT_RUNTIME_NG_CALL;
\r
462 static void mvmsleep(struct NyLPC_TcMiMicVM_TEvent* i_eh,NyLPC_TUInt32 i_sleep_in_msec)
\r
465 NyLPC_cThread_sleep(i_sleep_in_msec);
\r
470 * MimicVMの起動と,ResponseJSONの起動
\r
474 static void mvm(NyLPC_TcHttpdConnection_t* i_connection,const struct TModMiMicRemoteMcuHeader* i_rqh)
\r
476 struct TVmEventHandler he;
\r
477 NyLPC_TcMiMicVM_t vm;
\r
478 NyLPC_TUInt32 vmret;
\r
479 if(i_rqh->content.mvm.v!=QVAL_V_1 || i_rqh->content.mvm.o!=QVAL_O_JSON)
\r
481 NyLPC_cHttpdConnection_sendResponseHeader2(i_connection,500,"text/html",0,NULL);
\r
486 //ここでリクエストパーサのエラー原因を調べて、詳細JSONをかくのもあり
\r
488 if(!NyLPC_cHttpdModUtils_sendJsonHeader(i_connection)){
\r
489 NyLPC_OnErrorGoto(Error1);
\r
492 he.super.get_stream=mvmgets;
\r
493 he.super.put_stream=mvmputs_json;
\r
494 he.super.native_call=nativeCall;
\r
495 he.super.sleep=mvmsleep;
\r
498 he.connection=i_connection;
\r
502 NyLPC_cMiMicVM_initialize(&vm,(struct NyLPC_TcMiMicVM_TEvent*)&(he.super));
\r
505 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"{\"version\":\""MVM_VERSION"\",\"stream\":[")){
\r
506 NyLPC_OnErrorGoto(Error3);
\r
509 vmret=NyLPC_cMiMicVM_run(&(vm),i_rqh->content.mvm.vm_instruction.bc_buf,i_rqh->content.mvm.vm_instruction.txt_len);
\r
510 if(!NyLPC_cHttpdConnection_sendResponseBodyF(i_connection,"],\"result\":%u}",vmret)){
\r
511 NyLPC_OnErrorGoto(Error3);
\r
513 NyLPC_cMiMicVM_finalize(&vm);
\r
517 NyLPC_cMiMicVM_finalize(&vm);
\r
520 NyLPC_cMiMicVM_finalize(&vm);
\r
521 NyLPC_cHttpBodyWriter_finalize(&hw);
\r